4. ICameraProvider接口定义:AIDL接口方法详解

ICameraProvider是Android Camera HAL中连接框架层(CameraService)与HAL实现的核心AIDL接口。它定义了CameraService如何发现、枚举和获取Camera设备接口。本章将深入剖析该接口的核心方法,包括getCameraIdList、getCameraDeviceInterface等,并分析其在HAL1兼容性调试中的关键作用。

调试要点:ICameraProvider接口的AIDL定义位于hardware/interfaces/camera/provider/2.4/ICameraProvider.aidl。在HAL1迁移至HAL3的过渡系统中,该接口的返回值直接影响上层应用的摄像头列表展示和设备打开行为。

4.1 接口架构总览

ICameraProvider接口采用服务端-客户端(Binder)模式,CameraService作为客户端调用Provider端的方法。以下SVG图展示了ICameraProvider在Camera HAL架构中的位置及其核心方法调用关系。

ICameraProvider 接口架构与核心方法调用关系 CameraService (客户端/调用方) ICameraProvider (AIDL 接口层) CameraProvider 实现(HAL端) 核心AIDL方法:getCameraIdList | getCameraDeviceInterface | setCallback | isSetTorchModeSupported getCameraIdList() 返回:String[] cameraIdList 作用:枚举所有可用Camera设备 HAL1兼容:返回ID格式需一致 getCameraDeviceInterface() 参数:String cameraId 返回:ICameraDevice 接口 HAL1兼容:返回ICameraDevice@1.0 setCallback() 参数:ICameraProviderCallback 作用:注册状态回调通知 用于热插拔通知 isSetTorchModeSupported() 返回:boolean 查询是否支持闪光灯模式设置 getConcurrentCameraIds() 返回:ConcurrentCameraIdCombination[] HAL1通常不支持,返回空列表

4.2 getCameraIdList() 方法详解

getCameraIdList()是CameraService启动后第一个调用的Provider方法,用于获取当前系统中所有可用的Camera设备ID列表。该方法的返回值直接影响上层应用能够看到的摄像头数量。

AIDL方法签名:
/**
 * 获取当前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不会注册任何设备
HAL1兼容性陷阱:在HAL1实现中,getCameraIdList()返回的ID必须与Camera.h中getCameraInfo返回的camera_info结构体中的device_id一致。如果Provider返回了"0"、"1",但底层HAL1库只识别"0",则打开"1"时会失败。调试时建议在Provider实现中打印日志,确认ID列表与HAL1库实际支持的设备匹配。

4.2.2 典型实现流程

  1. 初始化HAL1库:调用hw_get_module(CAMERA_HARDWARE_MODULE_ID, &module)获取HAL1模块。
  2. 获取摄像头数量:调用module->get_number_of_cameras()获取设备总数。
  3. 构建ID列表:遍历所有设备,将索引转换为字符串ID存入数组。
  4. 返回结果:通过Binder将String[]返回给CameraService。
HAL1兼容实现示例(C++):
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接口。

AIDL方法签名:
/**
 * 根据指定的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,需完全重写
调试技巧:在HAL1兼容性调试中,如果CameraService调用getCameraDeviceInterface("0")返回了null,请检查:① Provider中是否已正确初始化HAL1库;② cameraId是否在getCameraIdList()返回的列表中;③ HAL1的camera_device_open()是否成功返回。

4.3.2 典型实现流程

  1. 验证cameraId:检查传入的ID是否在getCameraIdList()返回的列表中。
  2. 打开HAL1设备:调用module->common.methods->open()打开对应ID的Camera设备。
  3. 创建ICameraDevice代理:将HAL1的camera_device_t封装为ICameraDevice@1.0实现。
  4. 返回接口:通过Binder将ICameraDevice接口返回给CameraService。
HAL1兼容实现示例(C++):
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端的状态变化通知,如摄像头热插拔事件。

AIDL方法签名:
/**
 * 注册回调接口,用于接收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通常不支持并发,返回空列表。

HAL1兼容性注意:如果Provider实现了HAL1兼容层,getConcurrentCameraIds()应返回空列表,否则CameraService可能会尝试并发打开多个HAL1设备,导致资源冲突或崩溃。

4.6 接口调用时序图

以下SVG图展示了CameraService通过ICameraProvider接口获取Camera设备接口的完整调用时序。

ICameraProvider 接口调用时序图 CameraService ICameraProvider HAL1实现 ① setCallback(callback) ② getCameraIdList() ③ 返回 ["0", "1"] ④ getCameraDeviceInterface("0") ⑤ module->common.methods->open() ⑥ 返回 ICameraDevice@1.0 ⑦ 通过ICameraDevice操作摄像头

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返回空列表
调试建议:在HAL1兼容性调试中,建议在Provider的每个AIDL方法入口和出口添加日志,记录参数和返回值。使用adb logcat -s CameraProvider过滤日志,可以快速定位接口调用失败的原因。