4. Camera HAL 初始化流程:open() 接口实现、camera_info 填充、静态元数据配置

Camera HAL 的初始化流程是上层 Framework 与底层硬件驱动建立通信的第一道关卡。本章聚焦 open() 接口的实现细节、camera_info 结构体的正确填充,以及静态元数据(Static Metadata)的配置策略。这三个环节直接决定了相机设备能否被成功枚举、打开,以及上层应用能否获取到正确的设备能力描述。

4.1 open() 接口实现

open() 是 HAL 模块暴露给 Camera Service 的核心入口,负责创建并返回一个 camera_device_t 实例。其典型实现流程如下:

  1. 参数校验:检查 hw_module_t 指针、camera_device_t 二级指针、camera_id 合法性。
  2. 设备实例分配:为自定义的 camera_device_t 包装结构体分配内存,并初始化内部状态机。
  3. 硬件接口初始化:调用 V4L2、CSI 或平台私有驱动接口,打开传感器、ISP 等硬件通路。
  4. ops 函数表挂载:将 set_preview_window、start_preview、take_picture 等标准操作函数指针赋值给 camera_device_ops_t。
  5. 静态元数据预加载:从配置文件或驱动中读取传感器能力,构建 camera_metadata_t 并缓存。
关键约束:open() 必须支持并发调用(不同 camera_id),且同一 camera_id 在未 close() 前不可重复打开。返回的 camera_device_t 生命周期由 Camera Service 管理。

4.2 camera_info 填充

camera_info 是 HAL 通过 get_camera_info() 返回给 Framework 的设备描述结构体。其填充质量直接影响上层对摄像头数量、朝向、闪光灯能力的判断。

字段 类型 说明 常见值
device_version uint32_t HAL 设备版本号 HARDWARE_DEVICE_API_VERSION(1, 0)
static_camera_characteristics camera_metadata_t* 指向静态元数据的主指针 由 construct_default_metadata() 生成
resource_cost int 设备资源开销(0~100) 主摄 0,副摄 50,虚拟摄像头 100
conflicting_devices const char** 互斥设备 ID 列表 如双摄同时使用时需标记
conflicting_devices_length int 互斥设备数量 0 表示无互斥
移植经验:在多摄平台上,resource_cost 和 conflicting_devices 必须根据硬件拓扑精确配置,否则可能导致 Camera Service 在并发打开时误判资源冲突,引发 open() 失败。

4.3 静态元数据配置

静态元数据(Static Metadata)是 HAL 向 Framework 声明摄像头硬件能力的核心数据结构。它通过 camera_metadata_t 的键值对形式组织,必须在 get_camera_info() 返回前完成填充。

4.3.1 元数据分类与关键 Tag

分类 关键 Tag 示例 配置来源
基础信息 ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE Sensor 数据手册
帧率范围 ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES 驱动能力查询
输出格式 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS ISP 支持列表
对焦能力 ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS 模组规格书
闪光灯 ANDROID_FLASH_INFO_AVAILABLE 硬件 GPIO 配置

4.3.2 配置流程

  1. 创建元数据缓冲区:使用 allocate_camera_metadata() 或 clone_camera_metadata() 分配初始空间。
  2. 逐项写入:通过 camera_metadata_put_*() 系列函数写入整数、浮点、字符串或数组类型。
  3. 校验与排序:调用 camera_metadata_sort() 确保内部索引有序,提升查找效率。
  4. 指针挂载:将最终 camera_metadata_t* 赋值给 camera_info.static_camera_characteristics。
常见陷阱:
- 漏配 ANDROID_SENSOR_ORIENTATION 会导致预览画面旋转异常。
- ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS 中输出尺寸必须与硬件实际支持严格一致,否则 configure_streams() 阶段会返回错误。
- 静态元数据一旦返回,在 HAL 生命周期内不可变更;如需动态调整,应使用动态元数据(Result Metadata)。

4.4 初始化流程总览

下图展示了从 Camera Service 调用 open() 到静态元数据就绪的完整数据流与模块交互关系:

Camera HAL 初始化流程:open() → camera_info → 静态元数据 Camera Service HAL Module open() 实现 camera_info 填充 静态元数据配置 V4L2 / ISP 驱动 Sensor 配置文件 open(camera_id) 查询能力 说明:静态元数据在 open() 期间预加载,通过 get_camera_info() 返回给 Framework,后续不再变更。

4.5 代码示例:open() 与静态元数据填充骨架

// HAL open() 实现骨架
static int camera_device_open(const struct hw_module_t* module,
                              const char* id,
                              struct hw_device_t** device) {
    if (module == NULL || id == NULL || device == NULL)
        return -EINVAL;

    int camera_id = atoi(id);
    if (camera_id < 0 || camera_id >= CAMERA_NUM)
        return -ENODEV;

    camera_device_t* dev = (camera_device_t*)malloc(sizeof(camera_device_t));
    memset(dev, 0, sizeof(camera_device_t));

    // 初始化 ops 函数表
    dev->ops = &camera_device_ops;
    dev->priv = init_camera_priv(camera_id);

    // 预加载静态元数据
    camera_metadata_t* metadata = construct_static_metadata(camera_id);
    if (metadata == NULL) {
        free(dev);
        return -ENOMEM;
    }

    // 填充 camera_info(实际通过 get_camera_info 返回)
    camera_info_t info;
    info.device_version = HARDWARE_DEVICE_API_VERSION(1, 0);
    info.static_camera_characteristics = metadata;
    info.resource_cost = (camera_id == 0) ? 0 : 50;
    info.conflicting_devices = NULL;
    info.conflicting_devices_length = 0;

    *device = (hw_device_t*)dev;
    return 0;
}

// 静态元数据构造示例
static camera_metadata_t* construct_static_metadata(int camera_id) {
    camera_metadata_t* meta = allocate_camera_metadata(
        CAMERA_METADATA_ENTRY_MAX, CAMERA_METADATA_DATA_MAX);

    int32_t pixel_array[2] = {1920, 1080};
    camera_metadata_put_int32(meta,
        ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, pixel_array, 2);

    int32_t fps_ranges[2] = {15, 30};
    camera_metadata_put_int32(meta,
        ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, fps_ranges, 2);

    // ... 继续填充其他必要 Tag

    camera_metadata_sort(meta);
    return meta;
}

4.6 初始化验证清单

  • 枚举测试:通过 get_camera_info() 返回的 device_version 是否与预期一致。
  • 元数据完整性:使用 camera_metadata_dump() 检查所有强制 Tag 是否已填充。
  • 并发打开:同时打开主摄与副摄,验证 resource_cost 和 conflicting_devices 逻辑。
  • 内存泄漏:反复 open()/close() 后检查 camera_metadata_t 是否被正确释放。
调试技巧:在 open() 入口和 get_camera_info() 返回前添加 ALOGV 日志,打印 camera_id、metadata 地址和关键 Tag 值,可快速定位初始化失败根因。