4. Camera HAL 初始化流程:HAL 模块加载、open() 调用链、CameraDevice 初始化、Session 创建

Camera HAL 的初始化是相机框架启动的第一个关键阶段,它决定了上层应用能否成功获取相机服务并开始预览或拍照。本章深入剖析从 HAL 模块加载到 Session 创建的完整调用链,帮助开发者精准定位初始化阶段的各类异常。

4.1 HAL 模块加载机制

Android 相机框架通过 HAL_MODULE_INFO_SYM 符号加载 HAL 实现库。该过程由 CameraService 在启动时触发,核心步骤如下:

  1. 动态库加载:dlopen() 打开 camera.<variant>.so 库文件。
  2. 符号查找:dlsym() 获取 HAL_MODULE_INFO_SYM 结构体指针。
  3. 模块验证:检查 hal_module_info.common.module_api_version 和 hal_module_info.common.hal_api_version。
  4. HAL 版本协商:根据 common.module_api_version 决定使用 Camera HAL v1、v3 或 v3.x+。
调试要点:模块加载失败时,优先检查 logcat 中的 dlopen 错误信息。常见原因包括:库文件路径错误、依赖库缺失、ABI 不匹配(32/64位)、SELinux 权限拒绝。
HAL 版本 模块 API 版本 关键结构体 适用场景
HAL v1 HAL_MODULE_API_VERSION(1, 0) camera_module_t Android 4.x 及以下
HAL v3 HAL_MODULE_API_VERSION(3, 0) camera_module_t + camera3_device_t Android 5.x ~ 7.x
HAL v3.2+ HAL_MODULE_API_VERSION(3, 2) camera_module_t + camera3_device_t + camera3_stream_configuration_t Android 8.x 及以上
HAL 模块加载流程 CameraService dlopen("camera.*.so") dlsym(HAL_MODULE_INFO_SYM) 版本协商 (module_api_version) HAL v1 接口 HAL v3 接口 HAL v3.2+ 接口

4.2 open() 调用链分析

当应用通过 CameraManager.openCamera() 请求相机时,框架层会触发 HAL 的 open() 回调。完整的调用链涉及三个层级:

层级 组件 关键函数 职责
应用层 CameraManager openCamera(String, CameraDevice.StateCallback, Handler) 发起打开请求,注册状态回调
框架层 CameraService connectDevice() → connectHelper() 权限检查、设备策略验证、HAL 调用
HAL 层 camera_module_t common.methods->open() 初始化硬件、分配设备上下文
关键日志标记:在 logcat 中搜索 "CameraService::connect" 和 "camera_module_open" 可追踪 open 调用进度。若 HAL 层 open 返回 -ENODEV,通常表示硬件初始化失败或设备已被占用。
// HAL open() 回调典型实现框架
static int camera_device_open(const struct hw_module_t* module,
                              const char* name,
                              struct hw_device_t** device) {
    int camera_id = atoi(name);
    camera3_device_t* camera_dev = NULL;

    // 1. 分配设备结构体内存
    camera_dev = (camera3_device_t*)malloc(sizeof(camera3_device_t));
    if (!camera_dev) return -ENOMEM;

    // 2. 初始化设备上下文(传感器、ISP、电源管理等)
    camera_dev->priv = init_camera_device_context(camera_id);
    if (!camera_dev->priv) {
        free(camera_dev);
        return -ENODEV;
    }

    // 3. 填充 HAL v3 函数表
    camera_dev->ops = &camera_device_ops;
    camera_dev->common.tag = HARDWARE_DEVICE_TAG;
    camera_dev->common.version = CAMERA_DEVICE_API_VERSION_3_2;
    camera_dev->common.module = (hw_module_t*)module;
    camera_dev->common.close = camera_device_close;

    *device = &camera_dev->common;
    return 0;
}

4.3 CameraDevice 初始化

CameraDevice 初始化是 HAL 层为特定相机设备准备运行环境的过程。该阶段主要完成以下工作:

  • 传感器能力查询:读取 static_metadata,包括分辨率范围、帧率、AE/AWB 能力等。
  • 流配置准备:初始化 camera3_stream_configuration_t 结构体,准备接收上层流请求。
  • 资源预分配:分配 ISP 管线缓冲区、ISP 统计信息缓冲区、3A 算法上下文。
  • 中断/事件注册:注册传感器 VSYNC、SOF(Start of Frame)中断处理函数。
常见初始化失败场景:
• initialize() 返回 -EINVAL:通常由于 camera3_callback_ops 指针为空或版本不匹配。
• 传感器驱动 probe 失败:检查 dmesg 中的 I2C/SPI 通信错误。
• 内存分配失败:多见于低内存设备或缓冲区配置过大。

4.4 Session 创建流程

Session 创建是初始化流程的最后一步,由 CameraCaptureSession 的创建触发。HAL 层需要完成流配置和管线启动:

  1. configure_streams() 调用:上层传递 camera3_stream_configuration_t,包含所有请求的流(预览、拍照、录像等)。
  2. 流验证与调整:HAL 检查流参数(分辨率、格式、usage flags),必要时调整 max_buffers 或降级格式。
  3. ISP 管线重配置:根据流配置重新计算 ISP 处理管线参数。
  4. BufferQueue 建立:为每个流分配 gralloc 缓冲区,建立生产者-消费者通道。
  5. Session 就绪回调:通过 camera3_callback_ops->notify() 发送 CAMERA3_MSG_ERROR 或成功信号。
Session 创建与流配置流程 应用层 CameraManager 框架层 CameraService HAL 层 configure_streams() 流验证与调整 ISP 管线重配置 BufferQueue 建立

4.5 初始化流程常见问题定位

异常现象 可能原因 定位方法
HAL 模块加载失败 库文件缺失、SELinux 拒绝、ABI 不匹配 logcat -b all | grep dlopen + ls -l /vendor/lib*/camera.*.so
open() 返回 -ENODEV 硬件初始化失败、设备被占用、电源未上电 dmesg | grep camera + 检查 GPIO/PMIC 状态
configure_streams() 失败 流参数不合法、ISP 资源不足、格式不支持 打印 camera3_stream 参数 + 检查 static_metadata 能力列表
Session 创建超时 BufferQueue 死锁、ISP 管线卡死 dumpsys media.camera + 检查 gralloc 缓冲区分配日志
调试黄金法则:初始化阶段的日志具有强时序性。建议在 HAL 层关键函数入口/出口添加 ALOGD 标记,配合 logcat -v time 分析各阶段耗时。若某阶段耗时超过 500ms,极可能存在资源竞争或硬件响应延迟。