該小節我們從源代碼上分析,應用程式申請Buffer的調用過程,下面是一個從應用程式開始的流程圖:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIwczX0xiRGZkRGZ0Xy9GbvNGL2EzXlpXazxSP9EVTyMmeNhXQ61EM4wmYwhGWhxGZzwEMW1mY1RzRapnTtxkb5ckYplTeMZTTINGMShUYfRHelRHLwEzX39GZhh2css2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xyayFWbyVGdhd3LcV2Zh1Wa9M3clN2byBXLzN3btg3PnBnauMTMyATM1gDM5IzMwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
應用程式在調用surface->lock(&outBuffer,NULL);函數的時候,會發起Surface::dequeueBuffer()的操作,進入調用:
/*代理端的生産者*/
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,reqWidth, reqHeight, reqFormat, reqUsage);
發起一個遠端調用,該函數會查詢SurfaceFlinger邊的mSlots,輸出結果放入buf中,他得到的是數組mSlots的一個下标,表示已經配置設定了一個mSlots的下标。那麼這個遠端調用會導緻那個函數被調用呢?
進入IGraphicBufferProducer.cpp檔案,查找到class BpGraphicBufferProducer (代理類),在找到其中的dequeueBuffer:
virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, uint32_t width,uint32_t height, PixelFormat format, uint32_t usage) {
/*建構資料*/
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeUint32(width);
data.writeUint32(height);
data.writeInt32(static_cast<int32_t>(format));
data.writeUint32(usage);
/*發起遠端調用,到最後調用本檔案中的status_t BnGraphicBufferProducer::onTransact方法*/
status_t result = remote()->transact(DEQUEUE_BUFFER, data, &reply);
其中上的所說的onTransact函數如下:
status_t BnGraphicBufferProducer::onTransact(
case DEQUEUE_BUFFER: {
/*此處的dequeueBuffer由他的派生類BufferQueueProducer實作*/
int result = dequeueBuffer(&buf, &fence, width, height, format,usage);
在BufferQueueProducer.cpp檔案中:
status_t BufferQueueProducer::dequeueBuffer(int *outSlot,sp<android::Fence> *outFence, uint32_t width, uint32_t height,PixelFormat format, uint32_t usage) {
/*等待空閑的Slot,得到以後把他鎖定*/
status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue,&found);
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
/*如果GraphicBuffer 中擷取的buffer是空的,或者參數和申請的參數不一樣*/
if ((buffer == NULL) ||buffer->needsReallocation(width, height, format, usage))
/*标記為需要重新配置設定*/
returnFlags |= BUFFER_NEEDS_REALLOCATION;
/*如果需要重新配置設定*/
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
/*重新配置設定*/
sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(width, height, format, usage,{mConsumerName.string(), mConsumerName.size()}, &error));
現在我們詳細的分析一下graphicBuffer,看看其是怎麼配置設定buffer的。之前的小節我們提到過,生産者和消費者指向同一個mCore(BufferQueueCore類),mAllocator(GraphicBufferAlloc類)。
進入GraphicBufferAlloc.cpp,檢視其createGraphicBuffer函數:
sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width,uint32_t height, PixelFormat format, uint32_t usage,std::string requestorName, status_t* error) {
sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(width, height, format, usage, std::move(requestorName)));
進入GraphicBuffer.cpp檔案,檢視其構造函數:
GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,PixelFormat inFormat, uint32_t inUsage, std::string requestorName): BASE(),mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),mInitCheck(NO_ERROR),mId(getUniqueId()), mGenerationNumber(0){
mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage,std::move(requestorName));
GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
status_t err = allocator.allocate(inWidth, inHeight, inFormat,inUsage,&handle, &outStride, mId, std::move(requestorName));
我們猜測一下initSize會調用gralloc HAL配置設定buffer,那麼肯定是在GraphicBufferAllocator的構造函數中打開HAL了。進入GraphicBufferAllocator的構造函數:
可以知道,其繼承于Loader與mDevice,其中Loader的構造函數如下:
Loader::Loader()
: mDevice(nullptr)
{
hw_module_t const* module;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
uint8_t majorVersion = (module->module_api_version >> 8) & 0xFF;
uint8_t minorVersion = module->module_api_version & 0xFF;
gralloc1_device_t* device = nullptr;
if (majorVersion == 1) {
gralloc1_open(module, &device);
} else {
if (!mAdapter) {
mAdapter = std::make_unique<Gralloc1On0Adapter>(module);
}
device = mAdapter->getDevice();
}
mDevice = std::make_unique<Gralloc1::Device>(device);
}
可以看到,與我們猜測的一緻。下面我們在來分析:
GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
status_t err = allocator.allocate(inWidth, inHeight, inFormat,inUsage,&handle, &outStride, mId, std::move(requestorName));
中的allocator.allocate:
/*通過Ashmem配置設定buf,得到fd,使用fd構造handle,并且memap,這邊memp得到的虛拟位址隻是給SurfaceFlinger程序使用*/
status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height,PixelFormat format, uint32_t usage, buffer_handle_t* handle,uint32_t* stride, uint64_t graphicBufferId, std::string requestorName)
auto descriptor = mDevice->createDescriptor();
auto error = descriptor->setDimensions(width, height);
error = descriptor->setFormat(static_cast<android_pixel_format_t>(format));
error = descriptor->setProducerUsage()
error = descriptor->setConsumerUsage(
在SurfaceFlinger生産者roducer.cpp中包含了mCore與mslots[],配置設定記憶體就是標明空餘的mslots,然後對其進行構造。
打開生産者,BufferQueueProducer.h,可以找到
/*typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];*/
BufferQueueDefs::SlotsType& mSlots;
可以知道mSlots是一個SlotsType的引用,BufferSlot定義如下(主要成員):
struct BufferSlot {
sp<GraphicBuffer> mGraphicBuffer;
GraphicBuffer中存在函數initSize():
mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage,std::move(requestorName));
GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
status_t err = allocator.allocate(inWidth, inHeight, inFormat,inUsage,&handle, &outStride, mId, std::move(requestorName));
可以知道GraphicBuffer包括了handle,handle中至少包括了檔案句柄,以及base。與之對應在我們應用程式的Surface也尊在mslots[],其中的BufferSlot中的GraohicBuffer也包含了handle,并且handle中也存在fd與base。
現在我們分析了SurfaceFlinger如何建立buffer,下小節我們繼續分析,分析其如何傳遞回去給我們編寫的應用程式。