4、ICameraProvider接口:核心接口方法与回调定义

ICameraProvider 是 Camera HAL 框架中 Provider 层的核心接口,它定义了 HAL 实现必须暴露给 Camera Service 的一组标准方法。通过该接口,Camera Service 能够发现设备、查询能力、管理会话,并监听底层硬件变化。本章将深入剖析 ICameraProvider 的核心方法签名、参数语义以及回调机制。

4.1 接口定位与职责

ICameraProvider 位于 hardware/interfaces/camera/provider/ 路径下,以 HIDL / AIDL 接口定义。其核心职责包括:

  • 设备枚举:返回当前可用的 Camera 设备标识符列表。
  • 设备能力查询:返回指定设备的静态能力元数据(如分辨率、帧率、AE/AWB 范围)。
  • 设备打开/关闭:创建或销毁 CameraDevice 会话。
  • 回调注册:允许 Service 注册监听器,接收热插拔、错误等异步事件。
关键设计原则: ICameraProvider 采用“一次查询、多次使用”模式。设备列表和静态能力在枚举阶段一次性获取,运行时只通过回调通知变化,避免频繁 IPC 开销。

4.2 核心方法定义

以下表格列出了 ICameraProvider 接口中最关键的 6 个方法,包括其输入参数、返回值及典型用途:

方法名 输入参数 返回值 用途说明
getCameraIdList 无 Status + hidl_vec<string> 返回当前所有可用 Camera 设备的唯一标识符列表
getCameraCharacteristics string cameraId Status + V1_0::CameraMetadata 返回指定设备的静态能力元数据(ANDROID.* 键值对)
getPhysicalCameraIdList string cameraId Status + hidl_vec<string> 返回逻辑相机包含的物理相机 ID 列表(多摄场景)
open string cameraId, sp<ICameraDeviceCallback> Status + sp<ICameraDevice> 打开指定 Camera 设备,返回设备操作接口
setCallback sp<ICameraProviderCallback> Status 注册 Provider 级回调,用于接收热插拔/状态变化通知
isTorchModeSupported string cameraId Status + bool 查询指定设备是否支持闪光灯常亮模式

4.3 回调接口:ICameraProviderCallback

ICameraProviderCallback 是 Provider 向 Service 发送异步事件的标准通道。其定义通常包含以下回调方法:

  • onCameraDeviceStatusChange(in string cameraId, in CameraDeviceStatus newStatus):当设备状态发生变化时触发,例如从 PRESENT 变为 NOT_PRESENT(热插拔)。
  • onTorchModeStatusChange(in string cameraId, in TorchModeStatus newStatus):当闪光灯模式状态变化时触发,例如从 AVAILABLE_OFF 变为 AVAILABLE_ON。
  • onPhysicalCameraDeviceStatusChange(in string cameraId, in string physicalCameraId, in CameraDeviceStatus newStatus):物理相机子设备状态变化回调(Android 11+ 多摄支持)。
实现提示: 回调方法必须是非阻塞的。HAL 实现应在独立的线程池中分发回调,避免阻塞 Provider 的主事务线程。Service 端收到回调后,会触发设备列表重新枚举或能力缓存刷新。

4.4 接口调用流程与回调注册时序

下图展示了 Camera Service 通过 ICameraProvider 接口完成设备枚举和回调注册的典型时序:

ICameraProvider 接口调用与回调注册时序 Camera Service ICameraProvider HAL Provider 1. setCallback(cb) 转发回调注册 2. getCameraIdList() 查询底层设备 返回 ID 列表 返回 Status + ID[] 3. getCharacteristics(id) 读取静态元数据 返回 CameraMetadata 4. onCameraDeviceStatusChange(id, NOT_PRESENT) 通知 Service 设备移除 说明: 回调注册必须在设备枚举之前完成,否则可能丢失热插拔事件。HAL 实现应保证回调线程安全。

4.5 方法参数与返回值详解

4.5.1 getCameraIdList

该方法无输入参数,返回一个字符串列表。每个字符串对应一个 Camera 设备的唯一 ID。在 Android 多摄架构中,逻辑相机和物理相机都会出现在该列表中。典型返回值示例:

// 单摄设备
["0"]

// 双摄设备(逻辑 + 物理)
["0", "1", "external/0"]

// 三摄设备(含外接 USB 相机)
["0", "1", "2", "external/0", "external/1"]

4.5.2 getCameraCharacteristics

输入参数为 Camera ID,返回 CameraMetadata 结构体。该结构体包含 ANDROID.* 命名空间下的键值对,例如:

// 关键元数据字段示例
ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE = (4032, 3024)
ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE = (4032, 3024)
ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES = [(15, 30), (30, 30)]
ANDROID_REQUEST_PARTIAL_RESULT_COUNT = 1
ANDROID_STATISTICS_INFO_MAX_FACE_COUNT = 10

4.5.3 open 方法

打开设备时,Service 传入 Camera ID 和一个 ICameraDeviceCallback 回调对象。HAL 实现返回 ICameraDevice 接口,用于后续的捕获请求、流配置等操作。如果设备已被占用或硬件故障,返回 Status::CAMERA_IN_USE 或 Status::INTERNAL_ERROR。

常见错误: 某些 HAL 实现在 open 方法中执行了耗时初始化(如 ISP 加载),导致 Service 超时。建议将耗时操作推迟到第一个捕获请求时执行,或使用异步初始化模式。

4.6 回调机制与线程模型

ICameraProviderCallback 的回调方法由 HAL 实现主动调用,Service 被动接收。为保证系统稳定性,回调机制需遵循以下规则:

规则 说明 违反后果
非阻塞 回调方法内不能执行耗时操作(如文件 I/O、加锁等待) 导致 Provider 线程阻塞,影响其他设备操作
线程安全 多个回调可能从不同线程同时调用,需保证内部状态一致性 数据竞争导致设备状态不一致或崩溃
顺序保证 同一设备的状态变化回调应按发生顺序到达 Service 端设备列表出现中间态错误
去重处理 连续发送相同状态的回调应被 HAL 过滤 Service 端不必要的枚举刷新,增加功耗

4.7 接口版本演进

ICameraProvider 接口随 Android 版本演进不断增加新方法。以下表格总结了主要版本的关键变化:

Android 版本 接口版本 新增方法/回调 说明
8.0 (O) HIDL 1.0 基础方法集 首次引入 Treble 架构,定义核心枚举/打开/回调
9.0 (P) HIDL 2.0 isTorchModeSupported 增加闪光灯模式查询,支持外部相机热插拔
10.0 (Q) HIDL 3.0 getPhysicalCameraIdList 支持多摄物理子设备枚举
11.0 (R) HIDL 3.1 onPhysicalCameraDeviceStatusChange 物理相机独立状态回调,支持更精细的热插拔管理
13.0 (T) AIDL 稳定版 接口迁移至 AIDL 统一使用 AIDL 接口定义,提升跨进程性能

4.8 接口实现示例(HIDL 片段)

以下是一个简化的 HAL 实现片段,展示如何实现 getCameraIdList 和 setCallback:

// CameraProvider.cpp 片段
Return<Status> CameraProvider::getCameraIdList(
    hidl_vec<hidl_string> *_aidl_return) {
    // 从底层硬件驱动获取设备列表
    std::vector<std::string> ids = mDeviceManager->enumerateDevices();
    *_aidl_return = hidl_vec<hidl_string>(ids.begin(), ids.end());
    return Status::OK;
}

Return<Status> CameraProvider::setCallback(
    const sp<ICameraProviderCallback>& callback) {
    // 保存回调引用,用于后续事件通知
    {
        std::lock_guard<std::mutex> lock(mCallbackLock);
        mCallback = callback;
    }
    // 注册底层热插拔监听
    mDeviceManager->registerHotplugListener(
        [this](const std::string& id, bool connected) {
            sp<ICameraProviderCallback> cb;
            {
                std::lock_guard<std::mutex> lock(mCallbackLock);
                cb = mCallback;
            }
            if (cb != nullptr) {
                CameraDeviceStatus status = connected ?
                    CameraDeviceStatus::PRESENT :
                    CameraDeviceStatus::NOT_PRESENT;
                cb->onCameraDeviceStatusChange(id, status);
            }
        });
    return Status::OK;
}
最佳实践: 在 setCallback 实现中,建议先保存回调引用,再注册底层监听。这样可以避免在注册过程中丢失设备状态变化事件。同时,回调调用应放在独立的线程池中,防止阻塞 Provider 的主事务线程。

4.9 接口调用常见问题排查

  • getCameraIdList 返回空列表:检查 HAL 实现是否正确初始化底层驱动,以及设备节点权限是否正确。
  • setCallback 后收不到回调:确认回调对象是否被正确序列化传递,以及 HAL 实现是否在独立线程中调用回调。
  • open 返回 CAMERA_IN_USE:检查设备是否已被其他进程打开,或 HAL 实现中是否存在资源泄漏。
  • getCameraCharacteristics 返回空元数据:确认 HAL 实现是否正确填充了 ANDROID.* 键值对,以及元数据大小是否超过 IPC 传输限制。

通过深入理解 ICameraProvider 接口的方法定义和回调机制,开发者可以更高效地实现符合 Android 兼容性要求的 Camera HAL Provider 层,确保设备枚举、能力查询和热插拔事件处理的正确性与稳定性。