2. Android系统架构与HAL定位
要理解HAL Service开发,必须先建立一张清晰的“系统地图”:Android并不是一个单体操作系统,而是由应用层、框架层、原生库与运行时、HAL层、内核层共同组成的纵向分层体系。HAL(Hardware Abstraction Layer,硬件抽象层)位于Framework与Linux Kernel之间,是Android为硬件厂商保留的“标准接口层”。它既向上为Java/Kotlin框架提供稳定的硬件访问能力,又向下屏蔽具体SoC、外设和驱动差异,使Android框架不必为每一块硬件重新编译。
一、Android分层架构:从App到Kernel
从下往上观察,Android系统大致分为五层。最底层是Linux Kernel,负责进程调度、内存管理、文件系统、网络协议栈以及各类硬件驱动;其上是HAL层,通常以共享库(.so)或独立HAL Service进程形式存在,封装摄像头、音频、传感器、蓝牙、显示、电源等硬件能力;再往上是Native C/C++ Libraries与Android Runtime,提供libc、OpenGL ES、Vulkan、Media框架、SQLite以及ART虚拟机;接着是Java API Framework,即我们熟悉的ActivityManager、WindowManager、CameraManager、SensorManager等系统服务;最上层是System Apps与第三方应用。
这种分层的核心价值在于“解耦”:应用只依赖Framework API,Framework只依赖HAL接口,HAL只依赖内核驱动。任何一层内部实现变化,只要接口不变,就不会向上层扩散。对于HAL开发者而言,这意味着工作边界非常明确——你实现的是HAL接口,而不是直接修改Framework或内核。
二、HAL在系统中的精确位置
HAL并不是一个“可选插件”,而是Android兼容性定义文档(CDD)和供应商接口(VINTF)约束下的强制层。在Android 8.0之前,HAL多以共享库形式被Framework直接加载,运行在system_server或Native服务进程中;Android 8.0引入Project Treble后,HAL被要求以独立进程形式运行,通过HIDL(Android 8~10)或AIDL(Android 11+)与Framework通信。这一变化使HAL Service成为真正的“系统服务”,拥有自己的进程、生命周期和权限边界。
从进程视角看,HAL Service通常由init进程根据.rc文件启动,注册到ServiceManager,Framework通过Binder获取代理对象并调用。例如Camera HAL Service运行在独立的cameraserver或vendor进程中,Sensor HAL Service运行在android.hardware.sensors-service进程中。这种设计让HAL崩溃不会直接拖垮system_server,也让厂商可以独立升级HAL而不影响Framework。
三、HAL与Framework、Kernel的交互关系
HAL与Framework之间是“接口契约”关系:Framework定义接口(如ICameraProvider、ISensors),HAL实现接口。Framework不关心HAL内部如何操作硬件,只关心接口调用是否成功、数据格式是否正确、回调是否及时。HAL与Kernel之间是“驱动调用”关系:HAL通过open/ioctl/read/write/mmap等系统调用访问/dev下的设备节点,或通过sysfs、netlink、uevent等机制与驱动交互。
一个典型的调用链如下:应用调用CameraManager.openCamera() → Framework CameraService通过Binder调用ICameraProvider → HAL Service收到请求后打开/dev/video0并配置V4L2参数 → 驱动操作ISP和Sensor → 图像数据通过DMA写入缓冲区 → HAL将buffer回传给Framework → 应用收到预览帧。这条链路中,HAL既是“翻译官”,也是“调度员”。
| 层次 | 典型对象 | 与HAL的关系 | 开发者关注点 |
|---|---|---|---|
| 应用层 | Camera App、Sensor App | 不直接接触HAL | API调用与权限 |
| Framework层 | CameraService、SensorService | 通过Binder调用HAL接口 | 接口定义、VINTF声明 |
| HAL层 | Camera HAL、Sensor HAL | 实现接口、调用驱动 | 接口实现、进程模型、线程模型 |
| Kernel层 | V4L2、ALSA、IIO驱动 | 被HAL通过系统调用访问 | 设备节点、ioctl参数、DMA |
四、案例场景:Sensor HAL的一次数据上报
以加速度传感器为例。应用注册SensorEventListener后,Framework的SensorService通过ISensors接口向Sensor HAL发送activate和batch请求。HAL Service收到后,打开/dev/iio:device0,配置采样率和量程,并启动一个poll线程等待数据。当驱动产生中断并写入数据后,HAL读取event,按照sensors_event_t格式封装,再通过回调接口上报给Framework。Framework经过权限和速率过滤后,通过Binder回调给应用。整个过程中,HAL负责“把驱动原始数据变成Android标准事件”,这是HAL最核心的职责。
// 伪代码:Sensor HAL 数据上报核心逻辑
while (running) {
poll(fd, POLLIN);
read(fd, &raw_event, sizeof(raw_event));
sensors_event_t event;
event.sensor = handle;
event.type = SENSOR_TYPE_ACCELEROMETER;
event.acceleration.x = raw_event.x * scale;
event.acceleration.y = raw_event.y * scale;
event.acceleration.z = raw_event.z * scale;
event.timestamp = raw_event.timestamp;
callback->postEvents(&event, 1);
}
五、常见误区与复盘
误区一:把HAL当成驱动。HAL不是驱动,驱动在内核态,HAL在用户态。HAL可以调用驱动,但也可以完全用软件模拟(如虚拟传感器)。
误区二:认为HAL可以随意改接口。HAL接口受VINTF和CDD约束,修改接口会导致Framework兼容性检查失败,设备无法通过CTS/VTS。
误区三:忽略进程隔离。Treble之后HAL Service是独立进程,不能直接访问Framework内部变量,必须通过Binder通信,且要处理死亡通知和超时。
复盘建议:开发HAL Service时,先画清楚“应用→Framework→HAL→Kernel”的调用链,明确每一层的输入输出和线程模型;再确认VINTF manifest中声明的接口版本与Framework期望一致;最后用lshal、dumpsys、logcat和perfetto验证服务是否注册、调用是否到达、数据是否正确。
总结来说,Android分层架构决定了HAL的“中间人”角色:向上提供稳定、标准、可版本化的硬件访问接口,向下封装驱动差异和硬件细节。理解HAL在系统中的位置,以及它与Framework、Kernel的交互边界,是后续开发、调试和优化HAL Service的基础。