1. HAL与HIDL概述:Android硬件抽象层演进史、Treble架构解析、HIDL设计哲学
各位同学,咱们今天聊聊Android HAL的来龙去脉。说实话,我刚开始做Android底层开发那会儿,HAL还是个挺朴素的东西。后来Google搞了个Treble,整个架构天翻地覆。嗯,咱们一步步看。
1.1 从HAL到Treble:一场被迫的进化
先说说为什么要有HAL。Android系统跑在Linux内核上,但Google不想让硬件厂商把驱动代码全开源。怎么办?在Framework和Kernel之间加个抽象层,这就是HAL(Hardware Abstraction Layer)。
早期的HAL长这样:
// 传统HAL模块结构
struct hw_module_t {
uint32_t tag; // 固定为 HARDWARE_MODULE_TAG
uint16_t module_api_version;
uint16_t hal_api_version;
const char *id; // 模块ID,如 "audio"、"camera"
const char *name;
const char *author;
struct hw_module_methods_t *methods;
void *dso; // 动态库句柄
uint32_t reserved[32];
};
这种设计有个致命问题——Framework直接加载HAL的so库。你想想看,每次系统升级,厂商都得重新编译HAL,用户等OTA等到花儿都谢了。我在项目里遇到过,Android 7.0升8.0,光适配HAL就花了三个月。
核心痛点:Framework与HAL强耦合,系统升级必须同步更新HAL,厂商碎片化严重。
Google也意识到这不行。2017年,Android 8.0带着Treble架构来了。说白了,就是把Framework和HAL彻底拆开,中间用HIDL(HAL Interface Definition Language)定义稳定接口。
1.2 Treble架构解析:三层分离
Treble架构把系统分成三块:
| 层级 | 内容 | 更新方式 |
|---|---|---|
| Framework层 | System Server、Java API、系统服务 | OTA直接推送 |
| HAL层 | HIDL Service、Vendor实现 | 厂商独立更新 |
| Kernel层 | Linux内核、设备驱动 | 厂商独立更新 |
中间那个HAL层,就是咱们这门课的核心。Framework通过HIDL接口调用HAL服务,不再直接加载so库。接口是稳定的,厂商只要保证接口不变,系统随便升。
我的经验:Treble刚出来时,很多厂商抱怨工作量翻倍。但你看现在,Android 12升13,主流机型两周就能推送。这就是接口稳定的威力。
咱们画个图,把Treble架构看清楚:
1.3 HIDL设计哲学:稳定压倒一切
HIDL不是随便拍脑袋想出来的。它的设计哲学,我总结成三条:
- 接口即契约——.hal文件定义了Framework和HAL之间的所有交互,双方都得遵守。
- 版本化演进——接口可以升级,但必须向后兼容。老版本不能断。
- 跨进程透明——调用HIDL服务就像调用本地函数,Binder帮你搞定IPC。
举个例子,一个简单的HIDL接口长这样:
// IMyLight.hal
package vendor.example.light@1.0;
interface IMyLight {
/**
* 设置灯光亮度
* @param brightness 0-255
* @return Status 操作结果
*/
setBrightness(uint8_t brightness) generates (Status status);
/**
* 获取当前亮度
* @return brightness 当前亮度值
*/
getBrightness() generates (uint8_t brightness);
};
你看,接口定义里没有实现细节,只有方法签名和返回值。这就是契约精神——厂商怎么实现我不管,但接口必须对得上。
避坑指南:我曾经在项目里犯过一个错——在HIDL接口里传了复杂结构体,结果跨进程序列化性能惨不忍睹。记住,HIDL接口参数尽量用基本类型,复杂数据用回调或者分批传输。
1.4 两种HAL模式:Binderized vs Passthrough
HIDL支持两种运行模式,咱们对比一下:
| 特性 | Binderized HAL | Passthrough HAL |
|---|---|---|
| 进程模型 | 独立进程,通过Binder通信 | 加载到调用进程,直接函数调用 |
| 安全性 | 高,进程隔离 | 低,共享地址空间 |
| 性能 | 有IPC开销 | 零拷贝,性能高 |
| 适用场景 | 大多数HAL(Camera、Audio等) | 高性能要求(GPU、显示) |
| 推荐程度 | Google推荐 | 尽量迁移到Binderized |
我个人习惯,新项目一律用Binderized。为什么?安全。你想想看,Passthrough模式下HAL跑在System Server进程里,一旦崩溃,整个系统都挂了。我在项目里遇到过,某个厂商的Passthrough HAL内存泄漏,导致系统三天两头重启。
关键结论:Treble + HIDL = Android系统升级不再依赖厂商。这是Android生态走向健康的关键一步。
1.5 本章小结
咱们这一章把HAL的演进史、Treble架构、HIDL设计哲学都过了一遍。核心就一句话:接口稳定,各自独立,契约驱动。后面的章节,咱们会深入HIDL语法、服务实现、测试验证,一步步把理论变成代码。
嗯,先消化这些。有问题随时问。