3. 初始化流程:open()、initialize()、configure_streams() 接口调用链与状态机

Camera HAL3 的初始化是上层框架与底层硬件驱动建立通信管道、协商数据通路的关键阶段。整个流程由三个核心接口串联:open()、initialize()、configure_streams()。这三个接口不仅完成了设备句柄的获取、回调机制的注册以及数据流的配置,还驱动着 HAL 设备内部状态机的精确跳转。理解这一调用链及其状态约束,是后续处理 CaptureRequest 的基础。

3.1 初始化调用链全景

下图展示了从 CameraService 发起请求到 HAL 完成流配置的完整调用链与状态变迁路径:

HAL3 初始化调用链与状态机 HAL3 初始化调用链与状态机 CameraService open() initialize() configure_streams() HAL 设备状态机 CLOSED 初始状态 OPEN open() 完成 INITIALIZED initialize() 完成 CONFIGURED 流已配置 open() initialize() configure_streams() ⚠ 非法状态转换约束 CLOSED → INITIALIZED(跳过 open)| OPEN → CONFIGURED(跳过 initialize)| 任何状态 → CLOSED(通过 close())

3.2 接口详解与实现要点

3.2.1 open():设备句柄获取

open() 是 HAL 模块的入口函数,由 hw_module_t 的 open 方法指针定义。调用时传入设备 ID 和指向 hw_device_t 的指针,HAL 实现需要在此函数中完成硬件设备的初始化,并将 camera3_device_t 结构体填充完整。

关键实现要点:

  • 分配并初始化 camera3_device_t 结构体,设置 ops 函数指针表。
  • 打开底层驱动设备节点(如 /dev/video*),进行硬件复位。
  • 分配内部状态机结构体,初始状态设置为 CLOSED。
  • 返回 0 表示成功,返回负值表示失败(如设备忙、权限不足)。
// HAL3 open() 典型实现骨架
static int camera_device_open(const struct hw_module_t* module,
                              const char* id,
                              struct hw_device_t** device) {
    camera3_device_t* camera_dev = (camera3_device_t*)malloc(sizeof(camera3_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;

    // 设置 ops 函数表
    camera_dev->ops = &g_camera3_ops;

    // 初始化内部状态
    camera_dev->priv = malloc(sizeof(hal_private_t));
    hal_private_t* priv = (hal_private_t*)camera_dev->priv;
    priv->state = HAL_DEVICE_STATE_CLOSED;

    *device = &camera_dev->common;
    return 0;
}

3.2.2 initialize():回调注册与框架握手

initialize() 是 HAL 设备从 OPEN 状态进入 INITIALIZED 状态的关键步骤。CameraService 在此接口中传入 camera3_callback_ops_t 结构体,HAL 必须保存该回调句柄,用于后续向框架上报事件、返回结果和发送通知。

回调函数触发时机HAL 实现责任
process_capture_resultCaptureRequest 处理完成填充结果元数据、输出 buffer、部分结果
notify快门事件、错误事件填充 camera3_notify_msg_t 并调用
signal_stream_flushflush() 调用时通知 HAL 内部线程停止等待

最佳实践:在 initialize() 中完成以下操作:

  • 保存 camera3_callback_ops_t 指针到私有数据区。
  • 创建内部工作线程池(如 request 处理线程、result 返回线程)。
  • 初始化同步锁和条件变量,确保线程安全。
  • 将状态机从 OPEN 切换为 INITIALIZED。
// initialize() 实现骨架
static int camera_device_initialize(const struct camera3_device* device,
                                    const camera3_callback_ops_t* callback_ops) {
    hal_private_t* priv = (hal_private_t*)device->priv;

    // 保存回调句柄
    priv->callback_ops = callback_ops;

    // 创建工作线程
    priv->request_thread = new RequestThread(priv);
    priv->result_thread  = new ResultThread(priv);

    // 状态切换
    priv->state = HAL_DEVICE_STATE_INITIALIZED;

    ALOGI("Camera HAL3 initialized successfully");
    return 0;
}

3.2.3 configure_streams():数据通路协商

configure_streams() 是初始化流程中最为复杂的接口。CameraService 在此传入 camera3_stream_configuration_t 结构体,包含所有需要配置的 stream 列表。HAL 需要根据硬件能力决定是否接受该配置,并为每个 stream 分配 buffer 队列和内部资源。

注意:configure_streams() 可能被多次调用(如切换分辨率、添加新 stream)。每次调用都会重置所有 stream 的配置,HAL 必须释放旧资源并重新分配。

// configure_streams() 实现骨架
static int camera_device_configure_streams(
        const struct camera3_device* device,
        camera3_stream_configuration_t* stream_list) {
    hal_private_t* priv = (hal_private_t*)device->priv;

    // 验证状态机:必须在 INITIALIZED 或 CONFIGURED 状态
    if (priv->state != HAL_DEVICE_STATE_INITIALIZED &&
        priv->state != HAL_DEVICE_STATE_CONFIGURED) {
        ALOGE("Invalid state for configure_streams: %d", priv->state);
        return -ENODEV;
    }

    // 释放旧配置(如果有)
    if (priv->state == HAL_DEVICE_STATE_CONFIGURED) {
        free_stream_resources(priv);
    }

    // 遍历所有 stream,验证并配置
    for (uint32_t i = 0; i < stream_list->num_streams; i++) {
        camera3_stream_t* stream = stream_list->streams[i];
        if (!validate_stream_format(stream)) {
            return -EINVAL;
        }
        allocate_stream_buffers(priv, stream);
    }

    // 配置 ISP 和 sensor 参数
    configure_hardware(priv, stream_list);

    // 状态切换
    priv->state = HAL_DEVICE_STATE_CONFIGURED;

    ALOGI("Streams configured: %u streams", stream_list->num_streams);
    return 0;
}

3.3 状态机约束与非法转换

HAL3 规范对状态机转换有严格约束,违反这些约束将导致框架报错或设备异常。下表总结了所有合法的状态转换路径:

当前状态调用接口目标状态说明
CLOSEDopen()OPEN设备打开,尚未初始化
OPENinitialize()INITIALIZED回调注册完成,可配置流
INITIALIZEDconfigure_streams()CONFIGURED首次流配置
CONFIGUREDconfigure_streams()CONFIGURED重新配置流(切换分辨率等)
CONFIGUREDclose()CLOSED关闭设备,释放所有资源
INITIALIZEDclose()CLOSED未配置流时直接关闭
OPENclose()CLOSED打开后未初始化直接关闭

常见实现错误:

  • 在 OPEN 状态下直接调用 configure_streams(),跳过 initialize()。
  • 在 CLOSED 状态下调用 initialize(),未先执行 open()。
  • 多次调用 initialize() 导致回调句柄被覆盖,未做幂等处理。
  • configure_streams() 失败后未回退到 INITIALIZED 状态。

3.4 初始化流程中的资源管理

在初始化过程中,HAL 需要管理多种资源,包括内存、文件描述符、硬件寄存器等。下表总结了各阶段需要分配和释放的资源:

阶段分配资源释放时机
open()camera3_device_t 结构体、私有数据区、驱动 fdclose()
initialize()工作线程、同步锁、条件变量、回调句柄close() 或重新 initialize()
configure_streams()gralloc buffer 句柄、ISP 配置块、sensor 参数下一次 configure_streams() 或 close()

调试建议:在 HAL 实现中增加状态机日志输出,每次状态转换时打印当前状态和目标状态。例如:

ALOGI("HAL state transition: %s -> %s",
      state_to_string(priv->state),
      state_to_string(new_state));

这有助于在开发阶段快速定位状态机异常。

3.5 初始化流程的时序约束

除了状态机约束,HAL3 规范还对初始化流程的时序有明确要求:

  • open() 超时:HAL 应在 500ms 内完成设备打开和初始化,超过此时间框架可能认为设备无响应。
  • initialize() 超时:回调注册和线程创建应在 200ms 内完成。
  • configure_streams() 超时:流配置应在 1s 内完成,复杂场景(如多 camera 同步)可适当放宽。
  • 幂等性:多次调用 configure_streams() 时,HAL 必须正确处理资源释放和重新分配,不能出现内存泄漏。