4. Camera HAL3 初始化流程:open()、initialize()、configure_streams() 的调用时序与参数解析

Camera HAL3 的初始化流程是 Camera Service 与 Vendor HAL 建立通信通道、协商数据格式并分配内存的关键阶段。该流程由三个核心接口调用组成:open()、initialize() 和 configure_streams()。理解它们的调用时序、参数含义以及 Vendor 层的实现约束,是进行 HAL 适配与调试的基础。

核心要点: 初始化流程是 Camera Service 主导的“握手”过程。open() 建立设备连接,initialize() 交换能力与回调,configure_streams() 最终确定数据管道。任何一步的失败或参数不匹配,都会导致 Camera 无法打开或预览黑屏。

4.1 调用时序与状态机

HAL3 的初始化遵循严格的状态机转换。Camera Service 按照固定顺序调用这三个接口,Vendor 层必须正确维护内部状态,否则会触发 Service 侧的异常处理。

HAL3 初始化调用时序与状态机 UNINITIALIZED OPENED INITIALIZED CONFIGURED open() initialize() configure_streams() ⚠ 状态转换约束 • 不允许跳过状态:例如未调用 open() 直接调用 initialize() 应返回 -ENODEV。 • configure_streams() 可在 INITIALIZED 状态下多次调用,用于切换分辨率或帧率。 • close() 调用后状态回到 UNINITIALIZED,所有已分配资源必须释放。

4.2 open():建立设备连接

open() 是 HAL 模块加载后的第一个调用,用于实例化一个 camera 设备。其原型定义在 camera_module_t 中:

int (*open)(const struct hw_module_t* module, const char* id,
            struct hw_device_t** device);

参数解析

参数类型说明
moduleconst struct hw_module_t*指向 HAL 模块实例的指针,Vendor 可通过它访问模块级信息。
idconst char*Camera ID 字符串,例如 "0"、"1",对应 camera_info_t 中的设备标识。
devicestruct hw_device_t**输出参数,指向新创建的 camera3_device_t 结构体指针。
Vendor 实现要点: 在 open() 中,Vendor 应分配 camera3_device_t 结构体,并填充其中的 ops 函数指针表(包括 initialize、configure_streams、process_capture_request 等)。同时,应初始化底层硬件驱动句柄,但此时不要分配流内存。

4.3 initialize():交换能力与回调

initialize() 是 Camera Service 与 HAL 建立双向通信的关键步骤。Service 传入回调接口,HAL 返回设备静态信息。

int (*initialize)(const struct camera3_device *device,
                  const camera3_callback_ops_t *callback_ops);

参数解析

参数类型说明
deviceconst struct camera3_device*由 open() 创建的设备实例。
callback_opsconst camera3_callback_ops_t*Service 提供的回调函数表,包含 process_capture_result、notify 等。

回调函数表 (camera3_callback_ops_t)

  • process_capture_result:HAL 通过此回调将已处理完成的 capture result 返回给 Service。
  • notify:HAL 通过此回调发送异步事件,如快门事件、错误事件、缓冲区释放信号等。
常见错误: Vendor 在 initialize() 中必须保存 callback_ops 指针,否则后续无法向 Service 返回数据。同时,initialize() 不应执行耗时操作(如 ISP 加载),否则可能导致 Service 超时(默认 5 秒)。

4.4 configure_streams():协商数据管道

configure_streams() 是初始化流程中最复杂、最关键的接口。它决定了 Camera 输出的格式、分辨率、帧率以及内存分配策略。

int (*configure_streams)(const struct camera3_device *device,
                         camera3_stream_configuration_t *stream_list);

参数解析

参数类型说明
deviceconst struct camera3_device*设备实例。
stream_listcamera3_stream_configuration_t*包含所有待配置 stream 的数组及操作模式。

camera3_stream_configuration_t 结构体

typedef struct camera3_stream_configuration {
    uint32_t                    num_streams;        // stream 数量
    camera3_stream_t            **streams;          // stream 指针数组
    uint32_t                    operation_mode;     // 操作模式
    const camera3_stream_buffer_set_t *buffer_set;  // 可选,用于 buffer 管理
} camera3_stream_configuration_t;

操作模式 (operation_mode)

模式常量值说明
CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE0x0000标准预览/拍照模式,最常用。
CAMERA3_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE0x0001高速模式,用于高帧率录像(如 120fps)。
CAMERA3_STREAM_CONFIGURATION_VENDOR_MODE_START0x8000Vendor 自定义模式起始值。

camera3_stream_t 关键字段

字段类型说明
stream_typeintCAMERA3_STREAM_OUTPUT (输出) 或 CAMERA3_STREAM_INPUT (输入)。
width / heightuint32_t图像分辨率,Vendor 必须支持。
formatint像素格式,如 HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED、HAL_PIXEL_FORMAT_YCbCr_420_888。
usageuint32_tGralloc 使用标志,指示 buffer 的预期用途(如 GPU 纹理、视频编码器)。
max_buffersuint32_tVendor 建议的最大 buffer 数量,Service 可据此分配。
privvoid*Vendor 私有数据指针,用于关联硬件管道。
Vendor 实现要点: configure_streams() 是 Vendor 进行硬件管道重配置的入口。Vendor 需要根据 stream_list 中的格式和分辨率,设置 ISP、传感器输出尺寸、MIPI 通道等。如果请求的配置硬件不支持,应返回 -EINVAL 并打印详细日志。

4.5 参数校验与常见错误码

Vendor 层在实现这三个接口时,必须对输入参数进行严格校验。以下是常见的错误码及其含义:

错误码值含义常见触发场景
-ENODEV-19设备不存在或未初始化open() 时 ID 无效;initialize() 时设备未 open
-EINVAL-22无效参数configure_streams() 中分辨率/格式不支持
-ENOMEM-12内存不足open() 分配设备结构体失败
-EUSERS-87资源冲突多个 stream 争用同一硬件资源
-EBUSY-16设备忙在已有 pipeline 运行时重复 configure_streams()

4.6 调试工具链实战建议

  • 日志打点: 在 open()、initialize()、configure_streams() 的入口和出口添加 ALOGD 日志,打印关键参数(ID、stream 数量、格式、分辨率)。
  • 参数转储: 在 configure_streams() 中,将 stream_list 内容转储到 /data/vendor/camera/ 目录下的 dump 文件,便于离线分析。
  • 状态机检查: 在每次接口调用时,检查当前 HAL 内部状态是否合法,非法状态直接返回 -ENODEV 并打印错误栈。
  • 超时监控: 使用 adb shell dumpsys media.camera 查看 Service 侧的调用超时统计,定位 Vendor 实现中的耗时瓶颈。
实战案例: 某平台在 configure_streams() 中返回 -EINVAL,原因是 HAL 未实现 HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED 到实际硬件格式的映射。通过添加格式转换表并打印匹配日志,问题得以解决。