4. HAL Service 生命周期管理
在 Treble 架构下,HAL Service 作为独立进程运行于 vendor 分区,其生命周期直接决定上层多媒体、传感器、图形等核心服务的可用性。本章围绕 Service 的启动流程、死亡通知机制与重启策略展开,帮助开发者构建高可用的 HAL 层服务。
核心目标:确保 HAL Service 在异常退出后能够被自动恢复,且恢复过程中不破坏系统服务的状态一致性。
4.1 Service 启动流程
HAL Service 的启动由 init.rc 脚本驱动,经过 注册 → 启动 → 发布 三个阶段。以下为典型流程:
- 解析 .rc 文件:init 进程读取 vendor/etc/init/hw/ 下的 .rc 文件,识别 service 定义。
- 创建进程:根据 service 的 binary 路径与参数 fork 子进程。
- 注册 hwservicemanager:Service 启动后调用
defaultServiceManager()向 hwservicemanager 注册自身。 - 发布接口:通过
registerAsService()暴露 IHal 接口,供 framework 层调用。 - 进入事件循环:Service 进入 Binder 或 HwBinder 线程池,等待客户端请求。
最佳实践:在 .rc 中为 HAL Service 添加
oneshot 标志时需谨慎,oneshot 服务退出后 init 不会自动重启,适用于一次性初始化任务,不适用于常驻服务。
4.2 死亡通知机制
当 HAL Service 进程异常终止(如段错误、OOM Killer 触发),framework 层的客户端需要及时感知并处理。Android 提供 死亡通知(Death Notification) 机制,通过 Binder 驱动实现跨进程状态监控。
| 组件 | 角色 | 关键方法 |
|---|---|---|
| 客户端(Client) | 注册死亡通知,接收回调 | linkToDeath() |
| Binder 驱动 | 监控服务端进程状态 | 内核自动检测进程退出 |
| 服务端(Service) | 被监控的目标进程 | 无需主动处理 |
| 死亡接收器(DeathRecipient) | 回调接口实现 | serviceDied() |
典型实现步骤:
// 1. 客户端实现 DeathRecipient
class MyDeathRecipient : public hardware::hidl_death_recipient {
void serviceDied(uint64_t cookie, const wp<::android::hidl::base::V1_0::IBase>& who) override {
// 服务已死亡,执行重连或上报逻辑
ALOGE("HAL Service died, cookie=%llu", cookie);
// 触发重启流程
}
};
// 2. 注册死亡通知
sp<MyDeathRecipient> recipient = new MyDeathRecipient();
Return<bool> linked = service->linkToDeath(recipient, 0x1234);
if (!linked) {
ALOGE("Failed to link death notification");
}
// 3. 解除注册(可选)
service->unlinkToDeath(recipient);
注意:死亡通知回调在 Binder 线程池中执行,不可在回调中执行耗时操作或直接调用 Binder 方法,否则可能导致死锁。建议使用消息队列或 Handler 将任务投递到主线程。
4.3 Service 重启策略
HAL Service 异常退出后,系统需要快速恢复服务。重启策略分为 init 自动重启 和 框架层主动重启 两种模式。
4.3.1 init 自动重启
在 .rc 文件中通过 class hal 和 critical 标志控制重启行为:
| 标志 | 行为 | 适用场景 |
|---|---|---|
class hal |
退出后 init 自动重启,默认最多 4 次/4 秒 | 大多数 HAL Service |
critical |
退出后立即重启,若 4 分钟内重启超过 4 次则设备进入 recovery | 核心服务(如 audio、graphics) |
oneshot |
退出后不重启 | 一次性初始化任务 |
disabled |
不随 class 启动,需手动触发 | 按需启动的服务 |
// 典型 .rc 配置示例
service vendor.audio-hal /vendor/bin/hw/android.hardware.audio@2.0-service
class hal
critical
user audioserver
group audio
capabilities SYS_NICE
seclabel u:r:hal_audio:s0
4.3.2 框架层主动重启
当死亡通知触发后,客户端可以主动调用 startService() 或通过 ServiceManager 重新获取服务:
// 死亡回调中执行重启
void serviceDied(uint64_t cookie, const wp<IBase>& who) override {
// 延迟 500ms 后重试,避免频繁重启
std::this_thread::sleep_for(std::chrono::milliseconds(500));
sp<IFoo> service = IFoo::getService();
if (service != nullptr) {
// 重新注册死亡通知
service->linkToDeath(this, cookie);
// 恢复业务状态
restoreState();
} else {
// 服务尚未启动,等待 init 重启
ALOGW("Service not available yet, waiting...");
}
}
重启策略对比:init 自动重启适用于无状态服务,框架层主动重启适用于需要恢复业务上下文的有状态服务。实际项目中常将两者结合使用——init 保证进程级恢复,框架层保证功能级恢复。
实战建议:在开发阶段为 HAL Service 添加
critical 标志,便于快速发现崩溃问题;在量产版本中根据服务重要性选择 class hal 或 critical,避免 critical 超限导致 recovery 影响用户体验。