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 注册监听器,接收热插拔、错误等异步事件。
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+ 多摄支持)。
4.4 接口调用流程与回调注册时序
下图展示了 Camera Service 通过 ICameraProvider 接口完成设备枚举和回调注册的典型时序:
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。
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 层,确保设备枚举、能力查询和热插拔事件处理的正确性与稳定性。