3. HAL演进与类型
Android HAL(Hardware Abstraction Layer)是连接 Framework 与内核驱动的关键中间层。它的形态并非一成不变,而是随着 Android 版本迭代经历了三次重要演进:Legacy HAL、HIDL HAL 与 AIDL HAL。理解这条演进主线,以及 Passthrough 与 Binderized 两种运行模式,是开发与调试 HAL Service 的基础。
一、核心原理:三代 HAL 的接口与进程模型
Legacy HAL 采用 C 语言头文件加函数指针结构体的方式,Framework 通过 hw_get_module() 加载 .so 动态库,直接以函数调用方式访问硬件。它没有版本化接口,也没有进程隔离,HAL 实现通常与调用方处于同一进程。
HIDL(HAL Interface Definition Language)在 Android 8.0 引入,使用 .hal 文件定义接口,通过 hidl-gen 生成 C++ 或 Java 代理与桩代码。HIDL 支持版本化(如 android.hardware.light@2.0),并允许 HAL 运行在独立进程中,通过 Binder 通信。
AIDL HAL 自 Android 11 起逐步推广,使用 .aidl 文件定义接口,复用 AIDL 工具链与 Binder 机制。相比 HIDL,AIDL HAL 语法更简洁、支持稳定 AIDL、可直接使用 Java 与 C++ 互操作,并成为 Android 14 之后新 HAL 的默认选择。
二、方法流程:Passthrough 与 Binderized 的切换
HIDL 时代,同一个 HAL 可以以两种模式运行,由 manifest.xml 与 vintf 配置决定。Passthrough 模式下,Framework 通过 dlopen 加载 HAL 的 .so,接口调用退化为本地函数调用;Binderized 模式下,HAL 作为独立服务注册到 hwservicemanager,Framework 通过 HwBinder 代理访问。
AIDL HAL 则默认采用 Binderized 模式,服务注册到 servicemanager,客户端通过 getService() 获取代理。若需兼容旧行为,可通过 VINTF 声明 passthrough 模式,但新设备应优先使用 Binderized。
# 查看当前设备 HAL 注册情况
adb shell dumpsys -l | grep -i hal
adb shell service list | grep android.hardware
# HIDL 服务查询
adb shell lshal
adb shell lshal --types=b
# AIDL HAL 服务查询
adb shell dumpsys android.hardware.light.ILights/default
三、案例场景:灯光 HAL 的三代实现对比
以灯光 HAL 为例,Legacy 版本直接提供 light_device_t 结构体,Framework 通过 hw_get_module(LIGHT_HARDWARE_MODULE_ID) 获取并调用 set_light()。HIDL 版本定义 android.hardware.light@2.0::ILight,实现 setLightState(),通过 lshal 可看到服务名。AIDL 版本定义 android.hardware.light.ILights,使用稳定 AIDL,服务名形如 android.hardware.light.ILights/default。
调试要点:Legacy HAL 出错时通常表现为 hw_get_module 返回负值或 dlopen 失败;HIDL 出错时 lshal 中服务缺失或 getService 返回空;AIDL 出错时 servicemanager 中查不到实例,或 getService 抛 ServiceSpecificException。
四、各版本适用场景与选型清单
| 类型 | 接口定义 | 通信机制 | 适用 Android 版本 | 典型场景 |
|---|---|---|---|---|
| Legacy HAL | C 头文件 + hw_module_t | 直接函数调用 | Android 7 及以下 | 旧设备维护、简单传感器 |
| HIDL Passthrough | .hal + hidl-gen | dlopen + 本地调用 | Android 8–10 过渡期 | 启动早期 HAL、兼容旧实现 |
| HIDL Binderized | .hal + hidl-gen | HwBinder | Android 8–13 | Camera、Audio、Graphics 等 |
| AIDL Binderized | .aidl + aidl 工具链 | Binder | Android 11+,14 起默认 | Light、Vibrator、Power、Thermal |
选型建议:新项目优先使用 AIDL HAL;若需兼容 Android 10 以下,可保留 HIDL;Legacy HAL 仅用于维护存量设备。Passthrough 模式适合启动极早期或对性能极敏感的模块,但会牺牲进程隔离带来的稳定性。
常见误区:误以为 HIDL 与 AIDL 可以随意混用同一服务名;误以为 Passthrough 一定比 Binderized 快——在跨进程频繁调用场景下,Binderized 的隔离优势往往比微小开销更重要;忽略 VINTF 清单导致服务注册成功但 Framework 无法发现。
五、复盘:演进背后的设计逻辑
从 Legacy 到 HIDL 再到 AIDL,核心驱动力是接口版本化、进程隔离与工具链统一。Legacy 解决了“能访问硬件”,HIDL 解决了“可版本化与可隔离”,AIDL 则解决了“与 Android 生态统一、降低维护成本”。理解这条主线,就能在调试时快速判断:当前 HAL 属于哪一代、运行在哪种模式、应该用哪套工具链去排查。
实际开发中,建议先通过 lshal 或 service list 确认 HAL 是否注册、运行模式是 Passthrough 还是 Binderized,再结合 logcat 与 dmesg 定位是接口定义、服务注册还是底层驱动的问题。掌握三代 HAL 的差异与适用场景,是后续编写和调试 HAL Service 的前提。