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,则可以将多个属性应用于它)。