HIDL C++

Android O 對 Android 操作系統進行了重新架構,以在獨立於設備的 Android 平台與設備和供應商特定代碼之間定義清晰的接口。 Android 已經以 HAL 接口的形式定義了許多這樣的接口,在hardware/libhardware中定義為 C 頭文件。 HIDL 將這些 HAL 接口替換為穩定的版本化接口,這些接口可以是 C++(如下所述)或Java中的客戶端和服務器端 HIDL 接口。

本節中的頁面介紹了 HIDL 接口的 C++ 實現,包括有關hidl-gen編譯器從 HIDL .hal文件自動生成的文件的詳細信息、這些文件的打包方式以及如何將這些文件與 C++ 代碼集成使用它們。

客戶端和服務器實現

HIDL 接口具有客戶端和服務器實現:

  • HIDL 接口的客戶端是通過調用接口上的方法來使用接口的代碼。
  • 服務器是 HIDL 接口的實現,它接收來自客戶端的調用並返回結果(如有必要)。

在從libhardware HAL 過渡到 HIDL HAL 時,HAL 實現成為服務器,調用 HAL 的進程成為客戶端。默認實現可以同時服務於直通和綁定 HAL,並且會隨著時間而改變:

圖 1.傳統 HAL 的開發進度。

創建 HAL 客戶端

首先在 makefile 中包含 HAL 庫:

  • 製作: LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0
  • 宋: shared_libs: [ …, android.hardware.nfc@1.0 ]

接下來,包含 HAL 頭文件:

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

創建 HAL 服務器

要創建 HAL 實現,您必須擁有代表您的 HAL 的.hal文件,並且已經使用hidl-gen上的-Lmakefile-Landroidbp為您的 HAL 生成了 makefile( ./hardware/interfaces/update-makefiles.sh這樣做是為了內部 HAL 文件,是一個很好的參考)。從libhardware傳輸 HAL 時,您可以使用 c2hal 輕鬆完成很多此類工作。

要創建實現 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 在直通模式下工作,您必須在/(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl( OPTIONAL_IDENTIFIER ).so中擁有函數HIDL_FETCH_IModuleName其中OPTIONAL_IDENTIFIER是標識直通實現的字符串。上述命令會自動滿足直通模式要求,這些命令也會創建android.hardware.nfc@1.0-impl目標,但可以使用任何擴展。例如android.hardware.nfc@1.0-impl-foo使用-foo來區分自己。

如果 HAL 是另一個 HAL 的次要版本或擴展,則應使用基本 HAL 來命名此二進製文件。例如, android.hardware.graphics.mapper@2.1實現仍應位於名為android.hardware.graphics.mapper@2.0-impl( OPTIONAL_IDENTIFIER )的二進製文件中。通常,此處的OPTIONAL_IDENTIFIER將包含實際的 HAL 版本。通過像這樣命名二進製文件,2.0 客戶端可以直接檢索它,而 2.1 客戶端可以向上轉換實現。

接下來,用功能填寫存根並設置一個守護程序。示例守護程序代碼(支持直通):

#include <hidl/LegacySupport.h>

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

defaultPassthroughServiceImplementationdlopen()提供的-impl庫並將其作為綁定服務提供。示例守護程序代碼(用於純綁定服務):

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
}

這個守護進程通常存在於$PACKAGE + "-service-suffix"中(例如, android.hardware.nfc@1.0-service ),但它可以在任何地方。特定 HAL 類的sepolicy是屬性hal_<module> (例如, hal_nfc) 。該屬性必須應用於運行特定 HAL 的守護進程(如果同一進程服務於多個 HAL,則可以對其應用多個屬性)。