4. ICameraProvider接口定义:AIDL接口方法详解
ICameraProvider是Android Camera HAL中连接框架层(CameraService)与HAL实现的核心AIDL接口。它定义了CameraService如何发现、枚举和获取Camera设备接口。本章将深入剖析该接口的核心方法,包括getCameraIdList、getCameraDeviceInterface等,并分析其在HAL1兼容性调试中的关键作用。
hardware/interfaces/camera/provider/2.4/ICameraProvider.aidl。在HAL1迁移至HAL3的过渡系统中,该接口的返回值直接影响上层应用的摄像头列表展示和设备打开行为。
4.1 接口架构总览
ICameraProvider接口采用服务端-客户端(Binder)模式,CameraService作为客户端调用Provider端的方法。以下SVG图展示了ICameraProvider在Camera HAL架构中的位置及其核心方法调用关系。
4.2 getCameraIdList() 方法详解
getCameraIdList()是CameraService启动后第一个调用的Provider方法,用于获取当前系统中所有可用的Camera设备ID列表。该方法的返回值直接影响上层应用能够看到的摄像头数量。
/**
* 获取当前CameraProvider支持的所有Camera设备ID列表。
* 返回的ID必须与getCameraDeviceInterface()中使用的ID一致。
*/
String[] getCameraIdList();
4.2.1 返回值规范与HAL1兼容性
| 场景 | 返回值示例 | 说明 |
|---|---|---|
| 单后置摄像头(HAL1) | ["0"] |
传统单摄像头设备,ID固定为"0" |
| 前后双摄(HAL1) | ["0", "1"] |
后置为"0",前置为"1" |
| 多摄像头(HAL3) | ["0", "1", "2", "3"] |
ID按物理Camera序号分配 |
| 逻辑摄像头(HAL3) | ["0", "1", "logical_back"] |
逻辑摄像头ID可包含字母 |
| 无摄像头设备 | [] |
返回空数组,CameraService不会注册任何设备 |
getCameraIdList()返回的ID必须与Camera.h中getCameraInfo返回的camera_info结构体中的device_id一致。如果Provider返回了"0"、"1",但底层HAL1库只识别"0",则打开"1"时会失败。调试时建议在Provider实现中打印日志,确认ID列表与HAL1库实际支持的设备匹配。
4.2.2 典型实现流程
- 初始化HAL1库:调用
hw_get_module(CAMERA_HARDWARE_MODULE_ID, &module)获取HAL1模块。 - 获取摄像头数量:调用
module->get_number_of_cameras()获取设备总数。 - 构建ID列表:遍历所有设备,将索引转换为字符串ID存入数组。
- 返回结果:通过Binder将
String[]返回给CameraService。
Status CameraProvider::getCameraIdList(
std::vector<std::string>* cameraIds) {
// 1. 获取HAL1模块
const camera_module_t* module;
int ret = hw_get_module(CAMERA_HARDWARE_MODULE_ID,
(const hw_module_t**)&module);
if (ret != 0) {
ALOGE("Failed to get camera module: %d", ret);
return Status::fromServiceSpecificError(ret);
}
// 2. 获取摄像头数量
int numCameras = module->get_number_of_cameras();
ALOGI("HAL1 reports %d cameras", numCameras);
// 3. 构建ID列表
cameraIds->clear();
for (int i = 0; i < numCameras; i++) {
cameraIds->push_back(std::to_string(i));
}
// 4. 调试日志:确认ID与HAL1库匹配
for (const auto& id : *cameraIds) {
ALOGI("Camera ID: %s", id.c_str());
}
return Status::ok();
}
4.3 getCameraDeviceInterface() 方法详解
getCameraDeviceInterface()是ICameraProvider中用于获取具体Camera设备操作接口的核心方法。CameraService在打开摄像头时调用此方法,传入目标Camera ID,获取对应的ICameraDevice接口。
/**
* 根据指定的cameraId获取对应的Camera设备接口。
* 返回的ICameraDevice可以是@1.0或@2.0版本。
* 如果cameraId无效,返回null。
*/
ICameraDevice getCameraDeviceInterface(String cameraId);
4.3.1 返回值类型与版本选择
| 返回接口版本 | 适用场景 | HAL1兼容性 |
|---|---|---|
ICameraDevice@1.0 |
HAL1设备、传统Camera实现 | 直接兼容,无需转换 |
ICameraDevice@2.0 |
HAL3设备、新版Camera实现 | 需要HAL1-to-HAL3适配层 |
ICameraDevice@3.0+ |
HAL3+设备、高级特性支持 | 不兼容HAL1,需完全重写 |
getCameraDeviceInterface("0")返回了null,请检查:① Provider中是否已正确初始化HAL1库;② cameraId是否在getCameraIdList()返回的列表中;③ HAL1的camera_device_open()是否成功返回。
4.3.2 典型实现流程
- 验证cameraId:检查传入的ID是否在
getCameraIdList()返回的列表中。 - 打开HAL1设备:调用
module->common.methods->open()打开对应ID的Camera设备。 - 创建ICameraDevice代理:将HAL1的
camera_device_t封装为ICameraDevice@1.0实现。 - 返回接口:通过Binder将ICameraDevice接口返回给CameraService。
Status CameraProvider::getCameraDeviceInterface(
const std::string& cameraId,
sp<ICameraDevice>* device) {
// 1. 验证cameraId
auto it = std::find(mCameraIds.begin(), mCameraIds.end(), cameraId);
if (it == mCameraIds.end()) {
ALOGE("Invalid camera ID: %s", cameraId.c_str());
*device = nullptr;
return Status::fromServiceSpecificError(-ENODEV);
}
// 2. 打开HAL1设备
int id = std::stoi(cameraId);
hw_device_t* hwDevice = nullptr;
int ret = mModule->common.methods->open(
&mModule->common, cameraId.c_str(), &hwDevice);
if (ret != 0) {
ALOGE("Failed to open camera %s: %d", cameraId.c_str(), ret);
*device = nullptr;
return Status::fromServiceSpecificError(ret);
}
// 3. 创建ICameraDevice@1.0代理
camera_device_t* cameraDevice =
reinterpret_cast<camera_device_t*>(hwDevice);
*device = new CameraDeviceHAL1(cameraDevice, id);
ALOGI("Opened camera %s successfully", cameraId.c_str());
return Status::ok();
}
4.4 setCallback() 与状态通知机制
setCallback()方法允许CameraService注册一个ICameraProviderCallback回调接口,用于接收Provider端的状态变化通知,如摄像头热插拔事件。
/**
* 注册回调接口,用于接收Provider状态变化通知。
* 如果callback为null,则取消之前的注册。
*/
void setCallback(ICameraProviderCallback callback);
4.4.1 ICameraProviderCallback 接口
| 回调方法 | 触发时机 | HAL1兼容性 |
|---|---|---|
onCameraDeviceStatusChange() |
Camera设备状态发生变化(如打开/关闭) | HAL1通常不支持,需手动模拟 |
onTorchModeStatusChange() |
闪光灯模式状态变化 | HAL1通过set_torch_mode()触发 |
onCameraDeviceError() |
Camera设备发生致命错误 | HAL1通过camera_device_ops_t错误回调 |
4.5 其他辅助方法
4.5.1 isSetTorchModeSupported()
查询Provider是否支持设置闪光灯模式。在HAL1中,此方法通常返回true,因为HAL1的camera_module_t提供了set_torch_mode()接口。
4.5.2 getConcurrentCameraIds()
获取支持并发使用的Camera设备ID组合。此方法在HAL3+中引入,HAL1通常不支持并发,返回空列表。
getConcurrentCameraIds()应返回空列表,否则CameraService可能会尝试并发打开多个HAL1设备,导致资源冲突或崩溃。
4.6 接口调用时序图
以下SVG图展示了CameraService通过ICameraProvider接口获取Camera设备接口的完整调用时序。
4.7 常见调试问题与解决方案
| 问题现象 | 可能原因 | 调试方法 |
|---|---|---|
| getCameraIdList返回空列表 | HAL1模块加载失败或get_number_of_cameras返回0 | 检查hw_get_module返回值,确认HAL1库路径正确 |
| getCameraDeviceInterface返回null | cameraId无效或HAL1 open失败 | 在Provider中打印cameraId和open返回值,检查权限 |
| setCallback后未收到通知 | 回调接口未正确注册或HAL1不支持状态变化 | 确认callback非空,在Provider中手动触发测试 |
| 并发打开摄像头失败 | HAL1不支持并发,getConcurrentCameraIds返回了非空列表 | 确保getConcurrentCameraIds返回空列表 |
adb logcat -s CameraProvider过滤日志,可以快速定位接口调用失败的原因。