【全栈第8课】HIDL 老式 HAL 与 AIDL 对比
Android 全栈工程师进阶教程 第08课。HIDL 老式 HAL 与 AIDL 对比。基于公开 AOSP 知识整理,含原理、可编译示例、常见问题定位。
> 本文是《Android 全栈工程师进阶教程》系列第 08 课。完整 26 课见 GitHub 仓库。
【全栈第8课】HIDL 老式 HAL 与 AIDL 对比
0. 这节课你将做出什么
读懂 某真实机型 里现存的 HIDL .hal 接口,做一份 HIDL vs AIDL 对比。
学完你能回答:HAL 一共经历了哪几代?HIDL 的 .hal 语法长什么样?为什么 Android 新版本 强制把 HAL 从 HIDL 转成 AIDL? 这一课不写新代码(HIDL 已废弃),目的是理解历史,这样 L9 写 AIDL HAL 时你知道"为什么是这样"。
1. 背景:HAL 的三代演进
HAL(Hardware Abstraction Layer,硬件抽象层)是 framework 和硬件驱动之间的一层。它经历了三代:
| 代 | 时期 | 形态 | 问题 |
|---|---|---|---|
| 第一代 hw_module_t | Android 8 前 | dlopen .so + 结构体函数指针,无 IPC,system/vendor 编一起 | 耦合,无法独立升级(Treble 前的痛) |
| 第二代 HIDL | Android 8(Treble) | .hal 接口语言 + hidl-gen 生成,跨进程 | 独立一套语言/工具,学习成本高 |
| 第三代 AIDL for HAL | Android 11+(新版本 强制) | 复用 AIDL,语法统一 | —— L9 学这个 |
本课聚焦第二代 HIDL,理解它为什么被淘汰。
2. 全局图:HIDL 在哪一层
Framework(system)
│ 通过 HIDL 接口跨进程调用
▼
HIDL HAL 服务(vendor 进程)
│ 通过 hw_binder(binder 的一个 context)通信
▼
内核驱动
HIDL 解决了第一代的耦合问题(跨进程、Treble 解耦),但它是独立的一套接口定义语言(IDL),有自己的 .hal 语法、hidl-gen 工具、版本管理规则——和 framework 一直在用的 AIDL 完全是两套东西。
3. 某真实机型 真实源码印证:HIDL 接口长什么样
hardware/interfaces/boot/1.0/IBootControl.hal:
package android.hardware.boot@1.0; // ← 包名带 @版本号(HIDL 特色)
interface IBootControl {
// ← 返回值用 generates(...),不是直接 return
getNumberSlots() generates (uint32_t numSlots);
setActiveBootSlot(uint32_t slot) generates (CommandResult error);
}
HIDL 语法特点:
- 包名带
@1.0版本号(版本是包名的一部分) - 返回值用
generates (类型 名字),而不是 C 那样类型 method() - 配套
types.hal定义结构体
某真实机型 树里还有 749 个 .hal 文件(camera 等遗留没转完),但新 HAL 一律 AIDL。
4. 前置准备
- 依赖 L7(Treble/VINTF)。
- 本课是阅读理解,产出一份对比文档,不写可编译代码。
5. 动手:HIDL vs AIDL 全面对比
| 维度 | HIDL | AIDL(L9) |
|---|---|---|
| 接口文件 | I*.hal + types.hal | I*.aidl |
| 包名 | android.hardware.boot@1.0(带版本) | vendor.example.demo(版本在 manifest) |
| 返回值 | method() generates (T out) | T method() 直接返回 |
| 工具 | hidl-gen | aidl |
| 版本管理 | 包名 @x.y + .hash 文件 | aidl_interface 的 versions 冻结目录 |
| 注册 | registerAsService() | AServiceManager_addService |
| 客户端获取 | IXxx::getService() | IXxx::fromBinder(waitForService(...)) |
| 后端 | C++/Java | C++/Java/NDK/Rust |
| 新版本 态度 | 废弃,chipset API≥202404 强制 AIDL | 主推 |
6. 看底层:为什么 Android 抛弃 HIDL 转 AIDL
- 重复造轮子:AIDL 本来就有(framework 跨进程一直用它),HIDL 是另起炉灶又造一套 IDL+工具。统一成 AIDL 能减少一整套工具链的维护。
- AIDL 通吃:同一套 AIDL 既能给 App 用、又能给 HAL 用、还能给系统服务用。学一套通吃,而 HIDL 只能 HAL 用。
- 新版本 硬性要求(见全栈路线 新版本 总结):chipset
ro.board.api_level ≥ 202404且 launch/upgrade 到 新版本 的设备,必须用 AIDL,不能用 HIDL——这是 Google 在 新季度版本 的强制要求,目的是彻底完成 HIDL→AIDL 迁移。
7. 编译 & 运行(本课无编译产物)
# 查设备上现存的 HIDL 和 AIDL HAL 各有哪些:
adb shell lshal | grep "@" # 带 @版本 的是 HIDL
adb shell lshal | grep -v "@" # 不带的多是 AIDL
> 验证状态(诚实):本课为阅读理解课,无可编译产物。HIDL 语法引自 某真实机型 真实 IBootControl.hal。
8. 踩坑提醒(遇到老 HIDL 代码时)
- 别再写新 HIDL HAL:新版本 不允许,新需求一律 AIDL(L9)。
- 改老 HIDL 接口要慎重:HIDL 接口一旦发布,版本(@1.0)就冻结了,改要发新版本 @1.1,不能直接改老的。
- HIDL 和 AIDL 的服务名风格不同:HIDL 是
包名@版本::接口/实例,AIDL 是包名.接口/实例,lshal 里都能看到。 - HIDL 转 AIDL 不是改个语法:数据结构、版本管理、注册方式都变,是重写,要充分测试。
9. 常见问题分析与定位(遗留 HIDL 实战)
9.1 常见问题清单
- 老设备某 HIDL HAL 起不来 / lshal 显示 N/A
- HIDL → AIDL 迁移后功能异常
- 新版本 上 CTS/VTS 报"还在用 HIDL"
- HIDL 接口版本冲突
9.2 分析与定位
① HIDL HAL 起不来(lshal N/A)
adb shell lshal | grep <hal名> # 看状态,N/A=声明了没起
adb shell lshal list --types=b # 列 hidl/binderized HAL
adb logcat | grep -iE "<hal名>|hwservicemanager"
- 和 AIDL 类似:声明了没起 → 查 HAL 进程的 .rc/sepolicy(L11);hwservicemanager(HIDL 的 servicemanager)有没有正常工作。
② 迁移后功能异常
- 原因:HIDL 和 AIDL 数据类型映射、默认值、错误处理语义有差异。
- 定位:对比迁移前后接口语义;抓 HAL 日志看调用参数/返回值是否一致。
③ 新版本 报还在用 HIDL
- 现象:VTS/CTS fail,提示 chipset API≥202404 不允许 HIDL。
- 修复:把对应 HIDL HAL 迁成 AIDL(L9 的做法)。
④ HIDL 版本冲突
- 原因:manifest 声明版本和实现版本不一致,或多个版本并存。
- 定位:
lshal看实际版本;对比 manifest target-level。
9.3 定位决策树
遗留 HIDL 出问题
├─ HAL 起不来(N/A) → lshal + hwservicemanager 日志 → .rc/sepolicy(L11)
├─ 迁移后异常 → 对比 HIDL/AIDL 类型映射+语义 → 抓 HAL 日志比对参数
├─ 新版本 报用 HIDL → 迁成 AIDL(L9)
└─ 版本冲突 → lshal 看实际版本 vs manifest target-level
10. 小结
- HAL 三代:hw_module_t(无IPC,耦合)→ HIDL(Treble,跨进程)→ AIDL(新版本 强制,统一)。
- HIDL 语法特征:包名带
@版本、返回值用generates、配types.hal、工具hidl-gen。 - 抛弃 HIDL 的原因:AIDL 本就有、通吃、新版本 硬性要求统一。
- 实战:别写新 HIDL,遇老 HIDL 改动慎重(版本冻结),迁 AIDL 是重写要测。
- 排查口诀:lshal 看状态(带 @ 是 HIDL);起不来查 hwservicemanager+sepolicy;新版本 报错就迁 AIDL。
下节预告
L9:AIDL HAL 编写(vendor 实现) —— 阶段二重头戏!真正从零写一个完整的 hello AIDL HAL:接口+实现+注册+init.rc+vintf+Android.bp。