Android 8 重新构建了 Android 操作系统,旨在为独立于设备的 Android 平台以及特定于设备和供应商的代码定义清晰的接口。Android 已经在 HAL 接口中定义了许多此类接口,这些接口在 hardware/libhardware
中定义为 C 标头。HIDL 用稳定、版本化的接口取代了这些 HAL 接口,这些接口可以是 C++ 中的客户端和服务器端 HIDL 接口(如下所述)或 Java。
本节中的页面介绍了 HIDL 接口的 C++ 实现,包括有关 hidl-gen
编译器从 HIDL .hal
文件自动生成的文件、这些文件的打包方式以及如何将这些文件与使用它们的 C++ 代码集成在一起的详细信息。
客户端和服务器实现
HIDL 接口具有客户端和服务器实现
- HIDL 接口的客户端是通过调用接口上的方法来使用该接口的代码。
- 服务器是 HIDL 接口的实现,它接收来自客户端的调用并返回结果(如果需要)。
在从 libhardware
HAL 过渡到 HIDL HAL 的过程中,HAL 实现变成了服务器,而调用 HAL 的进程变成了客户端。默认实现可以同时服务于直通式和绑定式 HAL,并且可以随时间变化
图 1. 传统 HAL 的开发过程。
创建 HAL 客户端
首先在 makefile 中包含 HAL 库
- 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 在直通模式下工作,您必须在 /(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"); }
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,则可以将多个属性应用于它)。