4. Camera HAL 初始化流程:HAL模块加载、open流程、camera_info填充、static_metadata构建

Camera HAL 的初始化是上层 Camera Service 与底层硬件驱动建立通信通道的关键阶段。该流程涉及四个核心步骤:HAL 模块加载、open 设备、camera_info 填充以及 static_metadata 构建。理解这一流程对于调试相机启动速度、设备识别失败以及元数据缺失等问题至关重要。

4.1 整体初始化流程概览

以下 SVG 图展示了从 Camera Service 调用 HAL 到应用层获取相机信息的完整初始化链路。

Camera HAL 初始化流程概览 Camera Service HAL Module 加载 open 设备 camera_info 填充 static_metadata 构建 Framework 获取信息 初始化关键路径 1. dlopen 加载 HAL .so 2. hw_module_t->open() 3. get_camera_info()

4.2 HAL 模块加载

HAL 模块加载是初始化的第一步,由 Camera Service 通过 hw_get_module() 或 HAL_MODULE_INFO_SYM 机制完成。加载过程的核心是找到并打开对应平台的 HAL 动态库(如 camera.xxx.so)。

步骤 函数/操作 说明
1 hw_get_module(CAMERA_HARDWARE_MODULE_ID, &module) 根据 HAL 类型 ID 查找并加载对应的 .so 文件
2 dlopen("camera.xxx.so", RTLD_NOW) 底层通过 dlopen 打开动态库,获取符号表
3 dlsym(handle, "HAL_MODULE_INFO_SYM_AS_STR") 获取 hw_module_t 结构体指针,其中包含 open、get_number_of_cameras 等函数指针
4 验证 module->tag == HARDWARE_MODULE_TAG 校验模块版本和标签,确保 HAL 接口兼容
调试要点: 如果 HAL 模块加载失败,常见原因包括:.so 文件路径错误、依赖库缺失、HAL_MODULE_INFO_SYM 未正确导出。建议在 hw_get_module 前后添加 log,检查 module->id 和 module->methods->open 是否非空。

4.3 open 流程

模块加载成功后,Camera Service 调用 module->methods->open() 打开具体的 camera 设备。该函数返回一个 hw_device_t 指针,实际类型为 camera_device_t,其中包含了操作相机的函数表。

// 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);
    camera_device_t* camera_dev = (camera_device_t*)malloc(sizeof(camera_device_t));
    memset(camera_dev, 0, sizeof(camera_device_t));

    // 填充 hw_device_t 公共字段
    camera_dev->common.tag     = HARDWARE_DEVICE_TAG;
    camera_dev->common.version = CAMERA_DEVICE_API_VERSION_1_0;
    camera_dev->common.module  = (hw_module_t*)module;
    camera_dev->common.close   = camera_device_close;

    // 填充 camera_device_t 操作函数表
    camera_dev->ops = &camera_ops;  // 包含 set_preview_window, start_preview 等

    *device = &camera_dev->common;
    return 0;
}
常见问题: open 流程中容易出现的错误包括:name 参数转换的 camera_id 越界、malloc 失败未处理、ops 函数表未完全初始化导致后续调用空指针。建议在 open 函数内增加 ALOGI 打印 camera_id 和设备指针地址。

4.4 camera_info 填充

在 open 设备之后,Camera Service 通过 get_camera_info() 获取每个相机的静态信息。该信息填充到 camera_info 结构体中,主要包括设备方向、是否支持闪光灯、以及最重要的 static_camera_characteristics 元数据。

// camera_info 结构体定义
typedef struct camera_info {
    int                     device_version;     // 设备版本,如 CAMERA_DEVICE_API_VERSION_1_0
    char                    device_id[256];     // 设备 ID,如 "0"、"1"
    int                     facing;             // 朝向:CAMERA_FACING_BACK / FRONT
    int                     orientation;        // 图像方向,0/90/180/270
    camera_metadata_t*      static_camera_characteristics; // 静态元数据
} camera_info_t;
字段 典型值 调试检查点
facing 0 (BACK) / 1 (FRONT) 确认前后摄分配正确,避免应用调用错摄像头
orientation 90 (后摄) / 270 (前摄) 方向错误会导致预览图像旋转 90° 或 180°
device_version CAMERA_DEVICE_API_VERSION_1_0 版本不匹配会导致 Service 拒绝加载设备

4.5 static_metadata 构建

static_camera_characteristics 是 Android Camera 框架中最重要的元数据集合,它描述了相机硬件的能力和限制。该元数据在 HAL 初始化时构建,并在整个相机生命周期内保持不变。

构建过程通常分为以下步骤:

  1. 创建元数据缓冲区: 使用 allocate_camera_metadata() 分配足够大的缓冲区。
  2. 填充标准 Tag: 调用 camera_metadata_ops 中的函数,逐个添加 ANDROID_SENSOR_INFO_*、ANDROID_SCALER_*、ANDROID_CONTROL_* 等 Tag。
  3. 填充厂商自定义 Tag: 如果平台有私有扩展能力,通过 ANDROID_REQUEST_AVAILABLE_CAPABILITIES 中的 BACKWARD_COMPATIBLE 或 PRIVATE_REPROCESSING 等标记。
  4. 排序并锁定: 调用 sort_camera_metadata() 确保元数据有序,便于快速查找。
// static_metadata 构建示例(伪代码)
static camera_metadata_t* build_static_metadata() {
    camera_metadata_t* metadata = allocate_camera_metadata(
        CAMERA_METADATA_ENTRY_MAX, CAMERA_METADATA_DATA_MAX);

    // 添加传感器尺寸
    int32_t sensor_size[] = {1920, 1080};
    add_camera_metadata_entry(metadata,
        ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, sensor_size, 2);

    // 添加支持的帧率范围
    int32_t fps_range[] = {15, 30};
    add_camera_metadata_entry(metadata,
        ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, fps_range, 2);

    // 添加闪光灯能力
    uint8_t flash_available = 1;
    add_camera_metadata_entry(metadata,
        ANDROID_FLASH_INFO_AVAILABLE, &flash_available, 1);

    sort_camera_metadata(metadata);
    return metadata;
}
关键调试技巧: 使用 dump_camera_metadata() 函数可以打印所有静态元数据内容,用于验证 HAL 层是否正确上报了能力。常见问题包括:ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE 与实际 sensor 输出尺寸不一致、ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES 缺失导致预览帧率异常。

4.6 初始化流程中的常见问题与排查

现象 可能原因 排查方法
Camera Service 无法找到 HAL 模块 .so 未正确安装或 hw_get_module 路径错误 检查 /vendor/lib/hw/ 或 /system/lib/hw/ 下是否存在对应 .so
open 返回 -ENODEV sensor 驱动未初始化或 I2C 通信失败 检查 kernel log 中 sensor 驱动 probe 是否成功
camera_info 中 orientation 错误 HAL 层硬编码了错误的方向值 对比 sensor 物理安装角度与 HAL 中 orientation 值
static_metadata 缺失关键 Tag 构建时未添加必要的 ANDROID 标准 Tag 使用 dump_camera_metadata 对比 CTS 要求的最小 Tag 集合

初始化流程的稳定性直接决定了相机应用能否正常启动。在调试过程中,建议在 HAL 层的每个关键函数入口和出口添加 ALOGI 日志,并结合 logcat -s CameraService 和 logcat -s CameraHal 分别观察 Framework 和 HAL 层的交互状态。