2. 内存分配策略:Gralloc分配器原理、BufferQueue机制、IMapper接口详解
在Camera HAL3系统中,Buffer内存分配是决定整体性能与功耗的关键环节。本章深入剖析Android图形栈中三大核心组件:Gralloc分配器、BufferQueue机制以及IMapper接口,揭示它们如何协同工作,为Camera HAL3提供高效、低延迟的内存分配与流转能力。
2.1 Gralloc分配器原理
Gralloc(Graphics Allocation)是Android系统中负责图形缓冲区分配与管理的硬件抽象层模块。它直接与硬件驱动交互,为Camera、Display、Video等组件提供物理连续或非连续的帧缓冲区。
2.1.1 Gralloc架构层次
Gralloc在Android系统中的位置如下图所示,它位于应用框架层与内核驱动之间,通过HIDL接口向上提供服务。
2.1.2 核心分配流程
Gralloc分配器的工作流程可概括为以下步骤:
- 描述需求:调用方(如Camera HAL3)通过
allocate接口传入Buffer描述符,包括宽度、高度、格式、使用标志(Usage Flags)。 - 策略匹配:Gralloc根据Usage Flags选择最佳内存类型(如CPU访问、GPU纹理、显示扫描输出、相机预览等)。
- 驱动分配:通过ION或DMA-BUF分配物理内存,返回文件描述符(fd)和缓冲区句柄。
- 元数据封装:将分配信息(大小、偏移、Stride、格式等)封装到
BufferDescriptor中返回。 - 缓存同步:分配完成后,通过
sync操作确保缓存一致性。
2.1.3 Usage Flags 分类
| Flag 类别 | 典型值 | 用途说明 |
|---|---|---|
| CPU 读 | CPU_READ_OFTEN | CPU频繁读取,如YUV后处理 |
| CPU 写 | CPU_WRITE_OFTEN | CPU频繁写入,如编码器输入 |
| GPU 纹理 | GPU_TEXTURE | GPU采样纹理,如滤镜渲染 |
| GPU 渲染目标 | GPU_RENDER_TARGET | GPU渲染输出,如SurfaceFlinger合成 |
| 显示 | COMPOSER_OVERLAY / COMPOSER_CLIENT | 显示合成器直接使用 |
| 视频编码 | VIDEO_ENCODER | 硬件编码器输入,要求物理连续 |
| 相机 | CAMERA_OUTPUT / CAMERA_INPUT | Camera HAL3 输出/输入缓冲区 |
CAMERA_OUTPUT 标志,避免与 GPU/CPU 标志混用,以减少不必要的缓存同步开销。对于 YUV 格式,建议使用 CPU_READ_OFTEN | CAMERA_OUTPUT 组合。
2.2 BufferQueue机制
BufferQueue是Android图形系统中用于跨进程传递图形缓冲区的生产者-消费者模型。在Camera HAL3中,BufferQueue连接了Camera HAL3(生产者)与CameraService/应用(消费者),实现高效的零拷贝缓冲区流转。
2.2.1 BufferQueue核心组件
2.2.2 缓冲区状态机
BufferQueue中的每个缓冲区(BufferSlot)都遵循严格的状态转换:
| 状态 | 说明 | 所有者 |
|---|---|---|
| FREE | 空闲状态,缓冲区可被生产者获取 | BufferQueue |
| DEQUEUED | 生产者已获取,正在填充数据 | 生产者 |
| QUEUED | 生产者已提交,等待消费者处理 | BufferQueue |
| ACQUIRED | 消费者已获取,正在处理数据 | 消费者 |
2.2.3 Camera HAL3中的BufferQueue配置
Camera HAL3通过ICameraDeviceSession::configureStreams配置BufferQueue参数:
// 典型配置示例
struct Stream {
uint32_t stream_id;
uint32_t width; // 1920
uint32_t height; // 1080
int32_t format; // HAL_PIXEL_FORMAT_YCbCr_420_888
uint32_t usage; // GRALLOC_USAGE_CAMERA_OUTPUT | GRALLOC_USAGE_CPU_READ_OFTEN
uint32_t max_buffers; // 建议值:4~8
int32_t rotation; // 0
int32_t data_space; // HAL_DATASPACE_V0_JFIF
};
max_buffers 设置过小(如2)会导致生产者频繁等待空闲缓冲区,造成帧率抖动;设置过大(如16)则会浪费内存。Camera HAL3 建议根据帧率与处理延迟动态调整,典型值为4~8。
2.3 IMapper接口详解
IMapper是Android图形栈中负责缓冲区内存映射与缓存同步的HIDL接口。它提供了将已分配的Gralloc缓冲区映射到CPU地址空间、以及管理缓存一致性的能力。
2.3.1 IMapper核心方法
| 方法 | 功能描述 | Camera HAL3 使用场景 |
|---|---|---|
importBuffer |
导入一个缓冲区句柄,创建本地映射 | 从CameraService接收缓冲区 |
freeBuffer |
释放缓冲区本地映射 | 流关闭时清理资源 |
lock |
锁定缓冲区,获取CPU可访问的地址 | YUV后处理、人脸检测 |
unlock |
解锁缓冲区,释放CPU访问 | 处理完成后交还控制权 |
flushLockedBuffer |
刷新缓存,确保数据一致性 | CPU写入后通知GPU/显示 |
getTransportSize |
获取缓冲区传输所需大小 | 跨进程传输优化 |
2.3.2 缓存同步模型
IMapper通过lock/unlock操作管理CPU与硬件之间的缓存一致性。Camera HAL3在使用缓冲区时必须遵循以下同步规则:
2.3.3 内存映射优化策略
Camera HAL3在使用IMapper时,以下优化策略可显著提升性能:
- 延迟映射:仅在需要CPU访问时才调用
lock,避免提前映射浪费地址空间。 - 批量解锁:多个缓冲区处理完成后,统一调用
unlock减少HIDL调用次数。 - 缓存刷新控制:使用
flushLockedBuffer替代unlock+lock组合,减少缓存刷新开销。 - 传输大小优化:通过
getTransportSize获取实际传输大小,避免跨进程传输整个缓冲区。
lock() → memcpy/memset → flushLockedBuffer() → unlock(),确保CPU写入对硬件可见。
2.4 三组件协同工作流
Gralloc、BufferQueue、IMapper三者协同完成Camera HAL3的缓冲区生命周期管理:
- 分配阶段:CameraService通过Gralloc分配缓冲区,返回句柄。
- 导入阶段:Camera HAL3通过IMapper的
importBuffer导入句柄,建立本地映射。 - 流转阶段:通过BufferQueue的
dequeueBuffer/queueBuffer实现生产者-消费者流转。 - 访问阶段:通过IMapper的
lock/unlock实现CPU与硬件的缓存同步。 - 释放阶段:流关闭时,通过IMapper的
freeBuffer和Gralloc的free释放内存。