本章节思维导图如上。主要讲述了 surafce 测试程序 demo 的第3步中的获取 Buffer,锁定(最关键)并写入 Buffer 的过程。
一 概述
该部分代码是在上一章节中 Surface 测试程序源码的精简版,保存了最关键的流程,如下所示:
#include <cutils/memory.h>
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <android/native_window.h>
using namespace android;
int main(int argc, char** argv)
{
//1 创建surfaceflinger的客户端
sp<SurfaceComposerClient> client = new SurfaceComposerClient();
//2 获取surface
sp<SurfaceControl> surfaceControl = client->createSurface(String8("resize"),
160, 240, PIXEL_FORMAT_RGB_565, 0);
sp<Surface> surface = surfaceControl->getSurface();
//设置layer,layer值越大,显示层越靠前
SurfaceComposerClient::openGlobalTransaction();
surfaceControl->setLayer(100000);
SurfaceComposerClient::closeGlobalTransaction();
//3 获取buffer->锁定buffer->写入buffer->解锁并提交buffer
//这里主要关注:申请Buff 和 提交Buff
ANativeWindow_Buffer outBuffer;
surface->lock(&outBuffer, NULL);
ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height);
surface->unlockAndPost();
//...
return 0;
}
主要的步骤为:
- 获取 SurfaceFlinger(后简称 SF)的客户端,通过 SF 的客户端获取 SurfaceControl,进而获得 Surface
- 通过 SurfaceControl 设置 Layer 层数值(忽略),通过 Surface 获取 Buffer,锁定 Buffer 并写入 Buffer
- 最后提交 Buffer
本章节主要关注获取 Buffer,锁定(最关键)并写入 Buffer 的过程。而获取 Buffer 只是通过ANativeWindow_Buffer 来创建一个 outBuffer 并传递给 Surface 的 lock 方法,写入 Buffer 只是最终使用 memset 向 Buffer 中写入数据。因此最关键也最繁琐的部分是 Surface 的 lock 方法,主要分析整个方法,对应代码为:
status_t Surface::lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
if (mLockedBuffer != 0) {
ALOGE("Surface::lock failed, already locked");
return INVALID_OPERATION;
}
//获取显示器一些信息
if (!mConnectedToCpu) {
int err = Surface::connect(NATIVE_WINDOW_API_CPU);
if (err) {
return err;
}
// we're intending to do software rendering from this point
setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
}
ANativeWindowBuffer* out;
int fenceFd = -1;
//关键点1
status_t err = dequeueBuffer(&out, &fenceFd);
ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
if (err == NO_ERROR) {
sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
const Rect bounds(backBuffer->width, backBuffer->height);
Region newDirtyRegion;
if (inOutDirtyBounds) {
newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
newDirtyRegion.andSelf(bounds);
} else {
newDirtyRegion.set(bounds);
}
// figure out if we can copy the frontbuffer back
const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
const bool canCopyBack = (frontBuffer != 0 &&
backBuffer->width == frontBuffer->width &&
backBuffer->height == frontBuffer->height &&
backBuffer->format == frontBuffer->format);
if (canCopyBack) {
// copy the area that is invalid and not repainted this round
const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
if (!copyback.isEmpty())
copyBlt(backBuffer, frontBuffer, copyback);
} else {
// if we can't copy-back anything, modify the user's dirty
// region to make sure they redraw the whole buffer
newDirtyRegion.set(bounds);
mDirtyRegion.clear();
Mutex::Autolock lock(mMutex);
for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
mSlots[i].dirtyRegion.clear();
}
}
{ // scope for the lock
Mutex::Autolock lock(mMutex);
int backBufferSlot(getSlotFromBufferLocked(backBuffer.get()));
if (backBufferSlot >= 0) {
Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion);
mDirtyRegion.subtract(dirtyRegion);
dirtyRegion = newDirtyRegion;
}
}
mDirtyRegion.orSelf(newDirtyRegion);
if (inOutDirtyBounds) {
*inOutDirtyBounds = newDirtyRegion.getBounds();
}
void* vaddr;
//关键点2
status_t res = backBuffer->lockAsync(
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
newDirtyRegion.bounds(), &vaddr, fenceFd);
if (res != 0) {
err = INVALID_OPERATION;
} else {
mLockedBuffer = backBuffer;
//构造 outbuffer 变量
outBuffer->width = backBuffer->width;
outBuffer->height = backBuffer->height;
outBuffer->stride = backBuffer->stride;
outBuffer->format = backBuffer->format;
outBuffer->bits = vaddr;//mmap映射地址
}
}
return err;
}
二 Surface.dequeueBuffer
Surface 的 dequeueBuffer 方法,代码实现如下:
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
//...
int buf = -1;
sp<Fence> fence;
//生产者,向SurfaceFlinger发出Buffer申请,得到 buffer,一个mslots数组的元素
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero,
reqW, reqH, reqFormat, reqUsage);
//...
if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
//向SF请求并返回fd,然后在APP这边mmap
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
if (result != NO_ERROR) {
mGraphicBufferProducer->cancelBuffer(buf, fence);
return result;
}
}
//...
*buffer = gbuf.get();
return OK;
}
这里关注两个关键方法,mGraphicBufferProducer 的 dequeueBuffer 方法和 mGraphicBufferProducer 的 requestBuffer 方法。
2.1 GraphicBufferProducer.dequeueBuffer
status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
sp<android::Fence> *outFence, bool async,
uint32_t width, uint32_t height, uint32_t format, uint32_t usage) {
//...
{ // Autolock scope
//...
int found;
//得到空闲的slots元素并锁定
status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async,
&found, &returnFlags);
if (status != NO_ERROR) {
return status;
}
//...
} // Autolock scope
//如果需要则重新分配
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
status_t error;
BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
width, height, format, usage, &error));
if (graphicBuffer == NULL) {
BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");
return error;
}
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
mSlots[*outSlot].mFrameNumber = UINT32_MAX;
mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
} // Autolock scope
}
if (attachedByConsumer) {
returnFlags |= BUFFER_NEEDS_REALLOCATION;
}
//...
return returnFlags;
}
这里专注两段代码:waitForFreeSlotThenRelock 方法和 graphicBuffer 的创建。
2.1.1 GraphicBufferProducer.waitForFreeSlotThenRelock
status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller,
bool async, int* found, status_t* returnFlags) const {
bool tryAgain = true;
while (tryAgain) {
if (mCore->mIsAbandoned) {
BQ_LOGE("%s: BufferQueue has been abandoned", caller);
return NO_INIT;
}
//...
// Look for a free buffer to give to the client
*found = BufferQueueCore::INVALID_BUFFER_SLOT;
int dequeuedCount = 0;
int acquiredCount = 0;
for (int s = 0; s < maxBufferCount; ++s) {
switch (mSlots[s].mBufferState) {
case BufferSlot::DEQUEUED:
++dequeuedCount;
break;
case BufferSlot::ACQUIRED:
++acquiredCount;
break;
case BufferSlot::FREE:
// We return the oldest of the free buffers to avoid
// stalling the producer if possible, since the consumer
// may still have pending reads of in-flight buffers
if (*found == BufferQueueCore::INVALID_BUFFER_SLOT ||
mSlots[s].mFrameNumber < mSlots[*found].mFrameNumber) {
*found = s;
}
break;
default:
break;
}
}
//...
} // while (tryAgain)
return NO_ERROR;
}
最为关键的就是上面这段,主要功能是在 mSlots 数组中找到已经 FREE 的空余 Buffer 并通过下标方式返回(下标为上段代码中的 found)
2.1.2 graphicBuffer的创建
在创建 graphicBuffer 时,这里传递了一个参数,是这样一句话:
mCore->mAllocator->createGraphicBuffer(width, height, format, usage, &error)
这里主要是调用了 BufferQueueCore 中的成员变量 mAllocator(IGraphicBufferAlloc类型)的 createGraphicBuffer 方法,这段代码比较简单,最终返回一个 GraphicBuffer 类型的变量,代码如下:
sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h,
PixelFormat format, uint32_t usage, status_t* error) {
sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
status_t err = graphicBuffer->initCheck();
*error = err;
if (err != 0 || graphicBuffer->handle == 0) {
if (err == NO_MEMORY) {
GraphicBuffer::dumpAllocationsToSystemLog();
}
ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "
"failed (%s), handle=%p",
w, h, strerror(-err), graphicBuffer->handle);
return 0;
}
return graphicBuffer;
}
之后我们详细分析下这里 sp graphicBuffer(…) 对应的构造器,代码如下:
GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,
PixelFormat reqFormat, uint32_t reqUsage)
: BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
mInitCheck(NO_ERROR), mId(getUniqueId())
{
width = w;
height = h;
stride = inStride;
format = inFormat;
usage = 0;
handle = NULL;
mInitCheck = initSize(w, h, reqFormat, reqUsage);
}
这里继续分析 initSize,代码如下:
status_t GraphicBuffer::initSize(uint32_t w, uint32_t h, PixelFormat format,
uint32_t reqUsage)
{
//打开 Gralloc 模块
GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
//调用 HAL 模块的 alloc 函数
status_t err = allocator.alloc(w, h, format, reqUsage, &handle, &stride);
if (err == NO_ERROR) {
this->width = w;
this->height = h;
this->format = format;
this->usage = reqUsage;
}
return err;
}
这里主要是调用了 gralloc 模块,获取 allocator 的代码如下:
GraphicBufferAllocator::GraphicBufferAllocator()
: mAllocDev(0)
{
hw_module_t const* module;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
if (err == 0) {
gralloc_open(module, &mAllocDev);
}
}
之后使用 allocator.alloc 来申请内存。代码如下:
status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,
int usage, buffer_handle_t* handle, int32_t* stride)
{
if (!w || !h)
w = h = 1;
// we have a h/w allocator and h/w buffer is requested
status_t err;
err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
if (err == NO_ERROR) {
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
int bpp = bytesPerPixel(format);
if (bpp < 0) {
// probably a HAL custom format. in any case, we don't know
// what its pixel size is.
bpp = 0;
}
alloc_rec_t rec;
rec.w = w;
rec.h = h;
rec.s = *stride;
rec.format = format;
rec.usage = usage;
rec.size = h * stride[0] * bpp;
list.add(*handle, rec);
}
return err;
}
这里调用了 mAllocDev->alloc 方法,再往下就是 HAL 层 Gralloc 模块的调用了,在 Gralloc 模块初始化的时候,代码如下:
int gralloc_device_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
gralloc_context_t *dev;
dev = (gralloc_context_t*)malloc(sizeof(*dev));
/* initialize our state here */
memset(dev, 0, sizeof(*dev));
/* initialize the procs */
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = const_cast<hw_module_t*>(module);
dev->device.common.close = gralloc_close;
dev->device.alloc = gralloc_alloc;
dev->device.free = gralloc_free;
*device = &dev->device.common;
status = 0;
} else {
status = fb_device_open(module, name, device);
}
return status;
}
所以这里的 mAllocDev->alloc 方法 就是 Gralloc 模块对应的 gralloc_alloc 方法,代码如下:
static int gralloc_alloc(alloc_device_t* dev,
int w, int h, int format, int usage,
buffer_handle_t* pHandle, int* pStride)
{
//...
int err;
if (usage & GRALLOC_USAGE_HW_FB) {
err = gralloc_alloc_framebuffer(dev, size, usage, pHandle);
} else {
err = gralloc_alloc_buffer(dev, size, usage, pHandle);
}
//...
*pStride = stride;
return 0;
}
因为是申请 buffer,所以这里选择的是 gralloc_alloc_buffer,继续分析代码,如下所示:
static int gralloc_alloc_buffer(alloc_device_t* dev,
size_t size, int /*usage*/, buffer_handle_t* pHandle)
{
//...
fd = ashmem_create_region("gralloc-buffer", size);
//...
if (err == 0) {
private_handle_t* hnd = new private_handle_t(fd, size, 0);
gralloc_module_t* module = reinterpret_cast<gralloc_module_t*>(
dev->common.module);
err = mapBuffer(module, hnd);
if (err == 0) {
*pHandle = hnd;
}
}
return err;
}
这里主要通过 ashmem 共享内存机制来分配内存 Buffer,得到 fd;同时使用 fd 和 mmap 生成的 Buffer 一同来构造一个 handle。这其中 mmap 生成的地址直接供 SF 使用。
2.2 GraphicBufferProducer.requestBuffer
此时 SF 已经得到了 handle(要申请的 Buffer 的句柄 fd 和 mmap 的首地址的集合)。接下来调用 requestBuffer 使用 binder 机制把 SF 的 handle 传递给 APP(这个分析过程中忽略了 Binder 通信部分的分析,Binder 通信部分详见系列文章链接:专题分纲目录 android 系统核心机制 binder)。BufferQueueProducer 的 requestBuffer 代码实现如下:
status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
Mutex::Autolock lock(mCore->mMutex);
//...
mSlots[slot].mRequestBufferCalled = true;
*buf = mSlots[slot].mGraphicBuffer;
return NO_ERROR;
}
2.3 总结
APP 对应一个 client,一个 SurfaceControl 对应一个 Layer,每个 Surface 都对应一个 mslots 数组(mslots 数组中共有64个元素,每个元素中包含一个 GraphicBuffer 和一个 handle,包含 fd 和 mmap 的映射地址)。Surface 获得 Buffer 的过程如下:
- 首先执行 dequeueBuffer。若 Surface 无 Buffer,则向生产者 producer(GraphicBufferProducer 类对象,最终通过 SF 操作)申请,查看 mslots 有无余项,若有直接返回,若无则向 Gralloc HAL 申请,得到一个 handle(要申请的 Buffer 的句柄 fd 和 mmap 的首地址的集合)
- 其次执行 requestBuffer,APP(Client 端)通过该方法将 SF 获得的 handle 转移到 Client 端的 handle 中
- APP 获得 fd,mmap 获得地址(通过 Gralloc HAL 来执行 mmap),接下来向 Buffer 中写入内容即可
三 GraphicBuffer.lockAsync
status_t GraphicBuffer::lockAsync(uint32_t usage, const Rect& rect, void** vaddr,
int fenceFd)
{
//...
status_t res = getBufferMapper().lockAsync(handle, usage, rect, vaddr, fenceFd);
return res;
}
继续分析 GraphicBufferMapper 的 lockAsync 方法,代码实现如下:
status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,
int usage, const Rect& bounds, void** vaddr, int fenceFd)
{
status_t err;
if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3) {
err = mAllocMod->lockAsync(mAllocMod, handle, usage,
bounds.left, bounds.top, bounds.width(), bounds.height(),
vaddr, fenceFd);
} else {
sync_wait(fenceFd, -1);
close(fenceFd);
err = mAllocMod->lock(mAllocMod, handle, usage,
bounds.left, bounds.top, bounds.width(), bounds.height(),
vaddr);
}
return err;
}
这里继续分析会进入到 HAL 层,对应的是 Gralloc 模块的 gralloc_lock 函数,代码实现如下:
int gralloc_lock(gralloc_module_t const* /*module*/,
buffer_handle_t handle, int /*usage*/,
int /*l*/, int /*t*/, int /*w*/, int /*h*/,
void** vaddr)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
private_handle_t* hnd = (private_handle_t*)handle;
*vaddr = (void*)hnd->base;
return 0;
}
这里主要是将 handle->base 赋值给 backBuffer->lockAsync 的参数 vaddr,这个同样也是 APP 中使用 mmap 映射的地址。最后会通过 outBuffer->bits = vaddr 这个赋值操作用 backBuffer 的成员变量初始化 outBuffer。