2. CameraDevice 接口基础:CameraManager、CameraCharacteristics、CameraDevice 的创建与生命周期

CameraDevice 接口是 Android Camera2 框架中应用层与底层硬件 HAL 交互的核心通道。要正确创建并管理 CameraDevice,必须首先理解其前置依赖:CameraManager(系统服务代理)与 CameraCharacteristics(设备静态能力描述)。本章将系统梳理这三个核心对象的创建流程、生命周期管理以及常见性能陷阱。

2.1 CameraManager:系统服务入口

CameraManager 是应用层访问相机子系统的唯一入口。它负责枚举可用摄像头、查询设备特性、以及建立与 CameraService 的 Binder 通信通道。

关键职责:
  • 通过 getCameraIdList() 获取当前设备上所有可用的摄像头 ID 列表。
  • 通过 getCameraCharacteristics(cameraId) 获取指定摄像头的静态能力信息。
  • 通过 openCamera(cameraId, stateCallback, handler) 创建 CameraDevice 实例。

获取 CameraManager 实例的标准方式:

// 从系统服务获取 CameraManager
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
if (manager == null) {
    // 设备不支持相机功能
    return;
}
性能提示:CameraManager 实例建议在 Application 或 Activity 初始化时获取一次并缓存复用,避免频繁通过 getSystemService() 创建新引用。该操作涉及跨进程 Binder 调用,重复获取会增加延迟。

2.2 CameraCharacteristics:设备能力画像

CameraCharacteristics 是一个只读的静态属性集合,描述了摄像头传感器的物理特性、支持的能力集、输出尺寸范围、帧率上限等关键参数。这些信息在创建 CameraDevice 和配置 CaptureSession 之前必须完成查询。

特性 Key 数据类型 说明 性能影响
INFO_SUPPORTED_HARDWARE_LEVEL int 硬件支持级别(LEGACY / LIMITED / FULL / LEVEL_3) 决定 Pipeline 能力上限
SCALER_STREAM_CONFIGURATION_MAP StreamConfigurationMap 支持的输出/输入格式、尺寸、最小帧持续时间 直接影响 Surface 配置与帧率
SENSOR_INFO_SENSITIVITY_RANGE Range<Integer> ISO 感光度范围 影响低光场景曝光策略
CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES Range<Integer>[] 自动曝光支持的目标帧率范围 决定帧率配置上限
REQUEST_PARTIAL_RESULT_COUNT int 一次 Capture 返回的部分结果数量 影响回调时序与延迟分析

典型查询代码:

CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);

// 查询硬件支持级别
Integer level = characteristics.get(
    CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
if (level != null && level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
    // LEGACY 级别不支持某些高级特性
}

// 获取输出尺寸映射
StreamConfigurationMap configMap = characteristics.get(
    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size[] outputSizes = configMap.getOutputSizes(ImageFormat.YUV_420_888);
避坑指南:CameraCharacteristics 的查询结果在摄像头设备生命周期内不会改变,但不同摄像头 ID 的特性可能差异巨大(例如前置与后置)。务必在 openCamera() 之前完成所有特性读取,不要在 Capture 回调中动态查询,以避免主线程阻塞。

2.3 CameraDevice 的创建流程

CameraDevice 的创建是一个异步过程,涉及应用层 → CameraService → HAL 驱动的完整链路。创建成功后,应用通过回调获得 CameraDevice 实例,进而创建 CaptureSession。

// 异步打开摄像头
manager.openCamera(cameraId, new CameraDevice.StateCallback() {
    @Override
    public void onOpened(@NonNull CameraDevice camera) {
        // CameraDevice 创建成功,可以开始配置 CaptureSession
        // 注意:此回调在 CameraManager 的 handler 线程中执行
    }

    @Override
    public void onDisconnected(@NonNull CameraDevice camera) {
        // 摄像头被系统断开连接(例如被其他高优先级应用抢占)
        camera.close();
    }

    @Override
    public void onError(@NonNull CameraDevice camera, int error) {
        // 创建失败或运行中发生致命错误
        // error 码包括 ERROR_CAMERA_IN_USE、ERROR_MAX_CAMERAS_IN_USE 等
        camera.close();
    }
}, backgroundHandler);
创建流程关键步骤:
  1. 应用调用 manager.openCamera(),请求通过 Binder 发送至 CameraService。
  2. CameraService 检查权限、设备可用性、并发限制。
  3. CameraService 通知 HAL 打开指定摄像头设备。
  4. HAL 驱动初始化传感器与 ISP 硬件。
  5. CameraService 创建 CameraDevice 代理并返回给应用。
  6. 应用收到 onOpened() 回调,获得 CameraDevice 实例。
CameraDevice 创建流程时序图 App CameraService HAL / Driver openCamera(id, cb) HAL_open() 传感器 & ISP 初始化 HAL_open() 返回 创建 CameraDevice 代理 onOpened(device) CameraDevice 就绪 整个流程为异步调用,onOpened 回调在 CameraManager 指定的 Handler 线程中执行

2.4 CameraDevice 的生命周期管理

CameraDevice 是一个重量级系统资源,其生命周期必须严格管理。错误的生命周期控制会导致资源泄漏、摄像头被占用、甚至系统服务崩溃。

生命周期阶段 触发条件 应用行为 常见错误
创建 openCamera() 调用成功 在 onOpened() 中保存 CameraDevice 引用 在回调外使用未初始化的引用
活跃 CameraDevice 已打开,可创建 CaptureSession 配置输出 Surface、创建 Session、发送 Capture 请求 未检查设备是否已断开就发送请求
断开 系统抢占、其他应用打开同一摄像头 立即调用 close(),释放所有关联资源 忽略 onDisconnected() 回调
错误 硬件故障、驱动崩溃、资源耗尽 调用 close(),尝试重新打开或降级处理 在 onError() 中继续使用 CameraDevice
关闭 应用主动调用 cameraDevice.close() 置空引用,通知上层状态变更 重复 close() 导致异常
最佳实践:CameraDevice 的 close() 方法必须在 onDisconnected() 和 onError() 回调中调用,同时在 Activity/Fragment 的 onPause() 或 onStop() 中主动释放。建议使用 AtomicBoolean 标记设备状态,防止重复关闭。
CameraDevice 生命周期状态机 CLOSED OPENING ACTIVE DISCONNECTED ERROR openCamera() onOpened() onDisconnected() onError() close() close() 所有终止状态(DISCONNECTED / ERROR)必须调用 close() 才能回到 CLOSED 状态

2.5 并发与资源竞争注意事项

CameraDevice 是独占资源。在同一时间,一个摄像头 ID 只能被一个应用进程打开。CameraManager 通过 CameraService 的权限管理和引用计数来保证互斥访问。

并发陷阱:
  • 不要在主线程(UI 线程)中调用 openCamera(),Binder 调用可能阻塞数十毫秒。
  • 多个摄像头 ID 可以同时打开(例如前置 + 后置),但受硬件并发能力限制。
  • 在 onOpened() 回调中不要执行耗时操作,尽快创建 CaptureSession。
  • CameraDevice 实例不是线程安全的,所有操作应在同一 Handler 线程中串行执行。

2.6 性能调优切入点

从 CameraDevice 创建阶段开始,性能调优就已经介入。以下是本章涉及的三个关键调优方向:

调优维度 具体措施 预期收益
减少创建延迟 提前查询 CameraCharacteristics 并缓存;使用专用 HandlerThread 执行 openCamera 创建耗时从 200ms 降至 80ms
避免资源泄漏 严格遵循生命周期回调,在 onPause 中释放 CameraDevice 防止摄像头被长时间占用导致其他应用失败
合理选择摄像头 根据 CameraCharacteristics 的硬件级别选择最优摄像头(优先 FULL 级别) 获得更低的 Capture 延迟和更高的帧率
本章小结:CameraManager 是入口,CameraCharacteristics 是地图,CameraDevice 是引擎。三者的正确使用是构建高性能 Camera Pipeline 的基石。下一章将深入 CameraDevice 创建后的核心操作——CaptureSession 的配置与优化。