HIDL C++

Android 8 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 các 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ạng giao diện HAL, được xác định là tiêu đề C trong hardware/libhardware. HIDL thay thế các tham số này Giao diện HAL có giao diện ổn định, được lập phiên bản, có thể là giao diện HIDL phía máy chủ trong C++ (mô tả dưới đây) 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 cả thông tin chi tiết về các tệp được tạo tự động từ .hal của HIDL các tệp của trình biên dịch hidl-gen, cách đóng gói các tệp này và cách tích hợp các tệp này với mã C++ có sử dụng chúng.

Triển khai ứng dụng và máy chủ

Giao diện HIDL có cách triển khai ứng dụng và máy chủ:

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

Khi chuyển đổi từ HAL libhardware sang HAL HIDL, HAL Quá trình triển khai trở thành máy chủ và quy trình gọi vào HAL trở thành khách hàng. Các cách triển khai mặc định có thể phân phát cả truyền qua và liên kết HAL và có thể thay đổi theo thời gian:

Hình 1. Tiến trình phát triển HAL (Lớp trừu tượng phần cứng) cũ.

Tạo ứng dụng HAL

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

  • Nhãn hiệu: LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0
  • Sắp phát hành: shared_libs: [ …, android.hardware.nfc@1.0 ]

Tiếp theo, hãy thê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 quy trình triển khai HAL, bạn phải có các tệp .hal đại diện cho HAL và đã tạo tệp makefile 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 đối với HAL và là tài liệu tham khảo tốt). Khi chuyển qua HAL từ libhardware, bạn có thể dễ dàng thực hiện nhiều việc này bằng c2hal.

Cách tạo các tệp cần thiết để triển khai HAL:

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ế độ thông qua, bạn phải hàm HIDL_FETCH_IModuleName cư trú 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 tín hiệu truyền qua trong quá trình triển khai. Các yêu cầu về chế độ truyền qua được tự động đáp ứng bởi các lệnh bên trên. Các lệnh này cũng tạo ra android.hardware.nfc@1.0-impl nhưng có thể sử dụng bất kỳ tiện ích nào. Ví dụ: android.hardware.nfc@1.0-impl-foo sử dụng -foo để sự khác biệt.

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

Tiếp theo, điền chức năng vào các stub và thiết lập một trình nền. Ví dụ: mã trình nền (hỗ trợ truyền qua):

#include <hidl/LegacySupport.h>

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

defaultPassthroughServiceImplementation cuộc gọi dlopen() cho thư viện -impl được cung cấp và cung cấp dưới dạng dịch vụ liên kết. Ví dụ về mã trình nền (dành cho dịch vụ liên kết thuần tuý):

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 never exceeds
    // 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 sống trong $PACKAGE + "-service-suffix" (cho ví dụ: android.hardware.nfc@1.0-service), nhưng có thể ở bất cứ đâu. Chính sách dành cho một phiên bản cụ thể lớp HAL là thuộc tính hal_<module> (ví dụ: hal_nfc). Thuộc tính này phải được áp dụng cho trình nền chạy HAL cụ thể (nếu cùng một quy trình cung cấp nhiều HAL thì nhiều thuộc tính có thể áp dụng cho cảnh báo đó).