3. HAL 核心数据结构解析:内存布局与生命周期管理
在 Camera HAL 适配工作中,数据结构是驱动框架与硬件交互的“契约”。camera_metadata_t、camera3_stream_t 和 camera3_capture_request_t 是三个最核心的结构体,它们的内存布局直接决定了跨厂商兼容性,而生命周期管理则是避免内存泄漏和野指针的关键。
核心观点: 理解这三个结构体的内存布局,是解决多厂商平台兼容问题的第一步。错误的布局假设会导致数据错位、崩溃或性能下降。
3.1 camera_metadata_t:动态元数据的序列化容器
camera_metadata_t 是 Android Camera 框架中用于传递控制参数和结果元数据的核心结构。它采用紧凑的序列化布局,支持动态增长,但不同厂商的 HAL 实现可能对元数据条目顺序有不同假设。
3.1.1 内存布局
该结构体在内存中分为三个连续区域:
- 头部(Header): 包含总大小、条目数、剩余空间等元信息。
- 条目数组(Entries): 每个条目包含 Tag、类型、计数和数据偏移量。
- 数据区(Data): 实际存储的元数据值(如字符串、数组、结构体)。
3.1.2 生命周期管理
| 阶段 | 操作 | 注意事项 |
|---|---|---|
| 分配 | allocate_camera_metadata() |
预估条目数和数据大小,避免频繁 realloc。 |
| 添加/更新 | add_camera_metadata_entry() |
检查返回值,确保数据区未满。 |
| 查找 | find_camera_metadata_entry() |
返回的是条目索引,不是直接指针。 |
| 释放 | free_camera_metadata() |
必须由分配者释放,避免 double-free。 |
适配技巧: 在跨厂商平台适配时,不要假设元数据条目的顺序。始终使用 Tag 进行查找,而不是通过索引访问。某些厂商的 HAL 可能会在元数据中插入私有 Tag,导致索引偏移。
3.2 camera3_stream_t:数据流的配置与绑定
camera3_stream_t 定义了从 HAL 到框架的单个图像流(如预览、拍照、视频)的属性和缓冲区管理方式。它是 camera3_stream_configuration_t 数组中的元素,在 configure_streams() 调用中配置。
3.2.1 关键字段与内存布局
3.2.2 生命周期与所有权
- 创建: 框架在
configure_streams()调用前分配camera3_stream_t数组。 - 配置: HAL 在
configure_streams()中读取输入字段,并设置max_buffers和priv。 - 使用: 在
process_capture_request()中,通过camera3_stream_buffer_t引用。 - 销毁: 框架在
configure_streams()再次调用或设备关闭时释放。
常见陷阱: 某些厂商的 HAL 会在
priv 中存储硬件特定的 DMA 缓冲区句柄。在适配时,必须确保 priv 的清理逻辑与厂商的硬件资源管理一致,否则会导致内存泄漏或 DMA 缓冲区泄漏。
3.3 camera3_capture_request_t:一次捕获的完整描述
该结构体封装了单次捕获请求的所有信息,包括目标流、输入缓冲区、元数据和设置。它是 HAL 处理 pipeline 的输入单元。
3.3.1 结构体组成
| 字段 | 类型 | 说明 |
|---|---|---|
frame_number |
uint32_t | 帧序号,单调递增,用于追踪。 |
settings |
const camera_metadata_t* | 本次捕获的元数据设置(AE/AWB/AF 等)。 |
input_buffer |
const camera3_stream_buffer_t* | 输入缓冲区(用于 reprocessing)。 |
num_output_buffers |
uint32_t | 输出缓冲区数量。 |
output_buffers |
const camera3_stream_buffer_t* | 输出缓冲区数组。 |
num_physcam_settings |
uint32_t | 物理相机设置数量(多摄)。 |
physcam_settings |
const camera_metadata_t* | 物理相机设置数组。 |
3.3.2 生命周期与所有权规则
3.3.3 多摄场景下的物理相机设置
在多摄像头 HAL 中,physcam_settings 字段允许为每个物理相机指定独立的元数据。适配时需注意:
- 索引对齐:
physcam_settings数组的索引必须与physical_camera_ids的顺序一致。 - 生命周期: 物理相机设置的生命周期与主 request 的 settings 相同。
- 兼容性: 某些旧版 HAL 可能不支持
physcam_settings,需要检查 HAL 版本。
实战案例: 在适配某厂商的 MTK 平台时,发现其 HAL 在
process_capture_request() 中直接修改了 settings 指向的元数据内容,违反了 HAL 规范。解决方案是在 HAL 层做一次深度拷贝,避免影响框架侧的元数据。
3.4 数据结构关系总览
3.5 适配避坑指南
| 结构体 | 常见问题 | 解决方案 |
|---|---|---|
| camera_metadata_t | 厂商私有 Tag 导致查找失败 | 使用 find_camera_metadata_entry() 并检查返回值,不要假设 Tag 存在。 |
| camera3_stream_t | priv 指针未正确初始化或释放 | 在 configure_streams() 中统一管理 priv 的生命周期。 |
| camera3_capture_request_t | output_buffers 未全部返回 | 在 HAL 的 pipeline 中建立缓冲区追踪表,确保每个 buffer 都有对应的 result。 |
| 跨厂商 | 结构体对齐方式不同(如 32-bit vs 64-bit) | 使用 offsetof 和 sizeof 进行编译时检查,避免硬编码偏移。 |
总结: 掌握这三个结构体的内存布局和生命周期,是编写健壮、可移植 Camera HAL 的基础。在适配过程中,始终以规范文档为准,不要依赖特定厂商的实现细节。