4. HAL Service 实现:生命周期、注册与客户端获取
好,咱们进入第四章。这一章讲的是 HAL Service 的具体实现。说白了,就是让硬件服务真正跑起来,能被别人找到、调用。
我刚开始接触 HAL 开发时,觉得 Service 不就是个后台进程嘛,有什么难的?结果第一次写就踩了坑——服务注册成功了,客户端却死活连不上。后来才发现,是生命周期回调没处理好。
咱们一步步来,先搞清楚 Service 的生命周期,再讲怎么注册到 hwservicemanager,最后看客户端怎么拿到这个 Service。
4.1 Service 生命周期:从生到死
一个 HAL Service 的生命周期,其实就四个阶段:创建、初始化、运行、销毁。听起来简单,但每个阶段都有坑。
| 阶段 | 触发时机 | 关键操作 | 常见问题 |
|---|---|---|---|
| 创建 | 进程启动 | 分配内存、初始化成员变量 | 资源泄漏 |
| 初始化 | onCreate() 回调 | 打开硬件设备、建立连接 | 设备打开失败 |
| 运行 | 注册成功后 | 处理客户端请求、轮询硬件 | 死锁、ANR |
| 销毁 | 进程退出或异常 | 关闭设备、释放资源 | 资源未释放 |
嗯,这里要注意:Android 的 HAL Service 通常跑在独立的进程中。进程挂了,hwservicemanager 会自动感知,然后清理注册信息。但如果你在销毁阶段没做好清理,下次启动时可能就出问题了。
4.2 注册 Service 到 hwservicemanager
注册这一步,是让系统知道「我在这儿,快来用我」。hwservicemanager 就像一个服务黄页,所有 Service 都要在上面登记。
注册的核心代码其实不多,但顺序很重要。我习惯这样写:
// 1. 创建 Service 实例
sp<IYourHardware> service = new YourHardwareService();
// 2. 注册到 hwservicemanager
status_t status = defaultServiceManager()->addService(
String16("vendor.yourcompany.hardware.yourdevice"),
service
);
// 3. 检查注册结果
if (status != OK) {
ALOGE("Failed to register service: %d", status);
return -1;
}
// 4. 进入消息循环
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
你想想看,这里最关键的是第 4 步。很多人注册完就以为完事了,结果进程直接退出。因为主线程没有进入消息循环,addService 返回后进程就结束了。
注册的服务名有讲究。Google 推荐用「vendor.公司名.硬件类型.设备名」的格式。比如:
vendor.google.sensors.gyroscopevendor.qualcomm.camera.backvendor.yourcompany.display.primary
这样做的好处是避免命名冲突。我见过有人直接用「test_service」,结果跟系统服务重名了,调试了半天才发现。
4.3 客户端获取 Service
客户端获取 Service 的过程,其实就是去 hwservicemanager 查黄页。拿到 Service 的代理对象,然后通过 Binder 通信调用方法。
获取方式有两种:同步和异步。我一般用同步方式,代码更直观:
// 客户端获取 Service
sp<IYourHardware> service = nullptr;
// 尝试获取服务,最多等待 5 秒
for (int retry = 0; retry < 5; retry++) {
service = interface_cast<IYourHardware>(
defaultServiceManager()->getService(
String16("vendor.yourcompany.hardware.yourdevice")
)
);
if (service != nullptr) {
break;
}
// 没拿到就等一会儿再试
usleep(1000 * 1000); // 1秒
}
if (service == nullptr) {
ALOGE("Failed to get service after 5 retries");
return -1;
}
// 调用服务方法
int result = service->doSomething();
为什么要重试?因为 Service 可能还没启动完。hwservicemanager 是立即返回的,如果 Service 还没注册,getService 就返回 null。我建议至少重试 3-5 次,每次间隔 1 秒。
4.4 整体流程:一张图看懂
说了这么多,咱们用一张图把整个流程串起来。从 Service 启动到客户端调用,每一步都清晰可见。
从图上能看出来,整个流程是单向的。Service 先注册,Client 后获取。如果顺序反了,Client 就拿不到 Service。
4.5 实战中的几个坑
最后,我总结几个实战中容易踩的坑,你们写代码时多留意:
- 服务名拼写错误——注册和获取用的名字必须完全一致,大小写敏感。我建议把服务名定义成常量,两边引用同一个。
- 权限问题——Service 进程可能需要 SELinux 权限才能注册。如果注册失败,先看 logcat 里有没有 avc: denied 的提示。
- 多线程死锁——Service 的回调函数里不要调用 getService,否则可能死锁。因为 hwservicemanager 的锁是全局的。
- 进程保活——HAL Service 如果挂了,hwservicemanager 会自动清理。但客户端不会自动重连,需要自己实现重连逻辑。