自 2025 年 3 月 27 日起,我們建議您使用 android-latest-release
而非 aosp-main
建構及貢獻 AOSP。詳情請參閱「Android 開放原始碼計畫變更」。
HIDL C++
透過集合功能整理內容
你可以依據偏好儲存及分類內容。
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,則可套用多個屬性)。
這個頁面中的內容和程式碼範例均受《內容授權》中的授權所規範。Java 與 OpenJDK 是 Oracle 和/或其關係企業的商標或註冊商標。
上次更新時間:2025-07-27 (世界標準時間)。
[[["容易理解","easyToUnderstand","thumb-up"],["確實解決了我的問題","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["缺少我需要的資訊","missingTheInformationINeed","thumb-down"],["過於複雜/步驟過多","tooComplicatedTooManySteps","thumb-down"],["過時","outOfDate","thumb-down"],["翻譯問題","translationIssue","thumb-down"],["示例/程式碼問題","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["上次更新時間:2025-07-27 (世界標準時間)。"],[],[],null,["# HIDL C++\n\nAndroid 8 re-architects the Android OS to define clear interfaces between the\ndevice-independent Android platform and device- and vendor-specific code.\nAndroid already defines many such interfaces in the form of HAL interfaces,\ndefined as C headers in `hardware/libhardware`. HIDL replaces these\nHAL interfaces with stable, versioned interfaces, which can be client- and\nserver-side HIDL interfaces in C++ (described below) or\n[Java](/docs/core/architecture/hidl-java).\n\nThe pages in this section describe C++ implementations of HIDL interfaces,\nincluding details about the files auto-generated from the HIDL `.hal`\nfiles by the `hidl-gen` compiler, how these files are packaged, and\nhow to integrate these files with the C++ code that uses them.\n\nClient and server implementations\n---------------------------------\n\nHIDL interfaces have client and server implementations:\n\n- A **client** of a HIDL interface is the code that uses the interface by calling methods on it.\n- A **server** is an implementation of a HIDL interface that receives calls from clients and returns results (if necessary).\n\nIn transitioning from `libhardware` HALs to HIDL HALs, the HAL\nimplementation becomes the server and the process calling into the HAL becomes\nthe client. Default implementations can serve both passthrough and binderized\nHALs, and can change over time:\n\n**Figure 1.** Development progression for legacy HALs.\n\nCreate the HAL client\n---------------------\n\nStart by including the HAL libraries in the makefile:\n\n- Make: `LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0`\n- Soong: `shared_libs: [ ..., android.hardware.nfc@1.0 ]`\n\nNext, include the HAL header files: \n\n```c++\n#include \u003candroid/hardware/nfc/1.0/IFoo.h\u003e\n...\n// in code:\nsp\u003cIFoo\u003e client = IFoo::getService();\nclient-\u003edoThing();\n```\n\nCreate the HAL server\n---------------------\n\nTo create the HAL implementation, you must have the `.hal` files\nthat represent your HAL and have already generated makefiles for your HAL using\n`-Lmakefile` or `-Landroidbp` on `hidl-gen`\n(`./hardware/interfaces/update-makefiles.sh` does this for internal\nHAL files and is a good reference). When transferring over HALs from\n`libhardware`, you can do a lot of this work easily using c2hal.\n\nTo create the necessary files to implement your HAL: \n\n```c++\nPACKAGE=android.hardware.nfc@1.0\nLOC=hardware/interfaces/nfc/1.0/default/\nm -j hidl-gen\nhidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces \\\n -randroid.hidl:system/libhidl/transport $PACKAGE\nhidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces \\\n -randroid.hidl:system/libhidl/transport $PACKAGE\n```\n\nFor the HAL to work in passthrough mode, you must have\nthe function `HIDL_FETCH_IModuleName` residing in\n`/(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl(`\u003cvar translate=\"no\"\u003eOPTIONAL_IDENTIFIER\u003c/var\u003e`).so`\nwhere \u003cvar translate=\"no\"\u003eOPTIONAL_IDENTIFIER\u003c/var\u003e is a string identifying the passthrough\nimplementation. The passthrough mode requirements are met automatically by the\nabove commands, which also create the `android.hardware.nfc@1.0-impl`\ntarget, but any extension can be used. For instance\n`android.hardware.nfc@1.0-impl-foo` uses `-foo` to\ndifferentiate itself.\n\nIf a HAL is a minor version or an extension of another\nHAL, the base HAL should be used to name this binary. For instance,\n`android.hardware.graphics.mapper@2.1` implementations should\nstill be in a binary called\n`android.hardware.graphics.mapper@2.0-impl(`\u003cvar translate=\"no\"\u003eOPTIONAL_IDENTIFIER\u003c/var\u003e`)`.\nUsually, the \u003cvar translate=\"no\"\u003eOPTIONAL_IDENTIFIER\u003c/var\u003e here would include the actual HAL\nversion. By naming the binary like this, 2.0 clients can retrieve it directly,\nand 2.1 clients can upcast the implementation.\n\nNext, fill out the stubs with functionality and setup a daemon. Example\ndaemon code (supporting passthrough): \n\n```c++\n#include \u003chidl/LegacySupport.h\u003e\n\nint main(int /* argc */, char* /* argv */ []) {\n return defaultPassthroughServiceImplementation\u003cINfc\u003e(\"nfc\");\n}\n```\n\n`defaultPassthroughServiceImplementation` calls\n`dlopen()` for the provided `-impl` library and provides it as\na binderized service. Example daemon code (for pure binderized service): \n\n```c++\nint main(int /* argc */, char* /* argv */ []) {\n // This function must be called before you join to ensure the proper\n // number of threads are created. The threadpool never exceeds\n // size one because of this call.\n ::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/);\n\n sp\u003cINfc\u003e nfc = new Nfc();\n const status_t status = nfc-\u003eregisterAsService();\n if (status != ::android::OK) {\n return 1; // or handle error\n }\n\n // Adds this thread to the threadpool, resulting in one total\n // thread in the threadpool. We could also do other things, but\n // would have to specify 'false' to willJoin in configureRpcThreadpool.\n ::android::hardware::joinRpcThreadpool();\n return 1; // joinRpcThreadpool should never return\n}\n```\n\nThis daemon usually lives in `$PACKAGE + \"-service-suffix\"` (for\nexample, `android.hardware.nfc@1.0-service`), but it could be anywhere.\nThe [sepolicy](/docs/security/features/selinux/device-policy) for a specific\nclass of HALs is the attribute `hal_\u003cmodule\u003e` (for instance,\n`hal_nfc)`. This attribute must be applied to the daemon that runs a\nparticular HAL (if the same process serves multiple HALs, multiple attributes\ncan be applied to it)."]]