4. HAL Service 实现框架:生命周期、注册与启动
HAL Service 是整个硬件抽象层的执行核心。说白了,它就是运行在系统服务进程里的一个 Native 服务,负责跟底层的硬件驱动打交道,向上给 Framework 提供稳定的接口。
我刚开始接触 HAL Service 时,总觉得它跟普通的 Android Service 差不多。后来踩了几个坑才明白——它的生命周期管理、注册流程、启动顺序,每一个环节都有讲究。搞不清楚这些,写出来的 HAL Service 要么跑不起来,要么跑起来就崩。
4.1 HAL Service 的生命周期
一个典型的 HAL Service,从生到死会经历这几个阶段:
| 阶段 | 触发时机 | 关键动作 |
|---|---|---|
| 构造 | 进程启动,main() 执行 | 分配资源、初始化成员变量 |
| 注册 | 构造完成后立即执行 | 调用 registerAsService() 向 HwServiceManager 注册 |
| 运行 | 注册成功后进入事件循环 | 等待客户端请求,处理事务 |
| 销毁 | 进程退出或异常终止 | 释放资源、关闭硬件设备 |
这里有个容易忽略的点:HAL Service 没有像 Java Service 那样的 onStart/onStop 回调。它的生命周期完全由进程的 main() 函数控制。你写多少代码,它就活多久。
4.2 HwServiceManager 的作用
HwServiceManager 是 Android 8.0 之后引入的组件。它的角色,你可以理解成「硬件服务的电话总机」。
为什么需要它?
- 服务发现:客户端(比如 Framework 的 SensorService)想知道某个 HAL Service 在不在,得通过 HwServiceManager 来查
- 服务注册:每个 HAL Service 启动后,必须把自己的名字和接口告诉 HwServiceManager
- 服务保活:HwServiceManager 会监控已注册服务的状态,如果服务挂了,它能感知到
我个人的习惯是,把 HwServiceManager 看作一个「轻量级的 ServiceManager」。它不负责进程间通信的细节,只负责维护一个服务名到服务实例的映射表。
核心概念:HwServiceManager 本身也是一个独立的进程,在系统启动时由 init 进程拉起。它的代码在 hardware/interfaces/hwservicemanager/ 目录下。
4.3 HAL Service 的注册流程
注册流程,说白了就是三步:
- 创建服务实例:在 main() 函数里 new 出你的 HAL Service 对象
- 调用注册接口:通过
registerAsService()把服务注册到 HwServiceManager - 进入事件循环:调用
joinRpcThreadpool()让服务开始监听客户端请求
来看一个典型的代码骨架:
int main() {
// 1. 创建服务实例
sp<IFoo> service = new Foo();
// 2. 注册服务
status_t status = service->registerAsService("default");
if (status != OK) {
ALOGE("Failed to register Foo HAL service: %d", status);
return 1;
}
// 3. 进入事件循环
joinRpcThreadpool();
return 0;
}
嗯,这里要注意:registerAsService() 的第一个参数是实例名。同一个 HAL 接口可以有多个实例,比如 "default"、"custom"、"debug" 等等。客户端在获取服务时,需要指定实例名才能拿到对应的服务。
避坑指南:我曾经在项目里犯过一个低级错误——注册服务时忘了检查返回值。结果服务没注册成功,客户端一直拿不到服务,日志里也没有任何错误信息。排查了半天才发现是注册失败了。所以,一定要检查 registerAsService() 的返回值。
4.4 HAL Service 的启动与初始化
HAL Service 的启动,不是由 Framework 直接拉起的。它走的是 Android 传统的 init 进程启动流程。
具体来说:
- 在
device/<vendor>/<device>/init.rc里定义 service 条目 - init 进程解析 rc 文件,启动对应的可执行文件
- 可执行文件的 main() 函数执行,完成服务初始化和注册
一个典型的 init.rc 配置长这样:
service vendor.foo-hal /vendor/bin/hw/vendor.foo-hal
class hal
user system
group system
seclabel u:r:hal_foo:s0
这里有几个关键点:
- class hal:表示这个服务属于 hal 类,系统启动时会批量启动所有 hal 类服务
- user/group:指定服务运行的 uid/gid,通常是 system
- seclabel:SELinux 上下文,必须跟策略文件里定义的一致
dmesg | grep avc 的输出,里面会明确告诉你哪个上下文被拒绝了。
初始化阶段,除了注册服务,通常还需要做这些事:
- 打开硬件设备:通过 open() 系统调用打开 /dev 下的设备节点
- 初始化硬件:设置寄存器、配置中断、分配 DMA 缓冲区等
- 创建工作线程:有些 HAL Service 需要后台线程处理异步事件
- 设置回调:注册死亡通知、状态变化回调等
我个人习惯把初始化逻辑拆成几个小函数,每个函数只做一件事。这样调试起来方便,出问题了也能快速定位。
4.5 整体流程梳理
把上面这些串起来,HAL Service 的完整生命周期可以用下面这张图来表示:
这张图把整个流程串起来了。你想想看,从 init 启动到服务注册,再到硬件初始化和事件循环,每一步都有明确的职责。搞清楚了这些,写 HAL Service 的时候心里就有底了。
总结一下:HAL Service 的实现框架,核心就是三件事——注册(让系统能找到你)、初始化(让硬件能工作)、事件循环(让客户端能调用你)。把这三点做好,一个稳定的 HAL Service 就搭起来了。