[Android] GraphicBuffer之Framework層
一 前言
GraphicBuffer 是 SurfaceFlinger 中一塊重要的內(nèi)容, 它涉及到了我們應(yīng)用程序的數(shù)據(jù)是如何和SurfaceFlinger進(jìn)行傳遞的雌团。
在介紹 GraphicBuffer 之前壮吩,我們先提出這樣一個(gè)問(wèn)題:我們應(yīng)用程序的界面數(shù)據(jù)甩鳄,是如何傳遞給 SurfaceFlinger 進(jìn)行合成和顯示的代赁。是 Binder 嗎掩宜?顯然不是戚扳,Binder 傳遞不了這么大的數(shù)據(jù)。那么是共享內(nèi)存嗎魁巩,早期的界面數(shù)據(jù)的確是通過(guò)這種方式傳遞的急灭,但是那已經(jīng)是很早之前了。
前面我們介紹了SurfaceFlinger中的生產(chǎn)者和消費(fèi)者模型, 在生產(chǎn)者申請(qǐng) buffer 的時(shí)候, 如果拿到的 Slot 沒(méi)有和 GraphicBuffer 進(jìn)行綁定, 那么就會(huì)先創(chuàng)建一個(gè) GraphicBuffer , 然后進(jìn)行綁定
從這一篇開(kāi)始谷遂,我們就來(lái)探究 GraphicBuffer 的工作原理葬馋。
1.1 GraphicBuffer 的創(chuàng)建
在前面介紹 dequeueBuffer 申請(qǐng)緩沖區(qū)的時(shí)候, 我們還說(shuō)了一種邏輯, 那就是從 BufferQueue 中拿到的 slot 沒(méi)有關(guān)聯(lián)的 GraphicBuffer , 那么這種情況下還需要單獨(dú)創(chuàng)建 GraphicBuffer ,這里我們就來(lái)看看 GraphicBuffer 的創(chuàng)建邏輯
[frameworks/native/libs/gui/BufferQueueProducer.cpp]
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
// 如果拿到的緩沖區(qū)的 flag 為 BUFFER_NEEDS_REALLOCATION ,就創(chuàng)建一個(gè) GraphicBuffer
sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
width, height, format, BQ_LAYER_COUNT, usage,
{mConsumerName.string(), mConsumerName.size()});
}
在之前解讀 BufferQueue的時(shí)候介紹了 BufferQueue 中的生產(chǎn)者和消費(fèi)者,以及最重要的四個(gè)函數(shù)肾扰,其中的生產(chǎn)者在生成內(nèi)容的時(shí)候畴嘶,就會(huì)有這么一個(gè)過(guò)程;
- 生產(chǎn)者向 BufferQueue 中申請(qǐng) slot(緩沖槽)
- 生產(chǎn)者拿到 slot集晚,但是 slot 并沒(méi)有關(guān)聯(lián)對(duì)應(yīng)的 GraphicBuffer(緩沖區(qū))
- 生產(chǎn)者創(chuàng)建一個(gè)緩沖區(qū)窗悯,并將它與緩沖槽相關(guān)聯(lián)。
如上代碼偷拔,就是步驟2中的一個(gè)片段蒋院。接下來(lái),我們看 GraphicBuffer 創(chuàng)建時(shí)的具體流程莲绰。
1.2 GraphicBuffer的構(gòu)造函數(shù)
[frameworks/native/libs/ui/GraphicBuffer.cpp]
GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inUsage, std::string requestorName)
: GraphicBuffer(inWidth, inHeight, inFormat, 1, static_cast<uint64_t>(inUsage), requestorName)
{
}
GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
uint32_t inLayerCount, uint64_t inUsage, std::string requestorName)
: GraphicBuffer() {
mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount, inUsage,
std::move(requestorName));
}
GraphicBuffer 的構(gòu)造函數(shù)非常簡(jiǎn)單, 它只是調(diào)用了一個(gè)初始化函數(shù) initWithSize悦污。
1.3 GraphicBuffer::initWithSize
status_t GraphicBuffer::initWithSize(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage,
std::string requestorName) {
// 獲取一個(gè) GraphicBufferAllocator 對(duì)象, 這個(gè)對(duì)象是一個(gè)單例
// GraphicBufferAllocator 主要負(fù)責(zé) GraphicBuffer 的內(nèi)存分配
GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
uint32_t outStride = 0;
// 分配一塊制定寬高的 GraphicBuffer
status_t err = allocator.allocate(inWidth, inHeight, inFormat, inLayerCount,
inUsage, &handle, &outStride, mId,
std::move(requestorName));
if (err == NO_ERROR) {
// 通過(guò) GraphicBufferMapper 將這塊 GraphicBuffer 的參數(shù)記錄下來(lái)
// GraphicBufferMapper 負(fù)責(zé)的是 GraphicBuffer 的內(nèi)存映射
mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
// 初始化參數(shù)
width = static_cast<int>(inWidth);
height = static_cast<int>(inHeight);
format = inFormat;
layerCount = inLayerCount;
usage = inUsage;
usage_deprecated = int(usage);
stride = static_cast<int>(outStride);
}
return err;
}
這里的初始化函數(shù)中,創(chuàng)建了一個(gè) GraphicBufferAllocator 對(duì)象钉蒲,這個(gè)我們申請(qǐng)的 GraphicBuffer 內(nèi)存,其實(shí)是通過(guò) GraphicBufferAllocator 這個(gè)對(duì)象進(jìn)行分配的彻坛。
從這里開(kāi)始顷啼,就需要注意了,因?yàn)樵趧?chuàng)建 GraphicBuffer 并分配內(nèi)存的時(shí)候昌屉,會(huì)通過(guò)一個(gè)個(gè)對(duì)象不斷的調(diào)用钙蒙,從 Framework 層一直到最后的硬件層。
首先我們來(lái)看 GraphicBufferAllocator 這個(gè)類(lèi)间驮。
二 GraphicBufferAllocator
GraphicBufferAllocator 它是一個(gè)單例躬厌,外部使用時(shí)可以通過(guò)它來(lái)為 GraphicBuffer 來(lái)分配內(nèi)存,Android 系統(tǒng)是為了屏蔽不同硬件平臺(tái)的差異性竞帽,所以使用它來(lái)為外部提供一個(gè)統(tǒng)一的接口扛施。
2.1 GraphicBufferAllocator::allocate
GraphicBufferAllocator::allocate 函數(shù)就是分配內(nèi)存的具體函數(shù), 它又通過(guò)調(diào)用一個(gè) mAllocator 對(duì)象的 allocate 來(lái)分配內(nèi)存, 這個(gè) mAllocator 是一個(gè) GrallocAllocator 的指針對(duì)象。GrallocAllocator 定義在frameworks/native/libs/ui/include/ui/Gralloc.h
屹篓,它有幾個(gè)實(shí)現(xiàn)分別是 定義在 Gralloc3.h 中的 Gralloc3Allocator , 和定義在 Gralloc2.h 中的 Gralloc2Allocator
[frameworks/native/libs/ui/GraphicBufferAllocator.cpp]
status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height,
PixelFormat format, uint32_t layerCount, uint64_t usage,
buffer_handle_t* handle, uint32_t* stride,
uint64_t /*graphicBufferId*/, std::string requestorName) {
// 如果寬或者高為0, 則將寬高設(shè)置為1
if (!width || !height)
width = height = 1;
// 如果圖層的數(shù)量少于1, 則將圖層的數(shù)量設(shè)置為1
if (layerCount < 1)
layerCount = 1;
// 移除調(diào)用者中的無(wú)效位
usage &= ~static_cast<uint64_t>((1 << 10) | (1 << 13));
// 分配內(nèi)存疙渣,使用的是 GrallocAllocator 指針,根據(jù)不同的版本有哦不同的實(shí)現(xiàn)堆巧,
// 這里我們假設(shè)它的實(shí)現(xiàn)是 Gralloc3Allocator
status_t error =
mAllocator->allocate(width, height, format, layerCount, usage, 1, stride, handle);
if (error == NO_ERROR) {
// 初始化參數(shù)
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
uint32_t bpp = bytesPerPixel(format);
alloc_rec_t rec;
rec.width = width;
rec.height = height;
rec.stride = *stride;
rec.format = format;
rec.layerCount = layerCount;
rec.usage = usage;
rec.size = static_cast<size_t>(height * (*stride) * bpp);
rec.requestorName = std::move(requestorName);
list.add(*handle, rec);
return NO_ERROR;
} else {
return NO_MEMORY;
}
}
GraphicBufferAllocator 有兩個(gè)實(shí)現(xiàn)類(lèi), 我們來(lái)看它其中的一個(gè)實(shí)現(xiàn)類(lèi) Gralloc3Allocator
2.2 Gralloc3Allocator
GrallocAllocator 有多個(gè)實(shí)現(xiàn)版本妄荔,Gralloc3Allocator 就是實(shí)現(xiàn) Gralloc3 的版本
2.2.1 Gralloc3Allocator的定義
在 Gralloc3Allocator 定義的構(gòu)造函數(shù)中泼菌,只有一個(gè)參數(shù),就是 Gralloc3Mapper啦租。這個(gè)參數(shù)在后面做內(nèi)存分配的時(shí)候會(huì)用上哗伯,接著來(lái)看它構(gòu)造函數(shù)具體的實(shí)現(xiàn)
[frameworks/native/libs/ui/include/ui/Gralloc3.h]
class Gralloc3Allocator : public GrallocAllocator {
public:
// Gralloc3Allocator 的構(gòu)造函數(shù)需要傳遞一個(gè) Gralloc3Mapper,因?yàn)榉峙鋬?nèi)存依賴映射器 mapper
Gralloc3Allocator(const Gralloc3Mapper& mapper);
bool isLoaded() const override;
std::string dumpDebugInfo() const override;
// 它只有一個(gè)函數(shù)篷角,就是分配內(nèi)存
status_t allocate(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount,
uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
buffer_handle_t* outBufferHandles) const override;
private:
const Gralloc3Mapper& mMapper;
// 真正實(shí)現(xiàn)分配內(nèi)存的則是 mAllocator焊刹,這是通過(guò) HAL 調(diào)用。
// HAL 層調(diào)用使用的通信方式就是 HIDL内地,其實(shí)和我們使用的 AIDL 是一樣的原理伴澄。
sp<hardware::graphics::allocator::V3_0::IAllocator> mAllocator;
};
2.2.2 Gralloc3Allocator的構(gòu)造函數(shù)
[frameworks/native/libs/ui/Gralloc3.cpp]
Gralloc3Allocator::Gralloc3Allocator(const Gralloc3Mapper& mapper) : mMapper(mapper) {
mAllocator = IAllocator::getService();
if (mAllocator == nullptr) {
return;
}
}
Gralloc3Allocator 的構(gòu)造函數(shù)會(huì)傳遞一個(gè) Gralloc3Mapper 作為參數(shù), 并將它賦值給 mMapper , 當(dāng)然, 其中最關(guān)鍵的還是通過(guò)一個(gè) IAllocator::getService() 獲取到了一個(gè) mAllocator 對(duì)象, 這個(gè) mAllocator 對(duì)象就是 hardware::graphics::allocator::V3_0::IAllocator 的指針。
看到這里阱缓,我們大概就能猜到非凌,這和我們常見(jiàn)的進(jìn)程間獲取服務(wù)的方式很相似,在我們?cè)趹?yīng)用中使用系統(tǒng)服務(wù)時(shí)荆针,也是先通過(guò) getService 拿到注冊(cè)好的服務(wù)敞嗡,然后再通過(guò)這個(gè) Bp 對(duì)象,調(diào)用對(duì)應(yīng)的服務(wù)函數(shù)航背。
2.2.3 Gralloc3Allocator的allocate
然后我們看 Gralloc3Allocator 分配內(nèi)存的函數(shù)
status_t Gralloc3Allocator::allocate(uint32_t width, uint32_t height, android::PixelFormat format,
uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
uint32_t* outStride, buffer_handle_t* outBufferHandles) const {
// 定義一個(gè)緩沖區(qū)的描述信息 descriptorInfo , 并將緩沖區(qū)的相關(guān)參數(shù)都封裝到這個(gè)描述信息 descriptorInfo 中
IMapper::BufferDescriptorInfo descriptorInfo;
sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
BufferDescriptor descriptor;
// 通過(guò)之前構(gòu)造函數(shù)中的 mMapper 對(duì)象來(lái)創(chuàng)建一個(gè)描述信息
status_t error = mMapper.createDescriptor(static_cast<void*>(&descriptorInfo),
static_cast<void*>(&descriptor));
if (error != NO_ERROR) {
return error;
}
// 通過(guò) mAllocator 這個(gè) Bp 對(duì)象來(lái)調(diào)用對(duì)應(yīng)的系統(tǒng)服務(wù)
// 調(diào)用到 hardware::graphics::allocator::V3_0::IAllocator 的 allocate 函數(shù)
auto ret = mAllocator->allocate(descriptor, bufferCount,
[&](const auto& tmpError, const auto& tmpStride,
const auto& tmpBuffers) {
error = static_cast<status_t>(tmpError);
if (tmpError != Error::NONE) {
return;
}
// import buffers
for (uint32_t i = 0; i < bufferCount; i++) {
error = mMapper.importBuffer(tmpBuffers[i],
&outBufferHandles[i]);
if (error != NO_ERROR) {
for (uint32_t j = 0; j < i; j++) {
mMapper.freeBuffer(outBufferHandles[j]);
outBufferHandles[j] = nullptr;
}
return;
}
}
*outStride = tmpStride;
});
// 確保內(nèi)核驅(qū)動(dòng)程序看到 BC_FREE_BUFFER 并立即關(guān)閉fds
hardware::IPCThreadState::self()->flushCommands();
return (ret.isOk()) ? error : static_cast<status_t>(kTransactionError);
}
Gralloc3Allocator 的內(nèi)存分配主要用到了兩個(gè)對(duì)象喉悴,分別是繼承自 Gralloc::GraphicBufferMapper
的 mMapper,和繼承自 GraphicBufferAllocator
的 mAllocator玖媚。
mAllocator 是通過(guò) HAL 創(chuàng)建的對(duì)象, 這個(gè) IAllocator 是一個(gè) HIDL 接口, HIDL 其實(shí)就是 hardware 層的 AIDL , 它和我們應(yīng)用層的 AIDL 其實(shí)是一樣的, 在我們應(yīng)用層, 如果想使用 AIDL 進(jìn)行跨進(jìn)程通信, 需要定義一個(gè) aidl 后綴名的文件, 而在系統(tǒng)的 HAL 層, 如果想使用 HIDL 進(jìn)行跨進(jìn)行通信也是類(lèi)似, 需要定義一個(gè) hal 后綴名的文件.箕肃。
例如 IAllocator 這個(gè)接口,其實(shí)就定義中 hardware/interfaces/graphics/allocator/3.0/ 路徑下的 IAllocator.hal 中
[hardware/interfaces/graphics/allocator/3.0/IAllocator.hal]
package android.hardware.graphics.allocator@3.0;
import android.hardware.graphics.mapper@3.0;
// 這是一個(gè)接口
interface IAllocator {
// 調(diào)試相關(guān)的方法今魔,不關(guān)心
dumpDebugInfo() generates (string debugInfo);
// 按照描述符的屬性分配緩沖區(qū)
allocate(BufferDescriptor descriptor, uint32_t count)
generates (Error error,
uint32_t stride,
vec<handle> buffers);
};
IAllocator.hal 定義的方法很簡(jiǎn)單, 它只有一個(gè) allocate 函數(shù),這個(gè)就是我們用來(lái)分配內(nèi)存的函數(shù)勺像。我們會(huì)拿到 Bp 對(duì)象來(lái)進(jìn)行調(diào)用,具體的實(shí)現(xiàn)則是在 Bn 中错森。
它實(shí)際上就是調(diào)用到了 HAL 部分的 allocate吟宦,這其實(shí)就有些像我們調(diào)用系統(tǒng)函數(shù)時(shí)的過(guò)程,也是通過(guò) AIDL 完成的涩维,只不過(guò)這里就是通過(guò) HIDL 完成的殃姓。接下來(lái)我們需要知道這個(gè) HAL 是如何完成工作的。
注意, 我們之前通過(guò) IAllocator 調(diào)用了兩個(gè)函數(shù), 其中還有一個(gè)函數(shù)是 getService ,而這里的 hal 文件中我們并沒(méi)有看到這個(gè)函數(shù), 那么這個(gè)函數(shù)是哪里來(lái)的呢 其實(shí)在編譯的時(shí)候, 還會(huì)生成一個(gè)文件 AllocatorAll.cpp , 這個(gè)文件就包含了我們之前調(diào)用的 getService
2.2.4 getService
[out/soong/.intermediates/hardware/interfaces/graphics/allocator/3.0/android.hardware.graphics.allocator@3.0_genc++/gen/android/hardware/graphics/allocator/3.0/AllocatorAll.cpp]
::android::sp<IAllocator> IAllocator::getService(const std::string &serviceName, const bool getStub) {
return ::android::hardware::details::getServiceInternal<BpHwAllocator>(serviceName, true, getStub);
}
到此瓦阐,F(xiàn)ramework 部分的內(nèi)容就全部介紹完了蜗侈,還是比較簡(jiǎn)單的,因?yàn)檎嬲墓ぷ鞫际前l(fā)生在 HAL 層和硬件層睡蟋。
最后宛篇,如果大伙有什么好的學(xué)習(xí)方法或建議歡迎大家在評(píng)論中積極留言哈,希望大家能夠共同學(xué)習(xí)薄湿、共同努力叫倍、共同進(jìn)步偷卧。
小編在這里祝小伙伴們?cè)谖磥?lái)的日子里都可以 升職加薪,當(dāng)上總經(jīng)理吆倦,出任CEO听诸,迎娶白富美,走上人生巔峰2显蟆晌梨!
不論遇到什么困難,都不應(yīng)該成為我們放棄的理由须妻!