前面介紹了Normal屬性顯示層中的第一類Layer,這里將介紹其中的第二類LayerBuffer。LayerBuffer會在視頻播放和攝像機預覽等場景中用到,就以Camera的preView(預覽)為例,來分析LayerBuffer的工作原理。
1. LayerBuffer的創建
先看LayerBuffer的創建,它通過SF的createPushBuffersSurfaceLocked得到,代碼如下所示:
**SurfaceFlinger.cpp**
~~~
sp<LayerBaseClient> SurfaceFlinger::createPushBuffersSurfaceLocked(
const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags)
{
sp<LayerBuffer> layer = new LayerBuffer(this, display, client,id);
layer->initStates(w, h, flags);
addLayer_l(layer);
returnlayer;
}
~~~
LayerBuffer的派生關系,如圖8-30所示:
:-: 
圖8-30 LayerBuffer的派生關系示意圖
從上圖中可以發現:
- LayerBuffer定義了一個內部類Source類,它有兩個派生類BufferSource和OverlaySource。根據它們的名字,可以猜測到Source代表數據的提供者。
* LayerBuffer中的mSurface其真實類型是SurfaceLayerBuffer。
LayerBuffer創建好了,不過該怎么用呢?和它相關的調用流程是怎樣的呢?下面來分析Camera。
2. Camera preView的分析
Camera是一個單獨的Service,全稱是CameraService,先看CameraService的registerPreviewBuffers函數。這個函數會做什么呢?代碼如下所示:
**CameraService.cpp**
~~~
status_tCameraService::Client::registerPreviewBuffers()
{
int w, h;
CameraParameters params(mHardware->getParameters());
params.getPreviewSize(&w, &h);
/*
①mHardware代表Camera設備的HAL對象。本書討論CameraHardwareStub設備,它其實是
一個虛擬的設備,不過其代碼卻具有參考價值。
BufferHeap定義為ISurface的內部類,其實就是對IMemoryHeap的封裝
*/
ISurface::BufferHeapbuffers(w, h, w, h,
HAL_PIXEL_FORMAT_YCrCb_420_SP,
mOrientation,
0,
mHardware->getPreviewHeap());
//②調用SurfaceLayerBuffer的registerBuffers函數。
status_t ret = mSurface->registerBuffers(buffers);
returnret;
}
~~~
上面代碼中列出了兩個關鍵點,逐一來分析它們。
(1)創建BufferHeap
BufferHeap是ISurface定義的一個內部類,它的聲明如下所示:
**ISurface.h**
~~~
classBufferHeap {
public:
......
//使用這個構造函數
BufferHeap(uint32_t w, uint32_t h,
int32_t hor_stride, int32_t ver_stride,
PixelFormat format, const sp<IMemoryHeap>& heap);
......
~BufferHeap();
uint32_t w;
uint32_t h;
int32_t hor_stride;
int32_t ver_stride;
PixelFormat format;
uint32_t transform;
uint32_t flags;
sp<IMemoryHeap> heap; //heap指向真實的存儲對象
};
~~~
從上面代碼中可發現,BufferHeap基本上就是封裝了一個IMemoryHeap對象,根據我們對IMemoryHeap的了解,它應該包含了真實的存儲對象,這個值由CameraHardwareStub對象的getPreviewHeap得到,這個函數的代碼如下所示:
**CameraHardwareStub.cpp**
~~~
sp<IMemoryHeap>CameraHardwareStub::getPreviewHeap() const
{
returnmPreviewHeap;//返回一個成員變量,它又是在哪創建的呢?
}
//上面的mPreivewHeap對象由initHeapLocked函數創建,該函數在HAL對象創建的時候被調用
void CameraHardwareStub::initHeapLocked()
{
......
/*
創建一個MemoryHeapBase對象,大小是mPreviewFrameSize * kBufferCount,其中
kBufferCount為4。注意這是一段連續的緩沖。
*/
mPreviewHeap= new MemoryHeapBase(mPreviewFrameSize * kBufferCount);
//mBuffer為MemoryBase數組,元素為4
for (inti = 0; i < kBufferCount; i++) {
mBuffers[i] = new MemoryBase(mPreviewHeap,
i * mPreviewFrameSize, mPreviewFrameSize);
}
}
~~~
從上面這段代碼中可以發現,CameraHardwareStub對象創建的用于preView的內存結構是按圖8-31所示的方式來組織的:
:-: 
圖8-31 CameraHardwareStub用于preView的內存結構圖
其中:
- BufferHeap的heap變量指向一塊MemoryHeap,這就是mPreviewHeap。
- 在這塊MemoryHeap上構建了4個MemoryBase。
(2)registerBuffers的分析
BufferHeap準備好后,要調用ISurface的registerBuffers函數,ISurface在SF端的真實類型是SurfaceLayerBuffer,所以要直接看它的實現,代碼如下所示:
**LayerBuffer.cpp**
~~~
status_t LayerBuffer::SurfaceLayerBuffer::registerBuffers(
const ISurface::BufferHeap& buffers)
{
sp<LayerBuffer> owner(getOwner());
if (owner != 0)
//調用外部類對象的registerBuffers,所以SurfaceLayerBuffer也是一個Proxy哦。
return owner->registerBuffers(buffers);
returnNO_INIT;
}
//外部類是LayerBuffer,調用它的registerBuffers函數
status_t LayerBuffer::registerBuffers(constISurface::BufferHeap& buffers)
{
Mutex::Autolock _l(mLock);
//創建數據的來源BufferSource,注意我們其實把MemoryHeap設置上去了
sp<BufferSource> source = new BufferSource(*this, buffers);
status_t result = source->getStatus();
if(result == NO_ERROR) {
mSource = source;//保存這個數據源為mSource。
}
returnresult;
}
~~~
BufferSource,曾在圖8-30中見識過,它內部有一個成員變量mBufferHeap指向傳入的buffers參數,所以registerBuffers過后,就得到了圖8-32:
:-: 
圖8-32 registerBuffers的結果示意圖
請注意上圖的箭頭指向,不論中間有多少層封裝,最終的數據存儲區域還是mPreivewHeap。
2.數據的傳輸
至此,Buffer在SF和Camera兩端都準備好了,那么數據是怎么從Camera傳遞到SF的呢?先來看數據源是怎么做的。
(1)數據傳輸的分析
CameraHardwareStub有一個preview線程,這個線程會做什么呢?代碼如下所示:
**CameraHardwareStub.cpp**
~~~
//preview線程從Thread類派生,下面這個函數在threadLoop中循環調用
int CameraHardwareStub::previewThread()
{
mLock.lock();
//每次進來mCurrentPreviewFrame都會加1
ssize_t offset = mCurrentPreviewFrame * mPreviewFrameSize;
sp<MemoryHeapBase> heap = mPreviewHeap;
FakeCamera* fakeCamera = mFakeCamera;//虛擬的攝像機設備
//從mBuffers中取一塊內存,用于接收來自硬件的數據
sp<MemoryBase>buffer = mBuffers[mCurrentPreviewFrame];
mLock.unlock();
if(buffer != 0) {
intdelay = (int)(1000000.0f / float(previewFrameRate));
void *base = heap->base();//base是mPreviewHeap的起始位置
//下面這個frame代表buffer在mPreviewHeap中的起始位置,還記得圖8-31嗎?
//四塊MemoryBase的起始位置由下面這個代碼計算得來
uint8_t *frame = ((uint8_t *)base) + offset;
//取出一幀數據,放到對應的MemoryBase中
fakeCamera->getNextFrameAsYuv422(frame);
//①把含有幀數據的buffer傳遞到上層
if(mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME)
mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, mCallbackCookie);
//mCurrentPreviewFrame 遞增,在0到3之間循環
mCurrentPreviewFrame = (mCurrentPreviewFrame + 1) % kBufferCount;
usleep(delay);//模擬真實硬件的延時
}
returnNO_ERROR;
}
~~~
讀者是否明白Camera preview的工作原理了?就是從四塊內存中取一塊出來接收數據,然后再把這塊內存傳遞到上層去處理。從緩沖使用的角度來看,mBuffers數組構成了一個成員個數為四的緩沖隊列。preview通過mData這個回調函數,把數據傳遞到上層,而CameraService實現了mData這個回調函數,這個回調函數最終會調用handlePreviewData,直接看handlePreviewData即可,代碼如下所示:
**CameraService.cpp**
~~~
voidCameraService::Client::handlePreviewData(const sp<IMemory>& mem)
{
ssize_t offset;
size_t size;
//注意傳入的mem參數,它實際上是Camera HAL創建的mBuffers數組中的一個
//offset返回的是這個數組在mPreviewHeap中的偏移量
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
if (!mUseOverlay)
{
Mutex::Autolock surfaceLock(mSurfaceLock);
if(mSurface != NULL) {
//調用ISurface的postBuffer,注意我們傳入的參數是offset。
mSurface->postBuffer(offset);
}
}
......
}
~~~
上面的代碼是什么意思?我們到底給ISurface傳什么了?答案很明顯:
- handlePreviewData就是傳遞了一個偏移量,這個偏移量是mBuffers數組成員的首地址。可用圖8-33來表示:
:-: 
圖8-33 handlePreviewData示意圖
有了圖8-33,讀者明白數據傳遞的工作原理了嗎?
下面看SurfaceLayerBuffer的postBuffer函數,不過它只是一個小小的代理,真正的工作由外部類LayerBuffer完成,直接看它好了,代碼如下所示:
**LayerBuffer.cpp**
~~~
void LayerBuffer::postBuffer(ssize_t offset)
{
sp<Source> source(getSource());//getSource返回mSource,為BufferSource類型
if(source != 0)
source->postBuffer(offset);//調用BufferSource的postBuffer函數。
}
~~~
**LayerBuffer.cpp**
~~~
voidLayerBuffer::BufferSource::postBuffer(ssize_t offset)
{
ISurface::BufferHeap buffers;
{
Mutex::Autolock _l(mBufferSourceLock);
buffers = mBufferHeap;//還記得圖8-32嗎?
if(buffers.heap != 0) {
//BufferHeap的heap變量指向MemoryHeap,下面取出它的大小
const size_t memorySize = buffers.heap->getSize();
//做一下檢查,判斷這個offset是不是有問題
if ((size_t(offset) + mBufferSize) > memorySize) {
LOGE("LayerBuffer::BufferSource::postBuffer() "
"invalid buffer(offset=%d, size=%d, heap-size=%d",
int(offset),int(mBufferSize), int(memorySize));
return;
}
}
}
sp<Buffer> buffer;
if (buffers.heap != 0) {
//創建一個LayerBuffer::Buffer
buffer = new LayerBuffer::Buffer(buffers, offset, mBufferSize);
if(buffer->getStatus() != NO_ERROR)
buffer.clear();
setBuffer(buffer);//setBuffer?我們要看看
//mLayer就是外部類LayerBuffer,調用它的invalidate函數將觸發SF的重繪
mLayer.invalidate();
}
}
void LayerBuffer::BufferSource::setBuffer(
const sp<LayerBuffer::Buffer>& buffer)
{
//setBuffer函數就是簡單地將new出來的Buffer設置給成員變量mBuffer,這么做會有問題嗎?Mutex::Autolock_l(mBufferSourceLock);
mBuffer = buffer; //將新的buffer設置為mBuffer,mBuffer原來指向的那個被delete
}
~~~
從數據生產者角度看,postBuffer函數將不斷地new一個Buffer出來,然后將它賦值給成員變量mBuffer,也就是說,mBuffer會不斷變化。現在從緩沖的角度來思考一下這種情況的結果:
- 數據生產者有一個含四個成員的緩沖隊列,也就是mBuffers數組。
- 而數據消費者只有一個mBuffer。
這種情況會有什么后果呢?請記住這個問題,我們到最后再來揭示。下面先看mBuffer的類型Buffer是什么。
(2)數據使用的分析
Buffer被定義成LayerBuffer的內部類,代碼如下所示:
**LayerBuffer.cpp**
~~~
LayerBuffer::Buffer::Buffer(constISurface::BufferHeap& buffers,
ssize_t offset, size_t bufferSize)
:mBufferHeap(buffers), mSupportsCopybit(false)
{
//注意,這個src被定義為引用,所以修改src的信息相當于修改mNativeBuffer的信息
NativeBuffer& src(mNativeBuffer);
src.crop.l = 0;
src.crop.t = 0;
src.crop.r = buffers.w;
src.crop.b = buffers.h;
src.img.w =buffers.hor_stride ?: buffers.w;
src.img.h =buffers.ver_stride ?: buffers.h;
src.img.format = buffers.format;
//這個base將指向對應的內存起始地址
src.img.base =(void*)(intptr_t(buffers.heap->base()) + offset);
src.img.handle = 0;
gralloc_module_tconst * module = LayerBuffer::getGrallocModule();
//做一些處理,有興趣的讀者可以去看看。
if(module && module->perform) {
int err = module->perform(module,
GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER,
buffers.heap->heapID(), bufferSize,
offset, buffers.heap->base(),
&src.img.handle);
mSupportsCopybit = (err == NO_ERROR);
}
}
~~~
上面是Buffer的定義,其中最重要的就是這個mNativeBuffer了,它實際上保存了mBuffers數組成員的首地址。
下面看繪圖函數,也就是LayerBuffer的onDraw函數,這個函數由SF的工作線程調用,代碼如下所示:
**LayerBuffer.cpp**
~~~
void LayerBuffer::onDraw(const Region& clip)const
{
sp<Source> source(getSource());
if(LIKELY(source != 0)) {
source->onDraw(clip);//source實際類型是BufferSource,我們去看看。
} else{
clearWithOpenGL(clip);
}
}
void LayerBuffer::BufferSource::onDraw(constRegion& clip) const
{
sp<Buffer> ourBuffer(getBuffer());
......//使用這個Buffer,注意使用的時候沒有鎖控制
mLayer.drawWithOpenGL(clip, mTexture);//生成一個貼圖,然后繪制它
}
~~~
其中getBuffer函數返回mBuffer,代碼如下所示:
~~~
sp<LayerBuffer::Buffer>LayerBuffer::BufferSource::getBuffer() const
{
Mutex::Autolock_l(mBufferSourceLock);
returnmBuffer;
}
~~~
從上面的代碼中能發現,mBuffer的使用并沒有鎖的控制,這會導致什么問題發生呢?請再次回到前面曾強調要記住的那個問題。此時生產者的隊列有四個元素,而消費者的隊列只有一個元素,它可用圖8-34來表示:
:-: 
圖8-34 數據傳遞的問題示意圖
從上圖可以知道:
- 使用者使用mBuffer,這是在SF的工作線程中做到的。假設mBuffer實際指向的內存為mBuffers[0]。
- 數據生產者循環更新mBuffers數組各個成員的數據內容,這是在另外一個線程中完成的。由于這兩個線程之間沒有鎖同步,這就造成了當使用者還在使用mBuffers[0]時,生產者又更新了mBuffers[0]。這會在屏幕上產生混雜的圖像。
經過實際測試得知,如果給數據使用端加上一定延時,屏幕就會出現不連續的畫面,即前一幀和后一幀的數據混雜在一起輸出。
從代碼的分析來看,這種方式確實有問題。我在真實設備上測試的結果,也在一定程度上驗證了這一點。通過修改LayerBuffer來解決這問題的難度比較大,是否可在讀寫具體緩存時加上同步控制呢(例如使用mBuffers[0]的時候調用一下lock,用完后調用unlock)?這樣就不用修改LayerBuffer了。讀者可再深入研究這個問題。
- 前言
- 第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 本章小結