1. HAL层概述:Android系统架构回顾、HAL层的作用与设计哲学、HAL与内核驱动的关系
1.1 Android系统架构:从上层到底层
做Android底层开发,首先得把系统架构刻在脑子里。我习惯把Android系统想象成一栋楼——用户看到的是顶层装修,而我们搞HAL的,负责的是中间的水电管道。
这栋楼从上到下大概分五层:
- 应用层(Application)——用户直接接触的App,比如相机、电话、地图。
- 应用框架层(Framework)——提供API给App调用,比如CameraManager、AudioManager。
- 系统运行库层(Libraries & Android Runtime)——C/C++原生库,加上ART虚拟机。
- HAL层(Hardware Abstraction Layer)——我们今天的重点,硬件抽象层。
- Linux内核层(Kernel)——真正的硬件驱动、进程管理、内存管理都在这里。
你想想看,一个App想打开摄像头,数据流是这样的:App → Framework → Native Service → HAL → Kernel Driver → 硬件。HAL就在中间,承上启下。
核心观点:HAL是Android系统里唯一一个「既懂上层框架,又懂底层硬件」的层次。搞懂它,你才算真正入了底层开发的门。
1.2 HAL层的作用与设计哲学
HAL存在的意义是什么?说白了就一句话:让上层框架不依赖具体的硬件实现。
我在项目中遇到过这样一个场景:某款手机用的是展讯平台,另一款用高通平台。两个平台的Camera HAL实现完全不同,但Framework层的Camera API却一模一样。这就是HAL的功劳——它把硬件差异全部封装在下面。
HAL的设计哲学,我总结为三点:
- 接口标准化——Google定义好HAL接口(比如camera3_device_t结构体),厂商必须按这个接口实现。接口不变,厂商怎么改都行。
- 实现私有化——厂商的HAL实现是闭源的,以.so文件形式存在。Google只看接口,不看实现。
- 解耦分层——Framework通过HAL调用硬件,不直接访问内核驱动。这样即使内核驱动换了,只要HAL接口不变,上层代码一行都不用改。
个人经验:我刚开始做HAL开发时,总觉得多此一举——直接调内核驱动多快啊?后来发现,不同厂商的内核驱动接口千奇百怪,没有HAL这层抽象,Framework得累死。嗯,HAL这层抽象,值。
1.3 HAL与内核驱动的关系
很多人分不清HAL和内核驱动的区别。我打个比方:
- 内核驱动是「翻译官」——把硬件的电信号翻译成Linux设备文件(/dev/xxx)。
- HAL是「项目经理」——把内核驱动提供的原始能力,包装成Framework能理解的接口。
举个例子,Camera HAL调用内核驱动的方式通常有两种:
- 通过设备节点:open("/dev/video0"),然后ioctl下发命令。
- 通过内存映射:mmap共享内存,传递图像数据。
我曾经踩过一个坑:某款芯片的ISP驱动在某个内核版本里改了ioctl命令码,但HAL层没同步更新。结果相机打不开,查了两天才定位到问题。从那以后,我每次做内核驱动升级,都会先检查HAL和驱动的接口是否对齐。
避坑指南:HAL和内核驱动的接口协议(ioctl命令码、数据结构)一定要文档化。我曾经见过一个项目,HAL和驱动的接口全靠口头沟通,结果一换人,整个项目瘫痪了两周。
1.4 HAL层的两种架构模式
Android HAL发展到现在,主要有两种架构:
| 对比项 | 传统HAL(Legacy HAL) | HIDL HAL(Treble架构) |
|---|---|---|
| 定义方式 | hardware/libhardware头文件 | .hal接口文件(自动生成代码) |
| 通信方式 | 直接函数调用(同一进程) | Binder/RPC跨进程调用 |
| 兼容性 | Framework和HAL强耦合 | Framework和HAL可独立升级 |
| 典型场景 | Android 8.0之前 | Android 8.0及之后 |
我个人更推荐新项目直接上HIDL。虽然学习曲线陡一点,但跨进程通信带来的稳定性提升是实打实的。Framework挂了,HAL还能继续跑,这在多媒体场景下特别重要。
1.5 本章知识体系总览
下面这张图,是我自己画的知识结构。每次带新人,我都会先让他们看这张图——搞懂HAL在整个系统中的位置,比背代码重要得多。
1.6 小结
这一章我们干了三件事:
- 回顾了Android系统架构,明确了HAL在五层模型中的位置。
- 理解了HAL的设计哲学——接口标准化、实现私有化、解耦分层。
- 理清了HAL和内核驱动的关系——HAL是项目经理,内核驱动是翻译官。