1. 从“共享画板”说起:为什么我们需要Gralloc?
想象一下,你和你的朋友要一起完成一幅巨大的数字壁画。你负责用CPU这支“精细的铅笔”勾勒线条和计算布局,而你的朋友则用GPU这块“高性能喷枪”来渲染绚丽的色彩和光影。你们俩需要在一块共用的“画板”上协同工作。这块“画板”就是图形缓冲区(Graphic Buffer),而负责准备、分配和管理这块“画板”的“后勤总管”,就是Android系统中的Gralloc(Graphics Memory Allocator)。
在Android 14及以后的版本里,这位“后勤总管”进行了一次重要的职责分工和升级。以前,它可能身兼数职,从找一块合适的“画板”(分配内存)到决定谁可以动笔、何时需要同步(访问管理)都一手包办。现在,它变得更专业、更模块化了,分成了两个核心部门:Allocator HAL 3.x 和 Mapper HAL 4.x。简单来说,Allocator是“仓库管理员”,专门负责从系统内存这个“大仓库”里,划出大小、规格合适的“空白画板”(Buffer)给你;而Mapper则是“画室助理”,当你拿到“画板”后,它负责帮你把画板固定好(映射到进程地址空间)、递给你画笔(提供CPU/GPU访问指针)、并在你和朋友交替作画时,确保双方看到的都是最新内容(缓存一致性管理)。
这种分工协作的设计,正是Android图形栈走向现代化、高性能和可维护性的关键一步。对于应用开发者、系统工程师,甚至是硬件驱动开发者来说,理解这套新机制,不仅能帮你更好地调试图形性能问题,还能让你在开发需要直接操作图像数据的应用(比如相机、视频编辑、AR/VR、游戏引擎)时,更加得心应手,避免掉进“内存访问错误”、“画面撕裂”或“性能瓶颈”这些坑里。接下来,我们就一起深入这个“画室”,看看这两位“管理员”和“助理”具体是怎么工作的。
2. Allocator HAL 3.x:专业的“内存仓库管理员”
Allocator HAL,顾名思义,它的核心工作就是分配。在Android的HAL(硬件抽象层)架构中,它位于android.hardware.graphics.allocator@3.0这个接口之下。它的存在,是为了将内存分配这个与硬件紧密相关的操作抽象出来。不同的设备(比如用高通、联发科或三星芯片的手机),其物理内存的布局、特性可能不同,但通过统一的Allocator HAL接口,上层应用和系统服务就能以一致的方式申请内存,而不用关心底层是UMA(统一内存架构)还是离散内存。
2.1 核心接口:allocate() 与 dumpDebugInfo()
Allocator HAL 3.x 的核心接口非常简洁,主要就是两个函数:
-
IAllocator::allocate():这是它的“主营业务”。你告诉它你需要多少块“画板”、每块“画板”的规格要求是什么(比如宽度、高度、像素格式、用途标志),它就会尽力为你准备好,并返回一个或多个“提货单”(即buffer_handle_t,一个指向不透明缓冲区句柄的指针)。 -
IAllocator::dumpDebugInfo():这是它的“管理后台”。当系统出现图形内存相关的疑难杂症时(比如怀疑内存泄漏、碎片化),调用这个接口可以让Allocator吐出一堆内部状态信息,对于调试来说是无价之宝。
让我们看一个更贴近真实场景的代码示例。假设你正在开发一个相机应用,需要分配一个用于预览的YUV图像缓冲区:
#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
#include <android/hardware/graphics/mapper/3.0/IMapper.h>
#include <log/log.h>
using namespace android::hardware::graphics::allocator::V3_0;
using namespace android::hardware::graphics::mapper::V3_0;
using android::hardware::hidl_vec;
sp<IAllocator> allocator = IAllocator::getService();
if (allocator == nullptr) {
ALOGE("Failed to get allocator service!");
return;
}
// 定义缓冲区的描述信息
BufferDescriptor descriptor;
IMapper::BufferDescriptorInfo descInfo = {
.width = 1920,
.height = 1080,
.layerCount = 1,
.format = PixelFormat::YCBCR_420_888, // 常见的相机预览格式
.usage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN) |
static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN) |
static_cast<uint64_t>(BufferUsage::CAMERA_OUTPUT),
};
// 首先需要通过 Mapper 来创建描述符(这体现了协同)
sp<IMapper> mapper = IMapper::getService();
mapper->createDescriptor(descInfo, [&](Error error, const BufferDescriptor& desc) {
if (error != Error::NONE) {
ALOGE("Failed to create descriptor: %d", static_cast<int>(error));
return;
}
descriptor = desc;
});
// 现在,使用 Allocat


943

被折叠的 条评论
为什么被折叠?



