GraphicBuffer是Surface系統中一個高層次的顯示內存管理類,它封裝了和硬件相關的一些細節,簡化了應用層的處理邏輯。先來認識一下它。
1. 初識GraphicBuffer
GraphicBuffer的代碼如下所示:
**GraphicBuffer.h**
~~~
class GraphicBuffer
:public EGLNativeBase<android_native_buffer_t,
GraphicBuffer,LightRefBase<GraphicBuffer>>,
public Flattenable
~~~
其中,EGLNativeBase是一個模板類。它的定義,代碼如下所示:
**Android_natives.h**
~~~
template <typename NATIVE_TYPE, typenameTYPE, typename REF>
class EGLNativeBase : public NATIVE_TYPE, publicREF
~~~
通過替換,可得到GraphicBuffer的派生關系,如圖8-21所示:
:-: 
圖8-21 GraphicBuffer派生關系的示意圖
從圖中可以看出:
- 從LightRefBase派生使GraphicBuffer支持輕量級的引用計數控制。
- 從Flattenable派生使GraphicBuffer支持序列化,它的flatten和unflatten函數用于序列化和反序列化,這樣,GraphicBuffer的信息就可以存儲到Parcel包中并被Binder傳輸了。
另外,圖中的android_native_buffer_t是GraphicBuffer的父類,它是一個struct結構體。可以將C++語言中的struct和class當作同一個東西,所以GraphicBuffer能從它派生。其代碼如下所示:
**android_native_buffer.h**
~~~
typedef struct android_native_buffer_t
{
#ifdef __cplusplus
android_native_buffer_t() {
common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
common.version = sizeof(android_native_buffer_t);
memset(common.reserved, 0, sizeof(common.reserved));
}
#endif
//這個android_native_base_t是struct的第一個成員,根據C/C++編譯的特性,這個成員
//在它的派生類對象所占有的內存中也是排第一個。
structandroid_native_base_t common;
intwidth;
intheight;
intstride;
intformat;
intusage;
void* reserved[2];
//這是一個關鍵成員,保存一些和顯示內存分配/管理相關的內容
buffer_handle_t handle;
void*reserved_proc[8];
} android_native_buffer_t;
~~~
GraphicBuffer和顯示內存分配相關的部分主要集中在buffer_handle_t這個變量上,它實際上是一個指針,定義如下:
**gralloc.h**
~~~
typedef const native_handle* buffer_handle_t;
~~~
native_handle的定義如下:
**native_handle.h**
~~~
typedef struct
{
intversion; /* version值為sizeof(native_handle_t) */
intnumFds;
intnumInts;
intdata[0]; /* data是數據存儲空間的首地址 */
} native_handle_t;
typedef native_handle_t native_handle;
~~~
讀者可能要問,一個小小的GraphicBuffer為什么這么復雜?要回答這個問題,應先對GraphicBuffer有比較全面的了解。按照圖8-20中的流程來看GraphicBuffer。
2. GraphicBuffer和存儲的分配
GraphicBuffer的構造函數最有可能分配存儲了。注意,流程中使用的是無參構造函數,所以應先看無參構造函數。
(1)無參構造函數的分析
代碼如下所示:
**GraphicBuffer.cpp**
~~~
GraphicBuffer::GraphicBuffer()
:BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
mInitCheck(NO_ERROR), mVStride(0), mIndex(-1)
{
/*
其中mBufferMapper為GraphicBufferMapper類型,它的創建采用的是單例模式,也就是每個
進程只有一個GraphicBufferMapper對象,讀者可以去看看get的實現。
*/
width =
height=
stride=
format=
usage = 0;
handle= NULL; //handle為空
}
~~~
在無參構造函數中沒有發現和存儲分配有關的操作。那么,根據流程,下一個有可能的地方就是reallocate函數了。
(2)reallocate的分析
Reallocate的代碼如下所示:
**GraphicBuffer.cpp**
~~~
status_t GraphicBuffer::reallocate(uint32_t w,uint32_t h, PixelFormat f,
uint32_t reqUsage)
{
if(mOwner != ownData)
return INVALID_OPERATION;
if(handle) {//handle值在無參構造函數中初始化為空,所以不滿足if的條件
GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
allocator.free(handle);
handle = 0;
}
returninitSize(w, h, f, reqUsage);//調用initSize函數
}
~~~
InitSize函數的代碼如下所示:
**GraphicBuffer.cpp**
~~~
status_t GraphicBuffer::initSize(uint32_t w,uint32_t h, PixelFormat format,
uint32_t reqUsage)
{
if(format == PIXEL_FORMAT_RGBX_8888)
format = PIXEL_FORMAT_RGBA_8888;
/*
GraphicBufferAllocator才是真正的存儲分配的管理類,它的創建也是采用的單例模式,
也就是每個進程只有一個GraphicBufferAllocator對象
*/
GraphicBufferAllocator& allocator =GraphicBufferAllocator::get();
//調用GraphicBufferAllocator的alloc來分配存儲,注意handle作為指針
//被傳了進去,看來handle的值會被修改
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;
mVStride = 0;
}
returnerr;
}
~~~
(3)GraphicBufferAllocator的介紹
從上面的代碼中可以發現,GraphicBuffer的存儲分配和GraphicBufferAllocator有關。一個小小的存儲分配為什么需要經過這么多道工序呢?還是先來看GraphicBufferAllocator,代碼如下所示:
**GraphicBufferAllocator.cpp**
~~~
GraphicBufferAllocator::GraphicBufferAllocator()
:mAllocDev(0)
{
hw_module_t const* module;
//調用hw_get_module,得到hw_module_t
interr = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
if (err == 0) {
//調用gralloc_open函數,注意我們把module參數傳了進去。
gralloc_open(module, &mAllocDev);
}
}
~~~
GraphicBufferAllocator在創建時,會首先調用hw_get_module取出一個hw_module_t類型的對象。從名字上看,它和硬件平臺有關系。它會加載一個叫libgralloc.硬件平臺名.so的動態庫。比如,我的HTC G7手機上加載的庫是/system/lib/hw/libgraolloc.qsd-8k.so。這個庫的源代碼在hardware/msm7k/libgralloc-qsd8k目錄下。
這個庫有什么用呢?簡言之,就是為了分配一塊用于顯示的內存,但為什么需要這種層層封裝呢?答案很簡單:
封裝的目的就是為了屏蔽不同硬件平臺的差別。
讀者可通過執行adb getprop ro.board.platform命令,得到具體手機上硬件平臺的名字。圖8-22總結了GraphicBufferAllocator分配內存的途徑。這部分代碼,讀者可參考hardware/libhardware/hardware.c和hardware/msm7k/libgralloc-qsd8k/gralloc.cpp,后文將不再深入探討和硬件平臺有關的知識。
:-: 
圖8-22 GraphicBufferAllocator內存的分配途徑
>[warning] **注意**,這里是以G7的libgralloc.qsk-8k.so為示例的。其中pmem設備用來創建一塊連續的內存,因為有些硬件設備(例如Camera)工作時需要使用一塊連續的內存,對于這種情況,一般就會使用pmem設備來分配內存。
這里,僅討論圖8-22中與硬件無關的分配方式。在這種情況下,將使用ashmem分配共享內存。下面看GraphicBufferAllocator的alloc函數,其代碼如下所示:
**GraphicBufferAllocator.cpp**
~~~
status_t GraphicBufferAllocator::alloc(uint32_tw, uint32_t h, PixelFormat format,int usage, buffer_handle_t* handle, int32_t*stride)
{
//根據前面的定義可知buffer_handle_t為native_handle_t*類型
status_t err;
if (usage & GRALLOC_USAGE_HW_MASK) {
err =mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
} else {
//SW分配,可以做到和HW無關了。
err = sw_gralloc_handle_t::alloc(w, h, format, usage, handle, stride);
}
......
returnerr;
}
~~~
下面,來看軟件分配的方式:
**GraphicBufferAllocator.cpp**
~~~
status_t sw_gralloc_handle_t::alloc(uint32_t w,uint32_t h, int format,
int usage, buffer_handle_t* pHandle, int32_t*pStride)
{
intalign = 4;
intbpp = 0;
......//格式轉換
size_tbpr = (w*bpp + (align-1)) & ~(align-1);
size_tsize = bpr * h;
size_tstride = bpr / bpp;
size =(size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
//直接使用了ashmem創建共享內存
int fd= ashmem_create_region("sw-gralloc-buffer", size);
......
//進行內存映射,得到共享內存起始地址
void*base = mmap(0, size, prot, MAP_SHARED, fd, 0);
sw_gralloc_handle_t* hnd = new sw_gralloc_handle_t();
hnd->fd = fd;//保存文件描述符
hnd->size = size;//保存共享內存的大小
hnd->base = intptr_t(base);//intptr_t將void*類型轉換成int*類型
hnd->prot = prot;//保存屬性
*pStride = stride;
*pHandle = hnd; //pHandle就是傳入的那個handle變量的指針,這里對它進行賦值
returnNO_ERROR;
}
~~~
我們知道,調用GraphicBuffer的reallocate函數后,會導致物理存儲被分配。前面曾說過,Layer會創建兩個GraphicBuffer,而Native Surface端也會創建兩個GraphicBuffer,那么這兩個GraphicBuffer是怎么建立聯系的呢?為什么說native_handle_t是GraphicBuffer的精髓呢?
3. flatten和unflatten的分析
試想,Native Surface的GraphicBuffer是怎么和Layer的GraphicBuffer建立聯系的:
先通過requestBuffer函數返回一個GraphicBuffer,然后這個GraphicBuffer被Native Surface保存。
這中間的過程其實是一個mini版的乾坤挪移,來看看,代碼如下所示:
**ISurface.cpp**
~~~
//requestBuffer的響應端
status_t BnSurface::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case REQUEST_BUFFER: {
CHECK_INTERFACE(ISurface, data, reply);
int bufferIdx = data.readInt32();
int usage = data.readInt32();
sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, usage));
......
/*
requestBuffer的返回值被寫到Parcel包中,由于GraphicBuffer從
Flattenable類派生,這將導致它的flatten函數被調用
*/
return reply->write(*buffer);
}
.......
}
//再來看請求端的處理,在BpSurface中
virtual sp<GraphicBuffer> requestBuffer(intbufferIdx, int usage)
{
Parcel data, reply;
data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
data.writeInt32(bufferIdx);
data.writeInt32(usage);
remote()->transact(REQUEST_BUFFER, data, &reply);
sp<GraphicBuffer> buffer = new GraphicBuffer();
reply.read(*buffer);//Parcel調用unflatten函數把信息反序列化到這個buffer中。
return buffer;//requestBuffer實際上返回的是本地new出來的這個GraphicBuffer
}
~~~
通過上面的代碼可以發現,挪移的關鍵體現在flatten和unflatten函數上。請看:
(1)flatten的分析
flatten的代碼如下所示:
**GraphicBuffer.cpp**
~~~
status_t GraphicBuffer::flatten(void* buffer,size_t size,
int fds[], size_t count) const
{
//buffer是裝載數據的緩沖區,由Parcel提供
......
if(handle) {
buf[6] = handle->numFds;
buf[7] = handle->numInts;
native_handle_t const* const h = handle;
//把handle的信息也寫到buffer中
memcpy(fds, h->data, h->numFds*sizeof(int));
memcpy(&buf[8], h->data + h->numFds,h->numInts*sizeof(int));
}
returnNO_ERROR;
}
~~~
flatten的工作就是把GraphicBuffer的handle變量信息寫到Parcel包中。那么接收端如何使用這個包呢?這就是unflatten的工作了。
(2)unflatten分析
unflatten的代碼如下所示:
**GraphicBuffer.cpp**
~~~
status_t GraphicBuffer::unflatten(void const*buffer, size_t size,
int fds[], size_t count)
{
......
if(numFds || numInts) {
width = buf[1];
height = buf[2];
stride = buf[3];
format = buf[4];
usage = buf[5];
native_handle* h =native_handle_create(numFds, numInts);
memcpy(h->data, fds, numFds*sizeof(int));
memcpy(h->data + numFds, &buf[8],numInts*sizeof(int));
handle = h;//根據Parcel包中的數據還原一個handle
} else{
width = height = stride = format = usage = 0;
handle = NULL;
}
mOwner= ownHandle;
returnNO_ERROR;
}
~~~
unflatten最重要的工作是,根據Parcel包中native_handle的信息,在Native Surface端構造一個對等的GraphicBuffer。這樣,Native Surface端的GraphicBuffer實際上就和Layer端的GraphicBuffer管理著同一塊共享內存。
3. registerBuffer的分析
registerBuffer有什么用呢?上一步調用unflatten后得到了代表共享內存的文件句柄,regiserBuffer的目的就是對它進行內存映射,代碼如下所示:
**GraphicBufferMapper.cpp**
~~~
status_tsw_gralloc_handle_t::registerBuffer(sw_gralloc_handle_t* hnd)
{
if (hnd->pid != getpid()) {
//原來是做一次內存映射操作
void* base = mmap(0, hnd->size, hnd->prot, MAP_SHARED, hnd->fd,0);
......
//base保存著共享內存的起始地址
hnd->base = intptr_t(base);
}
returnNO_ERROR;
}
~~~
4. lock和unlock的分析
GraphicBuffer在使用前需要通過lock來得到內存地址,使用完后又會通過unlock釋放這塊地址。在SW分配方案中,這兩個函數實現卻非常簡單,如下所示:
**GraphicBufferMapper.cpp**
~~~
//lock操作
int sw_gralloc_handle_t::lock(sw_gralloc_handle_t*hnd, int usage,
int l, int t, int w, int h, void** vaddr)
{
*vaddr= (void*)hnd->base;//得到共享內存的起始地址,后續作畫就使用這塊內存了。
returnNO_ERROR;
}
//unlock操作
status_tsw_gralloc_handle_t::unlock(sw_gralloc_handle_t* hnd)
{
returnNO_ERROR;//沒有任何操作
}
~~~
對GraphicBuffer的介紹就到這里。雖然采用的是SW方式,但是相信讀者也能通過樹木領略到森林的風采。從應用層角度看,可以把GraphicBuffer當做一個構架在共享內存之上的數據緩沖。對想深入研究的讀者,我建議可按圖8-20中的流程來分析。因為流程體現了調用順序,表達了調用者的意圖和目的,只有把握了流程,分析時才不會迷失在茫茫的源碼海洋中,才不會被不熟悉的知識阻攔前進的腳步。
- 前言
- 第1章 閱讀前的準備工作
- 1.1 系統架構
- 1.1.1 Android系統架構
- 1.1.2 本書的架構
- 1.2 搭建開發環境
- 1.2.1 下載源碼
- 1.2.2 編譯源碼
- 1.3 工具介紹
- 1.3.1 Source Insight介紹
- 1.3.2 Busybox的使用
- 1.4 本章小結
- 第2章 深入理解JNI
- 2.1 JNI概述
- 2.2 學習JNI的實例:MediaScanner
- 2.3 Java層的MediaScanner分析
- 2.3.1 加載JNI庫
- 2.3.2 Java的native函數和總結
- 2.4 JNI層MediaScanner的分析
- 2.4.1 注冊JNI函數
- 2.4.2 數據類型轉換
- 2.4.3 JNIEnv介紹
- 2.4.4 通過JNIEnv操作jobject
- 2.4.5 jstring介紹
- 2.4.6 JNI類型簽名介紹
- 2.4.7 垃圾回收
- 2.4.8 JNI中的異常處理
- 2.5 本章小結
- 第3章 深入理解init
- 3.1 概述
- 3.2 init分析
- 3.2.1 解析配置文件
- 3.2.2 解析service
- 3.2.3 init控制service
- 3.2.4 屬性服務
- 3.3 本章小結
- 第4章 深入理解zygote
- 4.1 概述
- 4.2 zygote分析
- 4.2.1 AppRuntime分析
- 4.2.2 Welcome to Java World
- 4.2.3 關于zygote的總結
- 4.3 SystemServer分析
- 4.3.1 SystemServer的誕生
- 4.3.2 SystemServer的重要使命
- 4.3.3 關于 SystemServer的總結
- 4.4 zygote的分裂
- 4.4.1 ActivityManagerService發送請求
- 4.4.2 有求必應之響應請求
- 4.4.3 關于zygote分裂的總結
- 4.5 拓展思考
- 4.5.1 虛擬機heapsize的限制
- 4.5.2 開機速度優化
- 4.5.3 Watchdog分析
- 4.6 本章小結
- 第5章 深入理解常見類
- 5.1 概述
- 5.2 以“三板斧”揭秘RefBase、sp和wp
- 5.2.1 第一板斧--初識影子對象
- 5.2.2 第二板斧--由弱生強
- 5.2.3 第三板斧--破解生死魔咒
- 5.2.4 輕量級的引用計數控制類LightRefBase
- 5.2.5 題外話-三板斧的來歷
- 5.3 Thread類及常用同步類分析
- 5.3.1 一個變量引發的思考
- 5.3.2 常用同步類
- 5.4 Looper和Handler類分析
- 5.4.1 Looper類分析
- 5.4.2 Handler分析
- 5.4.3 Looper和Handler的同步關系
- 5.4.4 HandlerThread介紹
- 5.5 本章小結
- 第6章 深入理解Binder
- 6.1 概述
- 6.2 庖丁解MediaServer
- 6.2.1 MediaServer的入口函數
- 6.2.2 獨一無二的ProcessState
- 6.2.3 時空穿越魔術-defaultServiceManager
- 6.2.4 注冊MediaPlayerService
- 6.2.5 秋風掃落葉-StartThread Pool和join Thread Pool分析
- 6.2.6 你徹底明白了嗎
- 6.3 服務總管ServiceManager
- 6.3.1 ServiceManager的原理
- 6.3.2 服務的注冊
- 6.3.3 ServiceManager存在的意義
- 6.4 MediaPlayerService和它的Client
- 6.4.1 查詢ServiceManager
- 6.4.2 子承父業
- 6.5 拓展思考
- 6.5.1 Binder和線程的關系
- 6.5.2 有人情味的訃告
- 6.5.3 匿名Service
- 6.6 學以致用
- 6.6.1 純Native的Service
- 6.6.2 扶得起的“阿斗”(aidl)
- 6.7 本章小結
- 第7章 深入理解Audio系統
- 7.1 概述
- 7.2 AudioTrack的破解
- 7.2.1 用例介紹
- 7.2.2 AudioTrack(Java空間)分析
- 7.2.3 AudioTrack(Native空間)分析
- 7.2.4 關于AudioTrack的總結
- 7.3 AudioFlinger的破解
- 7.3.1 AudioFlinger的誕生
- 7.3.2 通過流程分析AudioFlinger
- 7.3.3 audio_track_cblk_t分析
- 7.3.4 關于AudioFlinger的總結
- 7.4 AudioPolicyService的破解
- 7.4.1 AudioPolicyService的創建
- 7.4.2 重回AudioTrack
- 7.4.3 聲音路由切換實例分析
- 7.4.4 關于AudioPolicy的總結
- 7.5 拓展思考
- 7.5.1 DuplicatingThread破解
- 7.5.2 題外話
- 7.6 本章小結
- 第8章 深入理解Surface系統
- 8.1 概述
- 8.2 一個Activity的顯示
- 8.2.1 Activity的創建
- 8.2.2 Activity的UI繪制
- 8.2.3 關于Activity的總結
- 8.3 初識Surface
- 8.3.1 和Surface有關的流程總結
- 8.3.2 Surface之乾坤大挪移
- 8.3.3 乾坤大挪移的JNI層分析
- 8.3.4 Surface和畫圖
- 8.3.5 初識Surface小結
- 8.4 深入分析Surface
- 8.4.1 與Surface相關的基礎知識介紹
- 8.4.2 SurfaceComposerClient分析
- 8.4.3 SurfaceControl分析
- 8.4.4 writeToParcel和Surface對象的創建
- 8.4.5 lockCanvas和unlockCanvasAndPost分析
- 8.4.6 GraphicBuffer介紹
- 8.4.7 深入分析Surface的總結
- 8.5 SurfaceFlinger分析
- 8.5.1 SurfaceFlinger的誕生
- 8.5.2 SF工作線程分析
- 8.5.3 Transaction分析
- 8.5.4 關于SurfaceFlinger的總結
- 8.6 拓展思考
- 8.6.1 Surface系統的CB對象分析
- 8.6.2 ViewRoot的你問我答
- 8.6.3 LayerBuffer分析
- 8.7 本章小結
- 第9章 深入理解Vold和Rild
- 9.1 概述
- 9.2 Vold的原理與機制分析
- 9.2.1 Netlink和Uevent介紹
- 9.2.2 初識Vold
- 9.2.3 NetlinkManager模塊分析
- 9.2.4 VolumeManager模塊分析
- 9.2.5 CommandListener模塊分析
- 9.2.6 Vold實例分析
- 9.2.7 關于Vold的總結
- 9.3 Rild的原理與機制分析
- 9.3.1 初識Rild
- 9.3.2 RIL_startEventLoop分析
- 9.3.3 RIL_Init分析
- 9.3.4 RIL_register分析
- 9.3.5 關于Rild main函數的總結
- 9.3.6 Rild實例分析
- 9.3.7 關于Rild的總結
- 9.4 拓展思考
- 9.4.1 嵌入式系統的存儲知識介紹
- 9.4.2 Rild和Phone的改進探討
- 9.5 本章小結
- 第10章 深入理解MediaScanner
- 10.1 概述
- 10.2 android.process.media分析
- 10.2.1 MSR模塊分析
- 10.2.2 MSS模塊分析
- 10.2.3 android.process.media媒體掃描工作的流程總結
- 10.3 MediaScanner分析
- 10.3.1 Java層分析
- 10.3.2 JNI層分析
- 10.3.3 PVMediaScanner分析
- 10.3.4 關于MediaScanner的總結
- 10.4 拓展思考
- 10.4.1 MediaScannerConnection介紹
- 10.4.2 我問你答
- 10.5 本章小結