3. ICameraProvider 接口定义:核心方法解析
ICameraProvider 是 Android Camera HAL 中连接 Framework 与底层硬件服务的核心接口。它定义在 hardware/interfaces/camera/provider/2.4/ICameraProvider.hal(及更高版本)中,是 CameraProvider 进程必须实现的主干接口。本章将深入解析其最关键的三个方法:getCameraIdList、getCameraDeviceInterface 和 setCallback,并分析它们在初始化流程中的调用时序与实现要点。
3.1 接口总览与调用关系
在 CameraProvider 初始化完成后,CameraService 会通过 HwBinder 获取到 ICameraProvider 的代理对象,并依次调用以下核心方法:
| 方法名 | 调用时机 | 返回值 | 核心职责 |
|---|---|---|---|
getCameraIdList |
Provider 注册后立即调用 | Status + vec<string> |
返回当前 Provider 管理的所有 Camera ID 列表 |
getCameraDeviceInterface |
对每个 Camera ID 依次调用 | Status + ICameraDevice |
为指定 Camera ID 创建设备接口对象 |
setCallback |
Provider 注册后、getCameraIdList 之前 | Status |
注册 ICameraProviderCallback,用于上报热插拔等事件 |
isSetTorchModeSupported |
可选,在初始化后期 | Status + bool |
查询是否支持闪光灯手电筒模式 |
下图展示了 CameraService 与 ICameraProvider 之间的典型调用时序:
3.2 getCameraIdList 方法详解
getCameraIdList 是 CameraService 获取可用 Camera 设备列表的入口。其方法签名如下:
// ICameraProvider.hal (2.4)
getCameraIdList() generates (Status status, vec<string> cameraIdList);
实现要点:
- 返回稳定的 ID 列表:每次调用应返回相同的 ID 集合(除非发生热插拔)。ID 通常为
"0"、"1"等字符串,或物理 Camera 的 unique identifier。 - ID 与设备类型对应:每个 ID 必须能唯一映射到一个
CameraDevice实例。对于逻辑多摄像头(Logical Multi-Camera),ID 对应逻辑 Camera,物理 Camera 通过getPhysicalCameraIds另行查询。 - 空列表处理:如果 Provider 当前没有可用 Camera(例如 USB Camera 未插入),应返回空列表而非错误。CameraService 会据此判断设备状态。
- 线程安全:该方法可能被多个线程同时调用,实现中需加锁保护内部设备列表。
典型实现示例(C++ 伪代码):
Return<void> CameraProvider::getCameraIdList(
getCameraIdList_cb _hidl_cb) {
std::vector<std::string> idList;
{
std::lock_guard<std::mutex> lock(mLock);
for (const auto& [id, device] : mCameraDevices) {
idList.push_back(id);
}
}
_hidl_cb(Status::OK, idList);
return Void();
}
3.3 getCameraDeviceInterface 方法详解
该方法为指定的 Camera ID 创建并返回一个 ICameraDevice 接口对象。CameraService 会为每个 ID 调用一次此方法,以获取设备操作句柄。
// ICameraProvider.hal (2.4)
getCameraDeviceInterface(string cameraId)
generates (Status status, ICameraDevice device);
实现要点:
| 场景 | 返回值 | 说明 |
|---|---|---|
| cameraId 有效且设备可用 | Status::OK + ICameraDevice |
创建新的 ICameraDevice 实例并返回 |
| cameraId 不存在 | Status::ILLEGAL_ARGUMENT |
返回错误,CameraService 会记录日志并跳过 |
| 设备已被占用或初始化失败 | Status::INTERNAL_ERROR |
返回错误,CameraService 会尝试重新初始化 |
| 设备已断开(热插拔后) | Status::CAMERA_STATUS_NOT_PRESENT |
通知 CameraService 该设备已不存在 |
关键实现细节:
- 延迟创建:不要在此方法中执行耗时的硬件初始化(如打开 Sensor)。真正的初始化应推迟到
ICameraDevice::open()调用时进行。 - 唯一实例:每个 Camera ID 通常只创建一个
ICameraDevice实例。如果 CameraService 重复调用,应返回相同的对象或创建新的独立实例(取决于设计)。 - 生命周期管理:返回的
ICameraDevice对象由 CameraService 持有引用。Provider 需确保在设备断开时能正确释放资源。
下图展示了 getCameraDeviceInterface 的内部处理流程:
3.4 setCallback 方法详解
setCallback 用于向 Provider 注册一个 ICameraProviderCallback 回调接口。CameraService 通过此回调接收 Provider 上报的异步事件,如 Camera 热插拔、Torch 状态变化等。
// ICameraProvider.hal (2.4)
setCallback(ICameraProviderCallback callback)
generates (Status status);
实现要点:
- 单回调设计:通常只允许注册一个回调。如果重复调用,应替换旧回调或返回错误。
- 保存回调引用:Provider 必须持有回调的强引用(
sp<ICameraProviderCallback>),以便在事件发生时调用。 - 热插拔事件:当 Camera 设备插入或拔出时,通过
onCameraDeviceStatusChange方法通知 CameraService。 - 初始化完成通知:某些实现中,Provider 初始化完成后会通过回调通知 CameraService 可以开始查询设备列表。
回调接口定义(简化):
// ICameraProviderCallback.hal
interface ICameraProviderCallback {
// 设备状态变化:CAMERA_STATUS_PRESENT / NOT_PRESENT / ENUMERATING
onCameraDeviceStatusChange(
string cameraId,
CameraDeviceStatus newStatus);
// Torch 模式状态变化
onTorchModeStatusChange(
string cameraId,
TorchModeStatus newStatus);
};
3.5 方法间的依赖关系与初始化顺序
三个核心方法之间存在严格的调用顺序依赖,违反顺序会导致初始化失败或状态不一致:
- setCallback → 必须先调用,建立事件上报通道。
- getCameraIdList → 获取当前设备列表。
- getCameraDeviceInterface → 为每个 ID 创建设备接口。
下表总结了违反顺序的后果:
| 违反场景 | 后果 | 严重程度 |
|---|---|---|
| getCameraIdList 在 setCallback 之前 | 热插拔事件丢失,设备状态不一致 | 高 |
| getCameraDeviceInterface 在 getCameraIdList 之前 | CameraService 无法验证 ID 有效性,可能崩溃 | 高 |
| 重复调用 setCallback | 旧回调被覆盖,之前注册的监听者失效 | 中 |
| getCameraIdList 返回空列表后调用 getDeviceInterface | CameraService 不会调用,无影响 | 低 |
ALOGD("[Provider] getCameraIdList: returning %zu cameras", idList.size());
3.6 扩展方法:isSetTorchModeSupported 与 notifyDeviceStateChange
除了上述三个核心方法,ICameraProvider 还定义了以下辅助方法:
- isSetTorchModeSupported:查询 Provider 是否支持通过
setTorchMode控制闪光灯。返回true表示支持,CameraService 会允许应用调用 Torch API。 - notifyDeviceStateChange:通知 Provider 系统状态变化(如折叠状态、显示状态),Provider 可据此调整 Camera 行为(如禁用某些物理 Camera)。
这些方法在初始化阶段不是必须调用的,但实现时建议提供合理的默认行为。例如,如果不支持 Torch,isSetTorchModeSupported 应返回 false。