Camera HAL3开发调试与图像参数适配 - 第4节

4.1 HAL 模块加载机制

Camera HAL 的初始化始于 Android 系统通过 hw_get_module() 或 HAL_MODULE_INFO_SYM 符号查找并加载 HAL 动态库。该过程由 cameraserver 进程触发,最终定位到 camera.<variant>.so 共享库。

关键入口: 每个 HAL 库必须导出 HAL_MODULE_INFO_SYM 符号,类型为 hw_module_t,其中包含模块 ID、版本号及 open() 函数指针。

4.1.1 模块加载流程

  1. 服务启动: cameraserver 调用 CameraService::instantiate()。
  2. HAL 查找: hw_get_module(CAMERA_HARDWARE_MODULE_ID, &module) 根据系统属性 ro.hardware.camera 或 ro.board.platform 定位 .so 文件。
  3. 符号解析: 加载库后,通过 dlsym() 获取 HAL_MODULE_INFO_SYM 结构体地址。
  4. 模块验证: 检查 module->tag 是否为 HARDWARE_MODULE_TAG,版本号是否匹配。
  5. 回调注册: 将 camera_module_callbacks_t 注册到 HAL,用于热插拔通知。
调试技巧: 使用 adb shell lsof | grep camera 可查看已加载的 HAL 库路径;若加载失败,检查 logcat -s CameraService 中的 E 级别日志。
HAL 模块加载流程 cameraserver hw_get_module() camera.<plat>.so HAL_MODULE_INFO_SYM hw_module_t 验证 回调注册完成 注意:若系统属性 ro.hardware.camera 未设置,HAL 将按 ro.board.platform 回退查找。 使用 adb shell getprop ro.hardware.camera 可查看当前使用的 HAL 变体。

4.2 open() 函数调用链

模块加载成功后,CameraService 调用 module->common.open() 打开指定 camera ID 的设备。该函数在 HAL 侧对应 camera_device_open(),负责初始化硬件并返回 camera_device_t 接口。

4.2.1 调用链分解

调用层函数/方法职责
FrameworkCameraService::connect()验证客户端权限,分配 CameraClient
HAL 适配层camera_module_t::open()根据 camera_id 查找内部设备列表
HAL 实现层camera_device_open()初始化传感器、ISP、电源管理
Kernel 接口open("/dev/video*")建立 V4L2 或自定义驱动通道
常见失败原因: open() 返回 -ENODEV 通常表示 camera_id 越界或对应硬件未上电;返回 -EBUSY 表示设备已被占用,需检查并发访问控制。
// HAL 侧 open() 典型实现骨架
static int camera_device_open(const hw_module_t* module, const char* id,
                              hw_device_t** device) {
    int camera_id = atoi(id);
    if (camera_id < 0 || camera_id >= MAX_CAMERAS) {
        ALOGE("Invalid camera id: %s", id);
        return -ENODEV;
    }
    camera_device_t* camera_dev = (camera_device_t*)malloc(sizeof(camera_device_t));
    memset(camera_dev, 0, sizeof(*camera_dev));
    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;
    // 初始化硬件:GPIO、时钟、I2C 配置
    if (init_hardware(camera_id) != 0) {
        free(camera_dev);
        return -EIO;
    }
    *device = &camera_dev->common;
    return 0;
}
open() 函数调用链 CameraService::connect() module->common.open() camera_device_open() init_hardware() open("/dev/video*") 返回 camera_device_t 关键检查点:open() 返回后需验证 device->common.version 是否 >= CAMERA_DEVICE_API_VERSION_3_0。 若版本过低,CameraService 将拒绝使用并卸载 HAL 模块。

4.3 camera_info 初始化

在 open() 之后,CameraService 调用 camera_module_t::get_camera_info() 获取每个 camera 的静态能力信息。该信息填充到 camera_info_t 结构体中,包含设备方向、闪光灯支持、传感器朝向等。

4.3.1 camera_info_t 关键字段

字段类型说明
facingintCAMERA_FACING_BACK=0 / CAMERA_FACING_FRONT=1
orientationint传感器安装角度,0/90/180/270
device_versionuint32_tHAL 设备版本,如 CAMERA_DEVICE_API_VERSION_3_5
resource_costint资源开销评分,用于多摄像头策略
conflicting_devicesconst char**互斥设备 ID 列表,NULL 结尾

4.4.2 初始化流程

  • 静态配置读取: 从设备树、板级配置文件或硬编码表中读取 sensor 物理属性。
  • 动态校准加载: 从 /vendor/etc/camera/ 或 /data/misc/camera/ 加载镜头校准参数。
  • 能力合成: 将静态配置与校准参数合并,填充 camera_info_t。
  • 注册到服务: CameraService 将 info 存入全局列表,供后续 getCameraInfo() 查询。
调试方法: 在 HAL 的 get_camera_info() 中添加 ALOGD 打印 facing 和 orientation;使用 adb shell dumpsys media.camera 可查看服务端已注册的 camera_info 列表。
// camera_info 初始化示例
static int camera_get_info(const struct camera_module* module,
                           int camera_id, struct camera_info* info) {
    if (camera_id == 0) {
        info->facing = CAMERA_FACING_BACK;
        info->orientation = 90;
        info->device_version = CAMERA_DEVICE_API_VERSION_3_5;
        info->resource_cost = 100;
        info->conflicting_devices = (const char*[]){ "1", NULL };
    } else if (camera_id == 1) {
        info->facing = CAMERA_FACING_FRONT;
        info->orientation = 270;
        info->device_version = CAMERA_DEVICE_API_VERSION_3_5;
        info->resource_cost = 50;
        info->conflicting_devices = NULL;
    } else {
        return -EINVAL;
    }
    ALOGD("camera_info[%d]: facing=%d, orientation=%d", camera_id,
          info->facing, info->orientation);
    return 0;
}
camera_info 初始化数据流 设备树/板级配置 校准文件加载 能力合成模块 camera_info_t CameraService 注册 注意:orientation 值必须与 sensor 物理安装角度一致,错误设置会导致预览画面旋转异常。 resource_cost 用于多摄像头场景下的主副摄切换决策,值越大优先级越低。

4.4 初始化流程总结

Camera HAL 初始化可归纳为三个阶段:模块加载、设备打开、信息注册。每个阶段都有明确的错误码和调试入口,掌握这些流程是进行参数配置与调试的基础。

阶段关键函数输出产物典型调试点
模块加载hw_get_module()hw_module_t检查 .so 路径和符号表
设备打开camera_device_open()camera_device_t验证 device_version 和 ops 指针
信息注册get_camera_info()camera_info_t确认 facing/orientation 值
核心原则: 初始化阶段的任何失败都会导致相机服务无法正常启动。建议在 HAL 实现中为每个阶段添加详细的 ALOGE 日志,并配合 dumpsys 进行问题定位。