4. HAL模块初始化:HAL_MODULE_INFO_SYM结构体定义、open函数实现、camera_info填充、静态特性元数据构建

HAL模块初始化是Camera HAL驱动开发的起点,也是整个相机框架与硬件交互的桥梁。本章深入剖析HAL模块初始化的四个核心环节:HAL_MODULE_INFO_SYM结构体定义、open函数实现、camera_info填充以及静态特性元数据构建。掌握这些内容,你将能够构建一个符合Android HAL规范的相机模块入口。

4.1 HAL_MODULE_INFO_SYM结构体定义

在Android Camera HAL中,HAL_MODULE_INFO_SYM是每个HAL模块必须导出的符号,它是HAL框架与驱动代码之间的契约。该结构体定义了模块的ID、版本号、作者信息以及最重要的回调函数指针——open。

关键点:HAL_MODULE_INFO_SYM是全局唯一的符号名称,必须严格按照Android HAL规范命名,否则HAL框架无法加载模块。

以下是一个标准的HAL_MODULE_INFO_SYM定义示例:

static struct hw_module_methods_t camera_module_methods = {
    .open = camera_device_open,
};

struct camera_module HAL_MODULE_INFO_SYM = {
    .common = {
        .tag           = HARDWARE_MODULE_TAG,
        .module_api_version = CAMERA_MODULE_API_VERSION_2_4,
        .hal_api_version    = HARDWARE_HAL_API_VERSION,
        .id            = CAMERA_HARDWARE_MODULE_ID,
        .name          = "Camera HAL Module",
        .author        = "Your Company",
        .methods       = &camera_module_methods,
        .dso           = NULL,
        .reserved      = {0},
    },
    .get_number_of_cameras      = get_number_of_cameras,
    .get_camera_info            = get_camera_info,
    .set_callbacks              = set_callbacks,
    .get_vendor_tag_ops         = get_vendor_tag_ops,
    .open_legacy                = NULL,
    .set_torch_mode             = set_torch_mode,
    .init                       = NULL,
    .reserved                   = {0},
};

结构体字段说明:

字段 说明 典型值
tag 模块标签,固定为HARDWARE_MODULE_TAG HARDWARE_MODULE_TAG
module_api_version 模块API版本,决定HAL层支持的功能集 CAMERA_MODULE_API_VERSION_2_4
hal_api_version HAL框架API版本 HARDWARE_HAL_API_VERSION
id 模块唯一标识符 CAMERA_HARDWARE_MODULE_ID
methods 指向hw_module_methods_t结构体的指针,包含open函数 &camera_module_methods
get_number_of_cameras 返回设备上可用的摄像头数量 函数指针
get_camera_info 填充指定摄像头的camera_info结构体 函数指针
实践建议:在定义HAL_MODULE_INFO_SYM时,务必检查module_api_version与Android框架版本的兼容性。Android 10及以上推荐使用CAMERA_MODULE_API_VERSION_2_4。

4.2 open函数实现

open函数是HAL模块的入口点,负责创建并初始化摄像头设备实例。当CameraService调用hw_module_t->methods->open()时,HAL驱动需要完成设备节点的打开、硬件资源的分配以及回调接口的注册。

open函数的标准实现流程:

  1. 参数校验:检查module和hw_device_t指针是否有效,验证设备ID是否在合法范围内。
  2. 内存分配:为camera_device_t结构体分配内存,并初始化为零。
  3. 设备初始化:打开V4L2设备节点或ISP驱动接口,初始化传感器和ISP硬件。
  4. 回调注册:设置camera_device_ops_t中的函数指针,包括get_metadata、ops等。
  5. 返回设备句柄:将初始化完成的camera_device_t通过参数返回给框架。
static int camera_device_open(const struct hw_module_t *module,
                              const char *id,
                              struct hw_device_t **hw_device) {
    int camera_id = atoi(id);
    camera_device_t *camera_dev = NULL;

    // 1. 参数校验
    if (module == NULL || hw_device == NULL) {
        ALOGE("Invalid parameters");
        return -EINVAL;
    }
    if (camera_id < 0 || camera_id >= MAX_CAMERAS) {
        ALOGE("Invalid camera id: %d", camera_id);
        return -ENODEV;
    }

    // 2. 内存分配
    camera_dev = (camera_device_t *)calloc(1, sizeof(camera_device_t));
    if (camera_dev == NULL) {
        ALOGE("Failed to allocate camera device");
        return -ENOMEM;
    }

    // 3. 设备初始化
    camera_dev->priv = init_camera_hardware(camera_id);
    if (camera_dev->priv == NULL) {
        ALOGE("Failed to init camera hardware for id %d", camera_id);
        free(camera_dev);
        return -EIO;
    }

    // 4. 设置设备操作函数
    camera_dev->common.tag     = HARDWARE_DEVICE_TAG;
    camera_dev->common.version = CAMERA_DEVICE_API_VERSION_3_5;
    camera_dev->common.module  = (hw_module_t *)module;
    camera_dev->common.close   = camera_device_close;
    camera_dev->ops            = &camera_device_ops;

    // 5. 返回设备句柄
    *hw_device = &camera_dev->common;

    ALOGI("Camera device opened for id %d", camera_id);
    return 0;
}
常见陷阱:open函数中不要执行耗时操作(如ISP固件加载),这会导致CameraService启动超时。建议将耗时初始化延迟到第一次调用process_capture_request时执行。

4.3 camera_info填充

camera_info结构体描述了摄像头的静态属性,包括设备方向、是否支持闪光灯、设备姿态等。框架通过get_camera_info回调获取这些信息,用于上层应用决策。

camera_info结构体定义:

typedef struct camera_info {
    int                     device_version;
    uint32_t                device_id;
    int                     facing;
    int                     orientation;
    const char             *resource_cost;
    camera_metadata_t      *static_camera_characteristics;
    int                     status;
    int                     device_type;
    char                   *logical_camera_id;
    int                     physical_camera_count;
    char                  **physical_camera_ids;
    bool                    is_remote_device;
    int                     capability;
    int                     conflict_camera_count;
    char                  **conflict_camera_ids;
} camera_info_t;

填充camera_info的典型实现:

static int get_camera_info(int camera_id, struct camera_info *info) {
    if (camera_id < 0 || camera_id >= MAX_CAMERAS) {
        return -ENODEV;
    }

    // 设置设备版本
    info->device_version = CAMERA_DEVICE_API_VERSION_3_5;

    // 设置摄像头朝向
    if (camera_id == 0) {
        info->facing = CAMERA_FACING_BACK;
        info->orientation = 90;  // 后置摄像头旋转角度
    } else {
        info->facing = CAMERA_FACING_FRONT;
        info->orientation = 270; // 前置摄像头旋转角度
    }

    // 设置资源开销
    info->resource_cost = "100";

    // 设置静态特性元数据
    info->static_camera_characteristics = build_static_metadata(camera_id);

    // 设置设备状态
    info->status = CAMERA_DEVICE_STATUS_PRESENT;

    // 设置设备类型
    info->device_type = CAMERA_DEVICE_TYPE_PHYSICAL;

    return 0;
}
字段 含义 常见值
facing 摄像头朝向(前置/后置/外接) CAMERA_FACING_BACK / CAMERA_FACING_FRONT
orientation 图像相对于自然方向的旋转角度 0, 90, 180, 270
resource_cost 摄像头资源开销,用于多摄像头场景的调度决策 "100"(百分比字符串)
status 摄像头当前状态 CAMERA_DEVICE_STATUS_PRESENT
device_type 设备类型(物理/逻辑/虚拟) CAMERA_DEVICE_TYPE_PHYSICAL

4.4 静态特性元数据构建

静态特性元数据(static_camera_characteristics)是Camera HAL中最复杂的数据结构,它描述了摄像头所有不可变的硬件能力。这些元数据以camera_metadata_t的形式存储,包含传感器尺寸、像素大小、AE/AWB/AF能力、支持的输出格式等数百个标签。

构建静态特性元数据的核心步骤:

  1. 创建元数据缓冲区:使用allocate_camera_metadata()分配足够大的缓冲区。
  2. 填充基础信息:设置传感器信息、像素阵列大小、颜色特性等。
  3. 填充能力信息:设置AE/AWB/AF模式、场景模式、特效等支持情况。
  4. 填充输出配置:设置支持的图像格式、分辨率、帧率范围。
  5. 填充控制能力:设置3A控制、同步能力、请求管线深度等。
static camera_metadata_t *build_static_metadata(int camera_id) {
    camera_metadata_t *metadata;
    int32_t sensor_width = 3264;
    int32_t sensor_height = 2448;
    int32_t pixel_array_size[] = {sensor_width, sensor_height};
    int32_t active_array_size[] = {0, 0, sensor_width, sensor_height};

    // 1. 计算元数据所需空间
    size_t entry_capacity = 100;
    size_t data_capacity = 4096;
    metadata = allocate_camera_metadata(entry_capacity, data_capacity);

    // 2. 填充传感器信息
    int32_t sensor_info[] = {ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB};
    add_camera_metadata_entry(metadata,
        ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
        pixel_array_size, 2);
    add_camera_metadata_entry(metadata,
        ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
        active_array_size, 4);

    // 3. 填充AE/AWB/AF能力
    uint8_t ae_available_modes[] = {
        ANDROID_CONTROL_AE_MODE_ON,
        ANDROID_CONTROL_AE_MODE_OFF,
        ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH
    };
    add_camera_metadata_entry(metadata,
        ANDROID_CONTROL_AE_AVAILABLE_MODES,
        ae_available_modes,
        sizeof(ae_available_modes));

    // 4. 填充支持的输出格式和分辨率
    int32_t stream_config[] = {
        HAL_PIXEL_FORMAT_YCbCr_420_SP,  sensor_width,  sensor_height,
        HAL_PIXEL_FORMAT_YCbCr_420_SP,  640,           480,
        HAL_PIXEL_FORMAT_BLOB,          sensor_width,  sensor_height,
    };
    add_camera_metadata_entry(metadata,
        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
        stream_config,
        sizeof(stream_config) / sizeof(int32_t));

    // 5. 填充帧率范围
    int32_t fps_ranges[] = {15, 30, 30, 30};
    add_camera_metadata_entry(metadata,
        ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
        fps_ranges, 4);

    return metadata;
}
优化技巧:静态特性元数据在HAL模块生命周期内不会改变,建议在模块初始化时一次性构建完成并缓存,避免每次get_camera_info时重复分配和填充。

4.5 初始化流程总览

下图展示了HAL模块初始化的完整流程,从框架加载模块到最终返回设备句柄:

HAL模块初始化流程 框架加载HAL模块 查找HAL_MODULE_INFO_SYM符号 调用open函数 初始化摄像头设备 填充camera_info + 静态元数据 返回camera_device_t句柄

4.6 静态特性元数据关键标签速查

静态特性元数据包含数百个标签,以下表格列出了开发中最常使用的核心标签及其用途:

标签ID 类型 说明 必填
ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE int32[2] 传感器像素阵列的宽高 是
ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE int32[4] 有效像素区域(左、上、宽、高) 是
ANDROID_SENSOR_INFO_SENSITIVITY_RANGE int32[2] ISO感光度范围 是
ANDROID_CONTROL_AE_AVAILABLE_MODES uint8[n] 支持的自动曝光模式列表 是
ANDROID_CONTROL_AF_AVAILABLE_MODES uint8[n] 支持的自动对焦模式列表 是
ANDROID_CONTROL_AWB_AVAILABLE_MODES uint8[n] 支持的白平衡模式列表 是
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS int32[n*4] 支持的输出流配置(格式、宽、高、方向) 是
ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS int64[n*4] 各格式的最小帧持续时间(纳秒) 是
ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS float[n] 可用焦距列表(毫米) 是
ANDROID_FLASH_INFO_AVAILABLE uint8 是否支持闪光灯 是
合规性检查:Android CTS(兼容性测试套件)会严格检查静态特性元数据的完整性和正确性。缺失必填标签或填写错误值将导致CTS测试失败,直接影响设备认证。建议在开发阶段使用camera_metadata_t的验证工具进行自检。

4.7 静态特性元数据构建架构

静态特性元数据的构建涉及多个硬件抽象层的协同工作,下图展示了元数据从硬件参数到最终camera_metadata_t的转换路径:

静态特性元数据构建架构 硬件参数 传感器规格 ISP能力 镜头参数 HAL驱动层 参数解析 能力映射 格式转换 元数据构建 allocate_camera_metadata add_camera_metadata_entry 标签校验 camera_metadata_t 说明 静态特性元数据在模块初始化时构建一次,后续get_camera_info直接返回缓存指针,避免重复构建开销

4.8 常见问题与调试技巧

  • HAL模块加载失败:检查HAL_MODULE_INFO_SYM符号是否被正确导出,使用readelf -s hal_module.so | grep HAL_MODULE_INFO_SYM验证。
  • open函数返回错误:确认设备节点权限正确,使用ls -l /dev/video*检查节点是否存在且可读写。
  • camera_info填充异常:使用dumpsys media.camera查看框架层接收到的camera_info内容,与预期值对比。
  • 静态元数据CTS失败:使用camera_metadata_t的dump_camera_metadata()函数打印所有标签,对照Android兼容性定义文档(CDD)逐项检查。
调试利器:在HAL驱动中增加动态日志开关,通过adb shell setprop persist.camera.hal.debug 1控制日志输出级别,快速定位初始化阶段的问题。