4. Camera Provider 服务:HIDL 服务启动流程、ICameraProvider 接口实现、CameraService 与 HAL 的绑定机制

Camera Provider 是 Android Camera HAL3 架构中连接 Framework 与底层硬件驱动的核心桥梁。它作为独立进程运行,通过 HIDL(HAL Interface Definition Language)接口向 CameraService 提供设备枚举、打开、流配置等能力。本章深入剖析 Provider 服务的启动生命周期、ICameraProvider 接口的实现要点,以及 CameraService 与 HAL 之间的绑定握手过程。

4.1 HIDL 服务启动流程

Camera Provider 进程的启动由 init.rc 脚本触发,经过 HIDL 服务注册、Transport 层初始化、设备发现三个阶段,最终对外暴露服务。

阶段 关键动作 涉及组件
1. 进程启动 init 解析 android.hardware.camera.provider@2.x-service.rc,fork 出 provider 进程 init、servicemanager
2. HIDL 注册 调用 defaultPassthroughServiceImplementation() 或显式 registerAsService() libhidlbase、hwservicemanager
3. 设备枚举 实现 ICameraProvider::getCameraIdList(),扫描底层驱动节点 CameraModule、V4L2 / MIPI 驱动
移植要点: 在 Android 12+ 中,Camera Provider 必须使用 Passthrough 模式注册,否则 CameraService 无法通过 getService() 发现 Provider。检查 manifest.xml 中是否声明了正确的 fqName 和 version。
Camera Provider HIDL 服务启动流程 init.rc 启动 Provider HIDL Transport 初始化 registerAsService() getCameraIdList() Provider 服务就绪 关键检查点 manifest.xml 声明 + SELinux 权限

4.2 ICameraProvider 接口实现

ICameraProvider 是 HIDL 定义的核心接口,Provider 必须实现以下关键方法:

  • getCameraIdList():返回当前设备上所有可用的 Camera ID 列表(字符串数组)。
  • getCameraDeviceInterface():根据 Camera ID 返回对应的 ICameraDevice HIDL 接口实例。
  • setCallback():注册 ICameraProviderCallback,用于通知 CameraService 设备热插拔事件。
  • getVendorTags():返回厂商自定义的元数据标签描述。
实现建议: 在 getCameraDeviceInterface() 中,建议使用 懒加载 策略——只有首次请求时才打开 HAL 模块,避免 Provider 启动时占用过多资源。
// ICameraProvider 核心方法实现示例(C++)
Return<Status> CameraProvider::getCameraIdList(
    hidl_vec<hidl_string> *_aidl_return) {
    std::vector<std::string> camera_ids;
    // 扫描 /dev/video* 或读取 camera_module 配置
    for (int i = 0; i < mModule->getNumberOfCameras(); i++) {
        camera_ids.push_back(std::to_string(i));
    }
    *_aidl_return = camera_ids;
    return Status::OK;
}

Return<Status> CameraProvider::getCameraDeviceInterface(
    const hidl_string& cameraId,
    sp<ICameraDevice>* device) {
    // 根据 cameraId 创建对应的 CameraDevice HIDL 对象
    *device = new CameraDevice(cameraId, mModule);
    return Status::OK;
}

4.3 CameraService 与 HAL 的绑定机制

CameraService 作为系统服务运行在 cameraserver 进程中,通过 HIDL 的 服务发现 机制与 Camera Provider 建立绑定。绑定过程分为以下步骤:

  1. 服务查询: CameraService 调用 ICameraProvider::getService(),hwservicemanager 根据 fqName 返回对应的 Provider Binder 对象。
  2. 版本协商: 通过 getInterfaceVersion() 确认 Provider 实现的 HIDL 版本(如 2.4、2.5)。
  3. 回调注册: CameraService 实现 ICameraProviderCallback 并调用 setCallback() 注册到 Provider。
  4. 设备枚举: 调用 getCameraIdList() 获取可用 Camera 列表,随后逐个调用 getCameraDeviceInterface() 获取设备接口。
步骤 调用方 HIDL 方法 返回/回调
1 CameraService ICameraProvider::getService() Provider Binder 对象
2 CameraService getInterfaceVersion() uint32_t 版本号
3 CameraService setCallback(callback) Status::OK
4 CameraService getCameraIdList() hidl_vec<hidl_string>
5 CameraService getCameraDeviceInterface(id) sp<ICameraDevice>
CameraService 与 HAL 绑定时序 CameraService hwservicemanager Camera Provider getService() 返回 Binder setCallback() getCameraIdList() 返回 Camera ID 列表 getCameraDeviceInterface(id) 返回 ICameraDevice 绑定完成后,CameraService 通过 ICameraDevice 接口直接与 HAL 交互,Provider 不再介入数据通路
常见绑定失败原因:
  • SELinux 策略缺失: Provider 进程没有 hwservice_manager 的 find 权限,导致 getService() 返回 null。
  • manifest.xml 版本不匹配: Provider 注册的版本与 CameraService 请求的版本不一致,导致类型转换失败。
  • Transport 层崩溃: 如果 Provider 进程在注册后立即 crash,hwservicemanager 会移除服务注册,CameraService 无法绑定。

4.4 热插拔与回调机制

Camera Provider 通过 ICameraProviderCallback 接口向 CameraService 通知设备状态变化。当物理 Camera 被插入或拔出时,Provider 调用 cameraDeviceStatusChange() 或 physicalCameraDeviceStatusChange() 方法,CameraService 据此更新内部设备列表并通知上层应用。

// Provider 端通知热插拔事件
void CameraProvider::onCameraPluggedIn(const std::string& cameraId) {
    if (mCallback != nullptr) {
        mCallback->cameraDeviceStatusChange(
            cameraId,
            CameraDeviceStatus::PRESENT);
    }
}

void CameraProvider::onCameraUnplugged(const std::string& cameraId) {
    if (mCallback != nullptr) {
        mCallback->cameraDeviceStatusChange(
            cameraId,
            CameraDeviceStatus::NOT_PRESENT);
    }
}
移植调试技巧: 在 Provider 启动日志中增加 ALOGI 输出 getCameraIdList() 返回的 ID 数量和 setCallback() 的调用状态。使用 lshal 命令验证 Provider 是否成功注册:adb shell lshal | grep camera.provider。