自 2025 年 3 月 27 日起,我们建议您使用 android-latest-release
而非 aosp-main
构建 AOSP 并为其做出贡献。如需了解详情,请参阅 AOSP 的变更。
HIDL C++
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
Android 8 对 Android OS 的架构重新进行了设计,以在独立于设备的 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 的进程则成为客户端。默认实现可用于直通式 (passthrough) 和绑定式 (binderized) HAL,并可能会随着时间而发生变化:

图 1. 旧版 HAL 的发展历程。
创建 HAL 客户端
首先将 HAL 库添加到 makefile 中:
- Make:
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 客户端可以向上转换实现的类型。
接下来,使用功能填写存根并设置守护程序。守护程序代码(支持直通)示例:
#include <hidl/LegacySupport.h>
int main(int /* argc */, char* /* argv */ []) {
return defaultPassthroughServiceImplementation<INfc>("nfc");
}
defaultPassthroughServiceImplementation
会对收到的 -impl
库调用 dlopen()
,并将其作为绑定式服务提供。守护程序代码(对于纯绑定式服务)示例:
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 和/或其关联公司的注册商标。
最后更新时间 (UTC):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"]],["最后更新时间 (UTC):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)."]]