3. HAL3 核心数据结构详解

Camera HAL3 接口围绕三个核心数据结构构建:camera3_device_t、camera3_callback_ops_t 和 camera3_stream_t。它们是 HAL 层与 Camera Service 之间通信的契约基础,理解其内存布局、生命周期和线程安全模型,是进行 Vendor 层适配与调试的前提。

核心要点:这三个结构体分别代表了“设备句柄”、“回调通道”和“数据管道”。调试中 90% 的稳定性问题(如空指针、野指针、死锁)都源于对它们生命周期管理的疏忽。

3.1 camera3_device_t:HAL 设备抽象

camera3_device_t 是 HAL 层暴露给 Framework 的唯一设备句柄。它封装了所有操作相机设备的函数指针,其定义位于 hardware/libhardware/include/hardware/camera3.h。

字段 类型 说明
common hw_device_t 继承自硬件抽象层基类,包含 tag、version、close 等通用字段
ops camera3_device_ops_t * 指向操作函数表的指针,包含 initialize、configure_streams、process_capture_request 等核心接口
priv void * Vendor 私有数据指针,通常指向具体的 HAL 设备实现对象
// camera3_device_t 典型定义(简化)
typedef struct camera3_device {
    hw_device_t             common;
    camera3_device_ops_t    *ops;
    void                    *priv;
} camera3_device_t;
调试提示:在 Vendor 层适配时,priv 指针是最容易出问题的地方。建议在 open() 时分配一个调试专用的结构体,包含设备状态机、上次调用时间戳、错误计数器等字段,便于在 dump() 或 log 中快速定位。

下图展示了 camera3_device_t 在 HAL 层与 Framework 之间的桥梁作用:

camera3_device_t 架构关系图 Camera Service (Framework 侧) camera3_device_t (HAL 设备句柄) Vendor 实现 (priv 指向) 内部字段 common (hw_device_t) ops (函数指针表) priv (Vendor 私有数据) + 调试扩展字段

3.2 camera3_callback_ops_t:异步回调契约

camera3_callback_ops_t 是 HAL 层向 Framework 发送异步消息的唯一通道。它由 Camera Service 在 initialize() 时传入,HAL 层必须保存此指针并在合适的线程中调用其函数。

回调函数 触发时机 线程安全要求
process_capture_result HAL 完成一次 Capture Request 处理后 可并发调用,但同一 frame_number 必须有序
notify 发生错误、快门事件、3A 状态变化时 必须线程安全,不能阻塞
// camera3_callback_ops_t 定义
typedef struct camera3_callback_ops {
    void (*process_capture_result)(const struct camera3_callback_ops *,
                                    const camera3_capture_result_t *result);
    void (*notify)(const struct camera3_callback_ops *,
                   const camera3_notify_msg_t *msg);
} camera3_callback_ops_t;
常见陷阱:Vendor 层在实现 process_capture_result 回调时,必须确保 camera3_capture_result_t 中的 output_buffers 数组在回调返回前不会被复用。许多 Vendor 在 buffer 复用逻辑上出现竞争条件,导致 Framework 读到脏数据或崩溃。

下图展示了回调的异步数据流:

camera3_callback_ops_t 异步回调流程 HAL 处理线程 (ISP/3A 完成) callback_ops (保存的指针) Camera Service (接收结果) 回调类型与约束 • process_capture_result:每个 frame_number 必须按顺序回调,但不同 frame 可并发 • notify:必须非阻塞,不能持有 HAL 内部锁调用,否则导致死锁 • 回调返回前,HAL 不能释放 result 中的 buffer 引用

3.3 camera3_stream_t:数据流管道

camera3_stream_t 描述了一条从 HAL 到 Framework 的数据流。它定义了图像的格式、分辨率、使用场景以及 buffer 管理方式。在 configure_streams() 中,Framework 会传入一个 camera3_stream_t 数组,HAL 需要验证并设置 usage、max_buffers 等字段。

字段 方向 说明
stream_type Framework → HAL CAMERA3_STREAM_OUTPUT / INPUT / BIDIRECTIONAL
width / height Framework → HAL 图像分辨率,HAL 可调整(需满足最小要求)
format Framework → HAL 像素格式,如 HAL_PIXEL_FORMAT_YCbCr_420_888
usage HAL → Framework HAL 设置的 buffer 使用标志,如 GRALLOC_USAGE_HW_TEXTURE
max_buffers HAL → Framework HAL 请求的最大 buffer 数量,Framework 据此分配
priv HAL 私有 Vendor 可附加私有数据,如关联的 ISP 通道 ID
// camera3_stream_t 关键字段
typedef struct camera3_stream {
    int         stream_type;    // 输入/输出/双向
    uint32_t    width;
    uint32_t    height;
    int         format;         // 像素格式
    uint32_t    usage;          // Gralloc 使用标志(HAL 设置)
    uint32_t    max_buffers;    // HAL 请求的 buffer 数量
    void        *priv;          // Vendor 私有数据
    // ... 其他字段
} camera3_stream_t;
调试技巧:在 configure_streams() 中,建议打印每个 stream 的 format、width、height 和 usage。许多 Vendor 适配问题源于 usage 设置不当——例如预览流未设置 GRALLOC_USAGE_HW_TEXTURE 导致 SurfaceFlinger 合成失败。

下图展示了多个 stream 在 HAL 中的配置关系:

camera3_stream_t 多流配置示例 Framework 配置请求 Stream 数组 Stream[0] 预览 1920x1080 YCbCr Stream[1] 拍照 4096x3072 JPEG Stream[2] 视频 3840x2160 YCbCr Stream[3] 深度 640x480 DEPTH16 HAL 验证 & 设置 设置 usage 设置 max_buffers 验证 format 分配 ISP 通道 设置 priv 指针 关联硬件资源

3.4 三者协作关系总结

在 HAL3 的运行时模型中,这三个结构体构成了一个稳定的三角关系:

  • camera3_device_t 是入口,通过 ops 接收 Framework 的同步调用(如 configure_streams、process_capture_request)。
  • camera3_callback_ops_t 是出口,HAL 通过它异步返回结果和事件。
  • camera3_stream_t 是数据通道,在 configure_streams 中建立,在每次 process_capture_result 中携带 buffer 返回。
调试检查清单:
✅ camera3_device_t.priv 是否在 open() 时分配,在 close() 时释放?
✅ camera3_callback_ops_t 是否在 initialize() 中保存并增加引用计数?
✅ camera3_stream_t.usage 是否根据 stream_type 和 format 正确设置?
✅ 所有 stream 的 max_buffers 是否满足 ISP 管线的最小深度需求?