4. HAL Service 生命周期管理

在 Treble 架构下,HAL Service 作为独立进程运行于 vendor 分区,其生命周期直接决定上层多媒体、传感器、图形等核心服务的可用性。本章围绕 Service 的启动流程、死亡通知机制与重启策略展开,帮助开发者构建高可用的 HAL 层服务。

核心目标:确保 HAL Service 在异常退出后能够被自动恢复,且恢复过程中不破坏系统服务的状态一致性。

4.1 Service 启动流程

HAL Service 的启动由 init.rc 脚本驱动,经过 注册 → 启动 → 发布 三个阶段。以下为典型流程:

  1. 解析 .rc 文件:init 进程读取 vendor/etc/init/hw/ 下的 .rc 文件,识别 service 定义。
  2. 创建进程:根据 service 的 binary 路径与参数 fork 子进程。
  3. 注册 hwservicemanager:Service 启动后调用 defaultServiceManager() 向 hwservicemanager 注册自身。
  4. 发布接口:通过 registerAsService() 暴露 IHal 接口,供 framework 层调用。
  5. 进入事件循环:Service 进入 Binder 或 HwBinder 线程池,等待客户端请求。
HAL Service 启动流程 init 解析 .rc fork 子进程 注册 hwservicemanager 发布接口 事件循环 关键点: • .rc 中必须指定 class 为 hal,否则 init 不会自动重启。 • 注册 hwservicemanager 失败会导致 Service 无法被发现,需检查 SELinux 权限。
最佳实践:在 .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 将任务投递到主线程。
死亡通知机制交互流程 客户端 (Client) Binder 驱动 HAL Service linkToDeath() Binder 通信 进程退出 serviceDied() 回调 机制要点: • 死亡通知由 Binder 驱动主动推送,无需客户端轮询。 • 每个客户端可注册多个死亡接收器,cookie 用于区分不同服务实例。

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 异常退出 init 自动重启 框架层主动重启 设备进入 recovery class hal 死亡通知 critical 超限 • 推荐组合:critical 保证进程级恢复 + 死亡通知回调恢复业务状态。 • 避免在死亡回调中直接调用 Binder 方法,防止死锁。
实战建议:在开发阶段为 HAL Service 添加 critical 标志,便于快速发现崩溃问题;在量产版本中根据服务重要性选择 class hal 或 critical,避免 critical 超限导致 recovery 影响用户体验。