Android 8 會重新架構 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
- Soong:
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 在直通模式下運作,您必須讓函式 HIDL_FETCH_IModuleName
位於 /(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl(OPTIONAL_IDENTIFIER).so
中,其中 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 用戶端則可向上轉換實作。
接著,請為這些 Stub 填入功能,並設定 Daemon。守護程式程式碼範例 (支援轉送):
#include <hidl/LegacySupport.h> int main(int /* argc */, char* /* argv */ []) { return defaultPassthroughServiceImplementation<INfc>("nfc"); }
defaultPassthroughServiceImplementation
會為提供的 -impl
程式庫呼叫 dlopen()
,並將其提供為綁定服務。範例 Daemon 程式碼 (適用於純 Binderized 服務):
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 }
這個守護程式通常位於 $PACKAGE + "-service-suffix"
(例如 android.hardware.nfc@1.0-service
),但也可能位於其他位置。特定類別 HAL 的 sepolicy 是屬性 hal_<module>
(例如 hal_nfc)
)。這個屬性必須套用至執行特定 HAL 的守護程序 (如果同一個程序提供多個 HAL,則可套用多個屬性)。