更系統的SurfaceFlinger思路以及程式碼追蹤
轉自:http://blog.csdn.net/droidphone/article/details/5972568
SurfaceFlinger在系統啟動階段作為系統服務被載入。應用程式中的每個視窗,對應原生代碼中的Surface,而Surface又對應於SurfaceFlinger中的各個Layer,SurfaceFlinger的主要作用是為這些Layer申請記憶體,根據應用程式的請求管理這些Layer顯示、隱藏、重畫等操作,最終由SurfaceFlinger把所有的Layer組合到一起,顯示到顯示器上。當一個應用程式需要在一個Surface上進行畫圖操作時,首先要拿到這個Surface在記憶體中的起始地址,而這塊記憶體是在SurfaceFlinger中分配的,因為SurfaceFlinger和應用程式並不是執行在同一個程序中,如何在應用客戶端(Surface)和服務端(SurfaceFlinger - Layer)之間傳遞和同步顯示緩衝區?這正是本文要討論的內容。
Surface的建立過程
我們先看看Android如何建立一個Surface,下面的序列圖展示了整個建立過程。
圖一 Surface的建立過程
建立Surface的過程基本上分為兩步:
1. 建立SurfaceSession
第一步通常只執行一次,目的是建立一個SurfaceComposerClient的例項,JAVA層通過JNI呼叫原生代碼,原生代碼建立一個SurfaceComposerClient的例項,SurfaceComposerClient通過ISurfaceComposer介面呼叫SurfaceFlinger的createConnection,SurfaceFlinger返回一個ISurfaceFlingerClient介面給SurfaceComposerClient,在createConnection的過程中,SurfaceFlinger建立了用於管理緩衝區切換的SharedClient,關於SharedClient我們下面再介紹,最後,本地層把SurfaceComposerClient的例項返回給JAVA層,完成SurfaceSession的建立。
2. 利用SurfaceSession建立Surface
JAVA層通過JNI呼叫原生代碼Surface_Init(),原生代碼首先取得第一步建立的SurfaceComposerClient例項,通過SurfaceComposerClient,呼叫ISurfaceFlingerClient介面的createSurface方法,進入SurfaceFlinger,SurfaceFlinger根據引數,建立不同型別的Layer,然後呼叫Layer的setBuffers()方法,為該Layer建立了兩個緩衝區,然後返回該Layer的ISurface介面,SurfaceComposerClient使用這個ISurface介面建立一個SurfaceControl例項,並把這個SurfaceControl返回給JAVA層。
由此得到以下結果:
- JAVA層的Surface實際上對應於本地層的SurfaceControl物件,以後原生代碼可以使用JAVA傳入的SurfaceControl物件,通過SurfaceControl的getSurface方法,獲得本地Surface物件;
- Android為每個Surface分配了兩個圖形緩衝區,以便實現Page-Flip的動作;
- 建立SurfaceSession時,SurfaceFlinger建立了用於管理兩個圖形緩衝區切換的SharedClient物件,SurfaceComposerClient可以通過ISurfaceFlingerClient介面的getControlBlock()方法獲得這個SharedClient物件,檢視SurfaceComposerClient的成員函式_init:
- void SurfaceComposerClient::_init(
- const sp<ISurfaceComposer>& sm, const sp<ISurfaceFlingerClient>& conn)
- {
- ......
- mClient = conn;
- if (mClient == 0) {
- mStatus = NO_INIT;
- return;
- }
- mControlMemory = mClient->getControlBlock();
- mSignalServer = sm;
- mControl = static_cast<SharedClient *>(mControlMemory->getBase());
- }
獲得Surface對應的顯示緩衝區
雖然在SurfaceFlinger在建立Layer時已經為每個Layer申請了兩個緩衝區,但是此時在JAVA層並看不到這兩個緩衝區,JAVA層要想在Surface上進行畫圖操作,必須要先把其中的一個緩衝區繫結到Canvas中,然後所有對該Canvas的畫圖操作最後都會畫到該緩衝區內。下圖展現了繫結緩衝區的過程:
圖二 繫結緩衝區的過程
開始在Surface畫圖前,Surface.java會先呼叫lockCanvas()來得到要進行畫圖操作的Canvas,lockCanvas會進一步呼叫本地層的Surface_lockCanvas,原生代碼利用JAVA層傳入的SurfaceControl物件,通過getSurface() 取得本地層的Surface物件,接著呼叫該Surface物件的lock()方法,lock()返回了改Surface的資訊,其中包括了可用緩衝區的首地址vaddr,該vaddr在Android的2D圖形庫Skia中,建立了一個bitmap,然後通過Skia庫中Canvas的 API:Canvas.setBitmapDevice(bitmap),把該bitmap繫結到Canvas中,最後把這個Canvas返回給JAVA 層,這樣JAVA層就可以在該Canvas上進行畫圖操作,而這些畫圖操作最終都會畫在以vaddr為首地址的緩衝區中。
再看看在Surface的lock()方法中做了什麼:
- dequeueBuffer(&backBuffer)獲取backBuffer
- SharedBufferClient->dequeue()獲得當前空閒緩衝區的編號
- 通過緩衝區編號獲得真正的GraphicBuffer:backBuffer
- 如果還沒有對Layer中的buffer進行對映(Mapper),getBufferLocked通過ISurface介面重新重新對映
- 獲取frontBuffer
- 根據兩個Buffer的更新區域,把frontBuffer的內容拷貝到backBuffer中,這樣保證了兩個Buffer中顯示內容的同步
- backBuffer->lock() 獲得backBuffer緩衝區的首地址vaddr
- 通過info引數返回vaddr
釋放Surface對應的顯示緩衝區
畫圖完成後,要想把Surface的內容顯示到螢幕上,需要把Canvas中繫結的緩衝區釋放,並且把該緩衝區從變成可投遞(因為預設只有兩個 buffer,所以實際上就是變成了frontBuffer),SurfaceFlinger的工作執行緒會在適當的重新整理時刻,把系統中所有的 frontBuffer混合在一起,然後通過OpenGL重新整理到螢幕上。下圖展現瞭解除繫結緩衝區的過程:
圖三 解除繫結緩衝區的過程
- JAVA層呼叫unlockCanvasAndPost
- 進入原生代碼:Surface_unlockCanvasAndPost
- 原生代碼利用JAVA層傳入的SurfaceControl物件,通過getSurface()取得本地層的Surface物件
- 繫結一個空的bitmap到Canvas中
- 呼叫Surface的unlockAndPost方法
- 呼叫GraphicBuffer的unlock(),解鎖緩衝區
- 在queueBuffer()呼叫了SharedBufferClient的queue(),把該緩衝區更新為可投遞狀態
SharedClient 和 SharedBufferStack
從前面的討論可以看到,Canvas繫結緩衝區時,要通過SharedBufferClient的dequeue方法取得空閒的緩衝區,而解除繫結並提交緩衝區投遞時,最後也要呼叫SharedBufferClient的queue方法通知SurfaceFlinger的工作執行緒。實際上,在 SurfaceFlinger裡,每個Layer也會關聯一個SharedBufferServer,SurfaceFlinger的工作執行緒通過 SharedBufferServer管理著Layer的緩衝區,在SurfaceComposerClient建立連線的階段,SurfaceFlinger就已經為該連線建立了一個SharedClient 物件,SharedClient 物件中包含了一個SharedBufferStack陣列,陣列的大小是31,每當建立一個Surface,就會佔用陣列中的一個 SharedBufferStack,然後SurfaceComposerClient端的Surface會建立一個 SharedBufferClient和該SharedBufferStack關聯,而SurfaceFlinger端的Layer也會建立 SharedBufferServer和SharedBufferStack關聯,實際上每對 SharedBufferClient/SharedBufferServer是控制著同一個SharedBufferStack物件,通過 SharedBufferStack,保證了負責對Surface的畫圖操作的應用端和負責重新整理螢幕的服務端(SurfaceFlinger)可以使用不同的緩衝區,並且讓他們之間知道對方何時鎖定/釋放緩衝區。
SharedClient和SharedBufferStack的程式碼和標頭檔案分別位於:
/frameworks/base/libs/surfaceflinger_client/SharedBufferStack.cpp
/frameworks/base/include/private/surfaceflinger/SharedBufferStack.h
圖四 客戶端和服務端緩衝區管理
繼續研究SharedClient、SharedBufferStack、SharedBufferClient、 SharedBufferServer的誕生過程。
1. SharedClient
- 在createConnection階段,SurfaceFlinger建立Client物件:
- sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection()
- {
- Mutex::Autolock _l(mStateLock);
- uint32_t token = mTokens.acquire();
- sp<Client> client = new Client(token, this);
- if (client->ctrlblk == 0) {
- mTokens.release(token);
- return 0;
- }
- status_t err = mClientsMap.add(token, client);
- if (err < 0) {
- mTokens.release(token);
- return 0;
- }
- sp<BClient> bclient =
- new BClient(this, token, client->getControlBlockMemory());
- return bclient;
- }
- 再進入Client的建構函式中,它分配了4K大小的共享記憶體,並在這塊記憶體上構建了SharedClient物件:
- Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger)
- : ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)
- {
- constint pgsize = getpagesize();
- constint cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1));
- mCblkHeap = new MemoryHeapBase(cblksize, 0,
- "SurfaceFlinger Client control-block");
- ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase());
- if (ctrlblk) { // construct the shared structure in-place.
- new(ctrlblk) SharedClient;
- }
- }
- 回到createConnection中,通過Client的getControlBlockMemory()方法獲得共享記憶體塊的 IMemoryHeap介面,接著建立ISurfaceFlingerClient的子類BClient,BClient的成員變數mCblk儲存了 IMemoryHeap介面指標;
- 把BClient返回給SurfaceComposerClient,SurfaceComposerClient通過 ISurfaceFlingerClient介面的getControlBlock()方法獲得IMemoryHeap介面指標,同時儲存在 SurfaceComposerClient的成員變數mControlMemory中;
- 繼續通過IMemoryHeap介面的getBase ()方法獲取共享記憶體的首地址,轉換為SharedClient指標後儲存在SurfaceComposerClient的成員變數mControl中;
- 至此,SurfaceComposerClient的成員變數mControl和SurfaceFlinger::Client.ctrlblk 指向了同一個記憶體塊,該記憶體塊上就是SharedClient物件。
2. SharedBufferStack、SharedBufferServer、SharedBufferClient
SharedClient物件中有一個SharedBufferStack陣列:
SharedBufferStack surfaces[ NUM_LAYERS_MAX ];
NUM_LAYERS_MAX 被定義為31,這樣保證了SharedClient物件的大小正好滿足4KB的要求。建立一個新的Surface時,進入SurfaceFlinger的 createSurface函式後,先取在createConnection階段建立的Client物件,通過Client在 0--NUM_LAYERS_MAX 之間取得一個尚未被使用的編號,這個編號實際上就是SharedBufferStack陣列的索引:
[c-sharp] view plaincopyprint?- int32_t id = client->generateId(pid);
然後以Client物件和索引值以及其他引數,建立不同型別的Layer物件,一普通的Layer物件為例:
[c-sharp] view plaincopyprint?- layer = createNormalSurfaceLocked(client, d, id,
- w, h, flags, format);
在createNormalSurfaceLocked中建立Layer物件:
[c-sharp] view plaincopyprint?- sp<Layer> layer = new Layer(this, display, client, id);
構造Layer時會先構造的父類LayerBaseClient,LayerBaseClient中建立了SharedBufferServer物件,SharedBufferStack 陣列的索引值和SharedClient被傳入SharedBufferServer物件中。
[c-sharp] view plaincopyprint?- LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
- const sp<Client>& client, int32_t i)
- : LayerBase(flinger, display), lcblk(NULL), client(client), mIndex(i),
- mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
- {
- lcblk = new SharedBufferServer(
- client->ctrlblk, i, NUM_BUFFERS,
- mIdentity);
- }
自此,Layer通過lcblk成員變數(SharedBufferServer)和SharedClient共享記憶體區建立了關聯,並且每個Layer 對應於SharedBufferStack 陣列中的一項。
回到SurfaceFlinger的客戶端Surface.cpp中,Surface的建構函式如下:
[c-sharp] view plaincopyprint?- Surface::Surface(const sp<SurfaceControl>& surface)
- : mClient(surface->mClient), mSurface(surface->mSurface),
- mToken(surface->mToken), mIdentity(surface->mIdentity),
- mFormat(surface->mFormat), mFlags(surface->mFlags),
- mBufferMapper(GraphicBufferMapper::get()), mSharedBufferClient(NULL),
- mWidth(surface->mWidth), mHeight(surface->mHeight)
- {
- mSharedBufferClient = new SharedBufferClient(
- mClient->mControl, mToken, 2, mIdentity);
- init();
- }
SharedBufferClient構造引數mClient->mControl就是共享記憶體塊中的SharedClient物件,mToken就是SharedBufferStack 陣列索引值。
到這裡我們終於知道,Surface中的 mSharedBufferClient成員和Layer中的lcblk成員(SharedBufferServer),通過SharedClient中的同一個SharedBufferStack,共同管理著Surface(Layer)中的兩個緩衝區補充一點上面說的邏輯結構都是針對一個APK和surfaceflinger來說的。