HIDL C++

Android O tái cấu trúc hệ điều hành Android để xác định các giao diện rõ ràng giữa nền tảng Android độc lập với thiết bị và mã dành riêng cho thiết bị và nhà cung cấp. Android đã định nghĩa nhiều giao diện như vậy dưới dạng giao diện HAL, được định nghĩa là tiêu đề C trong hardware/libhardware . HIDL thay thế các giao diện HAL này bằng các giao diện ổn định, được phiên bản, có thể là giao diện HIDL phía máy khách và máy chủ trong C++ (được mô tả bên dưới) hoặc Java .

Các trang trong phần này mô tả cách triển khai C++ của giao diện HIDL, bao gồm chi tiết về các tệp được tạo tự động từ các tệp HIDL .hal bởi trình biên dịch hidl-gen , cách các tệp này được đóng gói và cách tích hợp các tệp này với mã C++ sử dụng chúng.

Triển khai máy khách và máy chủ

Giao diện HIDL có triển khai máy khách và máy chủ:

  • Máy khách của giao diện HIDL là mã sử dụng giao diện bằng cách gọi các phương thức trên đó.
  • Máy chủ là một triển khai giao diện HIDL nhận cuộc gọi từ máy khách và trả về kết quả (nếu cần).

Khi chuyển từ HAL libhardware sang HAL HIDL, việc triển khai HAL sẽ trở thành máy chủ và quá trình gọi vào HAL sẽ trở thành máy khách. Việc triển khai mặc định có thể phục vụ cả HAL truyền qua và HAL được liên kết và có thể thay đổi theo thời gian:

Hình 1. Quá trình phát triển của HAL cũ.

Tạo ứng dụng khách HAL

Bắt đầu bằng cách đưa các thư viện HAL vào tệp thực hiện:

  • Tạo: LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0
  • Bài viết: shared_libs: [ …, android.hardware.nfc@1.0 ]

Tiếp theo, bao gồm các tệp tiêu đề HAL:

#include <android/hardware/nfc/1.0/IFoo.h>
…
// in code:
sp<IFoo> client = IFoo::getService();
client->doThing();

Tạo máy chủ HAL

Để tạo triển khai HAL, bạn phải có các tệp .hal đại diện cho HAL của bạn và đã tạo các tệp tạo tệp cho HAL của bạn bằng cách sử dụng -Lmakefile hoặc -Landroidbp trên hidl-gen ( ./hardware/interfaces/update-makefiles.sh thực hiện việc này cho các tệp HAL nội bộ và là một tài liệu tham khảo tốt). Khi chuyển qua HAL từ libhardware , bạn có thể thực hiện nhiều công việc này một cách dễ dàng bằng cách sử dụng c2hal.

Để tạo các tệp cần thiết để triển khai HAL của bạn:

PACKAGE=android.hardware.nfc@1.0
LOC=hardware/interfaces/nfc/1.0/default/
m -j hidl-gen
hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces \
    -randroid.hidl:system/libhidl/transport $PACKAGE
hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces \
    -randroid.hidl:system/libhidl/transport $PACKAGE

Để HAL hoạt động ở chế độ chuyển tiếp, bạn phải có hàm HIDL_FETCH_IModuleName nằm trong /(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl( OPTIONAL_IDENTIFIER ).so trong đó OPTIONAL_IDENTIFIER là một chuỗi xác định việc triển khai chuyển tiếp. Các yêu cầu về chế độ chuyển tiếp được đáp ứng tự động bằng các lệnh trên, lệnh này cũng tạo mục tiêu android.hardware.nfc@1.0-impl nhưng có thể sử dụng bất kỳ tiện ích mở rộng nào. Ví dụ: android.hardware.nfc@1.0-impl-foo sử dụng -foo để phân biệt chính nó.

Nếu HAL là phiên bản phụ hoặc phần mở rộng của HAL khác thì nên sử dụng HAL cơ sở để đặt tên cho mã nhị phân này. Ví dụ: việc triển khai android.hardware.graphics.mapper@2.1 vẫn phải ở dạng nhị phân có tên android.hardware.graphics.mapper@2.0-impl( OPTIONAL_IDENTIFIER ) . Thông thường, OPTIONAL_IDENTIFIER ở đây sẽ bao gồm phiên bản HAL thực tế. Bằng cách đặt tên nhị phân như thế này, máy khách 2.0 có thể truy xuất trực tiếp và máy khách 2.1 có thể nâng cấp việc triển khai.

Tiếp theo, điền vào phần sơ khai chức năng và thiết lập một daemon. Mã daemon ví dụ (hỗ trợ truyền qua):

#include <hidl/LegacySupport.h>

int main(int /* argc */, char* /* argv */ []) {
    return defaultPassthroughServiceImplementation<INfc>("nfc");
}

defaultPassthroughServiceImplementation sẽ dlopen() thư viện -impl được cung cấp và cung cấp nó dưới dạng dịch vụ liên kết. Mã daemon ví dụ (đối với dịch vụ liên kết thuần túy):

int main(int /* argc */, char* /* argv */ []) {
    // This function must be called before you join to ensure the proper
    // number of threads are created. The threadpool will never exceed
    // size one because of this call.
    ::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/);

    sp<INfc> nfc = new Nfc();
    const status_t status = nfc->registerAsService();
    if (status != ::android::OK) {
        return 1; // or handle error
    }

    // Adds this thread to the threadpool, resulting in one total
    // thread in the threadpool. We could also do other things, but
    // would have to specify 'false' to willJoin in configureRpcThreadpool.
    ::android::hardware::joinRpcThreadpool();
    return 1; // joinRpcThreadpool should never return
}

Daemon này thường tồn tại trong $PACKAGE + "-service-suffix" (ví dụ: android.hardware.nfc@1.0-service ), nhưng nó có thể ở bất cứ đâu. Chính sách riêng biệt cho một lớp HAL cụ thể là thuộc tính hal_<module> (ví dụ: hal_nfc) . Thuộc tính này phải được áp dụng cho daemon chạy một HAL cụ thể (nếu cùng một quy trình phục vụ nhiều HAL thì nhiều thuộc tính có thể được áp dụng cho nó).