在前面一篇文章中,我們分析了Android應用程式與SurfaceFlinger服務的串連過程。Android應用程式成功串連上SurfaceFlinger服務之後,還需要一塊匿名共用記憶體來和SurfaceFlinger服務共用它的UI中繼資料,以便使得SurfaceFlinger服務可以正確地為它建立以及渲染Surface。在本文中,我們將詳細地分析這塊用來儲存UI中繼資料的匿名共用記憶體的建立過程。
在Android應用程式與SurfaceFlinger服務的關係概述和學習計劃一文中提到,用來儲存Android應用程式的UI中繼資料的匿名共用記憶體最終是被結構化為一個SharedClient對象來訪問的。每一個與UI有關的Android應用程式進程有且僅有一個SharedClient對象,而且這些SharedClient對象是由Android應用程式請求SurfaceFlinger服務建立的:Android應用程式首先獲得SurfaceFlinger服務的一個Binder代理介面,然後再通過這個代理介面得到另外一個類型為UserClient的Binder代理介面,最後就可以通過後一個Binder代理介面來獲得一個SharedClient對象。
由於每一個與UI有關的Android應用程式進程有且僅有一個SharedClient對象,因此,Android系統就通過一個單例模式的類來專負責建立和管理這個SharedClient對象。這個類的名稱為SurfaceClient,定義在frameworks/base/libs/surfaceflinger_client/Surface.cpp檔案中,如下所示:
class SurfaceClient : public Singleton<SurfaceClient>{ // all these attributes are constants sp<ISurfaceComposer> mComposerService; sp<ISurfaceComposerClient> mClient; status_t mStatus; SharedClient* mControl; sp<IMemoryHeap> mControlMemory; SurfaceClient() : Singleton<SurfaceClient>(), mStatus(NO_INIT) { sp<ISurfaceComposer> sf(ComposerService::getComposerService()); mComposerService = sf; mClient = sf->createClientConnection(); if (mClient != NULL) { mControlMemory = mClient->getControlBlock(); if (mControlMemory != NULL) { mControl = static_cast<SharedClient *>( mControlMemory->getBase()); if (mControl) { mStatus = NO_ERROR; } } } } friend class Singleton<SurfaceClient>;public: status_t initCheck() const { return mStatus; } SharedClient* getSharedClient() const { return mControl; } ssize_t getTokenForSurface(const sp<ISurface>& sur) const { // TODO: we could cache a few tokens here to avoid an IPC return mClient->getTokenForSurface(sur); } void signalServer() const { mComposerService->signal(); }};
當SurfaceClient類的靜態成員函數getInstance第一次被調用的時候,系統就會在對應的應用程式進程中建立一個SurfaceClient對象,即會調用SurfaceClient類的建構函式。SurfaceClient類的建構函式首先會調用ComposerService類的靜態成員函數getComposerService來獲得一個SurfaceFlinger服務的代理介面,並且儲存在SurfaceClient類的成員變數mComposerService中,以便以後可以使用。ComposerService類的靜態成員函數getComposerService在前面Android應用程式與SurfaceFlinger服務的串連過程分析一文中已經分析過了,這裡不再詳述。有了SurfaceFlinger服務的代理介面sf之後,SurfaceClient類的建構函式接著就可以調用它的成員函數createClientConnection來獲得一個類型為UserClient的Binder代理介面,這個Binder代理介面實現了ISurfaceComposerClient介面,因此,我們可以將它儲存在SurfaceClient類的成員變數mClient中。最後,SurfaceClient類的建構函式就調用前面獲得的類型為ISurfaceComposerClient的Binder代理介面mClient的成員函數getControlBlock來獲得一塊用來描述應用程式UI中繼資料的匿名共用記憶體mControlMemory ,並且將這些匿名共用記憶體強制轉化為一個SharedClient對象mControl,以便後面可以方便地訪問UI中繼資料。
以上就是Android應用程式與SurfaceFlinger服務之間的共用UI中繼資料(SharedClient)的建立過程的總體描述,接下來我們再詳細分析每一步的實現。現在,我們繼續分析一下SurfaceClient類的其餘成員函數的實現:
1. 成員函數initCheck用來檢查一個Android應用程式進程是否已經成功地請求SurfaceFlinger服務建立了一塊用來描述UI中繼資料的SharedClient對象了。
2. 成員函數getSharedClient用來返回用來描述UI中繼資料的SharedClient對象mControl。
3. 成員函數getTokenForSurface用來返回由參數sur所描述的一個Surface的Token值。這個Token值由SurfaceFlinger服務來建立和管理,並且可以通過前面所獲得的類型為UserClient的Binder代理介面mClient的成員函數getTokenSurface來獲得。
4. 成員函數signalServer用來通知SurfaceFlinger服務更新Android應用程式UI,這是通過調用SurfaceFlinger服務的代理介面mComposerService的成員函數signal來實現的,實際上就是向SurfaceFlinger服務發送一個訊號,以便可以將它喚醒起來更新UI。
介紹完成SurfaceClient類的實現之後,我們還需要瞭解一下兩個類的實現,即UserClient類和SharedClient類的實現,以便可以協助我們瞭解用來儲存Android應用程式的UI中繼資料的匿名共用記憶體的建立過程,以及協助後面兩篇文章對Surface的建立和渲染過程的分析。
接下來,我們就首先分析UserClient類的實現,接著再分析SharedClient類的實現。
在Android應用程式與SurfaceFlinger服務的串連過程分析一文的圖2中,我們介紹了用來串連Android應用程式和SurfaceFlinger服務的Client類,而UserClient類和Client類是類似的,它們都實現了相同的介面,只不過是側重點有所不同。Android應用程式與SurfaceFlinger服務的串連過程分析一文的圖2中的Client類替換成UserClient類,就可以得到UserClient類的實現結構圖,1所示:
圖1 UserClient類的實現結構圖
UserClient類與Client類最重要的區別是,前者實現了ISurfaceComposerClient介面的成員函數getControlBlock,而後者實現了ISurfaceComposerClient介面的成員函數createSurface。後面我們就會分析UserClient類是如何?ISurfaceComposerClient介面的成員函數getControlBlock的。
UserClient類的實現暫時就介紹到這裡,接下來我們來看SharedClient類的實現。為了方便描述,我們把Android應用程式與SurfaceFlinger服務的關係概述和學習計劃一文的圖4和圖5貼出來,如以2和圖3所示:
圖2 用來描述Android應用程式的UI中繼資料的SharedClient
圖3 SharedBufferStack的結構
每一個SharedClient對象包含了至多31個SharedBufferStack,而每一個SharedBufferStack都對應一個Android應用程式進程中的一個Surface。
SharedClient類定義在檔案frameworks/base/include/private/surfaceflinger/SharedBufferStack.h 檔案中,如下所示:
class SharedClient{public: SharedClient(); ~SharedClient(); ......private: ...... SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ];};
它有一個大小為SharedBufferStack::NUM_LAYERS_MAX的SharedBufferStack數組。SharedBufferStack::NUM_LAYERS_MAX的值等於31,定義在SharedBufferStack類中。
SharedBufferStack類同樣是定義在檔案frameworks/base/include/private/surfaceflinger/SharedBufferStack.h 檔案中,如下所示:
class SharedBufferStack{ ......public: // When changing these values, the COMPILE_TIME_ASSERT at the end of this // file need to be updated. static const unsigned int NUM_LAYERS_MAX = 31; static const unsigned int NUM_BUFFER_MAX = 16; static const unsigned int NUM_BUFFER_MIN = 2; static const unsigned int NUM_DISPLAY_MAX = 4; ...... struct SmallRect { uint16_t l, t, r, b; }; struct FlatRegion { static const unsigned int NUM_RECT_MAX = 5; uint32_t count; SmallRect rects[NUM_RECT_MAX]; }; struct BufferData { FlatRegion dirtyRegion; SmallRect crop; uint8_t transform; uint8_t reserved[3]; }; SharedBufferStack(); ...... status_t setDirtyRegion(int buffer, const Region& reg); status_t setCrop(int buffer, const Rect& reg); status_t setTransform(int buffer, uint8_t transform); Region getDirtyRegion(int buffer) const; Rect getCrop(int buffer) const; uint32_t getTransform(int buffer) const; // these attributes are part of the conditions/updates volatile int32_t head; // server's current front buffer volatile int32_t available; // number of dequeue-able buffers volatile int32_t queued; // number of buffers waiting for post ...... // not part of the conditions ...... volatile int8_t index[NUM_BUFFER_MAX]; ...... int8_t headBuf; // last retired buffer ...... BufferData buffers[NUM_BUFFER_MAX]; };
下面我們簡要地對SharedBufferStack類進行分析。
首先,SharedBufferStack類在內部定義了四個常量:
NUM_LAYERS_MAX -- 表示一個Android應用程式最多可以有NUM_LAYERS_MAX個Layer,可以將一個Layer理解為一個Surface。
NUM_BUFFER_MAX -- 表示一個SharedBufferStack至多可以有NUM_BUFFER_MAX個UI中繼資料緩衝區。
NUM_BUFFER_MIN -- 表示一個SharedBufferStack至少要有UM_BUFFER_MIN個UI中繼資料緩衝區。
NUM_DISPLAY_MAX -- 表示Android系統至多可以支援NUM_DISPLAY_MAX個顯示屏。
從這些常量就可以看出:
1. Android系統至多支援4個顯示屏。
2. 一個Android應用程式至多可以同時建立31個Surface。
3. 一個Surface可以有2~16個UI中繼資料緩衝區,即可以使用2~16緩衝區技術來渲染Surface。
其次,SharedBufferStack類在內部定義了三個結構體:
SmallRect -- 用來描述一個矩形地區,其中,成員變數l、t,、r和b分別表示左上和右下兩個角的位置。
FlatRegion -- 用來描述一個SmallRect數組rects ,數組的大小為NUM_RECT_MAX,但是實際個數為count。
BufferData -- 用來描述一個UI中繼資料緩衝區,它有四個成員變數dirtyRegion、crop、transform和reserved,其中,dirtyRegion用來描述一個Surface需要更新的地區,即裁剪地區,crop用來描述一個Surface的紋理座標,transform用來描述一個Surface的旋轉方向,例如,旋轉90度或者上下翻轉等等,而reserved是保留給以後使用的。通過這個UI中繼資料緩衝區,SurfaceFlinger服務就可以正確地把一個Surface的圖形緩衝區所描述的圖形渲染到螢幕來。
SharedBufferStack類有一個BufferData數組buffers,它的大小為NUM_BUFFER_MAX,即16,就是用來一組UI中繼資料緩衝區的,這些UI中繼資料緩衝區的內容可以分別通過setDirtyRegion、setCrop、setTransform、getDirtyRegion、getCrop和getTransform這六個成員函數來訪問。這六個成員函數的第一個參數均為一個int值,用來描述要訪問的是哪一個BufferData的資料。
SharedBufferStack類還有另外一個類型為int8_t的數組index,它的大小也為NUM_BUFFER_MAX。這個index數組才是一個真正的Stack,它按照一定的規則來訪問。index數組的每一個元素的值均是一個索引值,用來映射到數組buffers中去的。例如,假設index[0]的值等於2,那麼它就對應數組buffers中的第2個元素,即buffers[2]。
SharedBufferStack類的其餘重要成員變數的含義如下所示:
head -- 用來描述一個SharedBufferStack的頭部,它是一個索引值,是映射到數組index中去的。
available -- 用來描述一個SharedBufferStack中的空閑UI中繼資料緩衝區的個數。
queued -- 用來描述一個SharedBufferStack中的已經補使用了的UI中繼資料緩衝區的個數,即那些在排隊等待SurfaceFlinger服務使用的UI中繼資料緩衝區。
headBuf -- 用來描述一個SharedBufferStack的頭部所對應的UI中繼資料緩衝區的編號,這個編號是映射到數組buffers中去。
關於SharedBufferStack類的實現,我們就暫時介紹到這裡,在下一篇文章分析Android應用程式的Surface建立過程時,我們再通過SharedBufferServer類和SharedBufferClient類的實現來進一步理解SharedBufferStack類的實現。
現在,我們就開始詳細分析Android應用程式與SurfaceFlinger服務之間的共用UI中繼資料的建立過程,4所示:
圖 4 Android應用程式的共用UI中繼資料的建立過程
接下來我們就詳細分析每一個步驟。
Step 1. SurfaceFlinger::createClientConnection
sp<ISurfaceComposerClient> SurfaceFlinger::createClientConnection(){ sp<ISurfaceComposerClient> bclient; sp<UserClient> client(new UserClient(this)); status_t err = client->initCheck(); if (err == NO_ERROR) { bclient = client; } return bclient;}
SurfaceFlinger類的成員函數createClientConnection實現在檔案frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中,它的實現很簡單,只是建立了一個類型為UserClient的Binder對象client,並且獲得它的一個ISurfaceComposerClient介面,最後將這個ISurfaceComposerClient介面,即一個UserClient代理對象,返回給Android應用程式進程。
接下來,我們再繼續分析UserClient對象的建立過程,,即UserClient類的建構函式的實現。
Step 2. new UserClient
UserClient::UserClient(const sp<SurfaceFlinger>& flinger) : ctrlblk(0), mBitmap(0), mFlinger(flinger){ const int pgsize = getpagesize(); const int 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; }}
UserClient類的成員變數mFlinger是一個類型為SurfaceFlinger的強指標,它指向了SurfaceFlinger服務, UserClient類的另外一個成員變數mBitmap是一個int32_t值,它是用來為Android應用程式的Surface分配Token值的,即如果它的第n位等於1,那麼就表示值等於n的Token已經被分配出去使用了。
UserClient類的建構函式首先得到一個SharedClient對象的大小,接著再將這個大小對齊到頁面邊界,於是就得到了接下來要建立的匿名共用塊的大小cblksize。這塊匿名共用記憶體是一個MemoryHeapBase對象描述的,並且儲存在UserClient類的成員變數mCblkHeap。MemoryHeapBase類是用來建立匿名共用記憶體的一個C++介面,它的實現原理可以參考Android系統匿名共用記憶體(Anonymous Shared Memory)C++調用介面分析一文。
UserClient類的建構函式得到了一塊匿名共用記憶體之後,緊接著就在這塊匿名共用記憶體上建立了一個SharedClient對象,並且儲存在UserClient類的成員變數ctrlblk中,以便後面可以通過它來訪問Android應用程式的UI中繼資料。
回到SurfaceFlinger類的成員函數createClientConnection中,它將一個指向了一個UserClient對象的ISurfaceComposerClient介面返回到Android應用程式進程之後,Android應用程式進程就可以將它封裝成一個類型為BpSurfaceComposerClient的Binder代理對象。
Step 3. return BpSurfaceComposerClient
將一個Binder代理對象封裝成一個BpSurfaceComposerClient的過程可以參考前面Android應用程式與SurfaceFlinger服務的串連過程分析一文中的Step 4。
Step 4. UserClient::getControlBlock
sp<IMemoryHeap> UserClient::getControlBlock() const { return mCblkHeap;}
從前面的Step 2可以知道,UserClient類的成員變數mCblkHeap指向了一塊匿名共用記憶體,UserClient類將這塊匿名共用記憶體返回給Android應用程式之後,Android應用程式就會將它結構化成一個SharedClient對象來訪問,並且儲存在SurfaceClient類的成員變數mControl中,這個結構化過程就可以參考前面所描述的SurfaceClient類的建構函式了。
至此,用來描述Android應用程式的UI中繼資料的一個SharedClient對象的建立過程就分析完了。以後當Android應用程式請求SurfaceFlinger服務建立一個Surface的時候,SurfaceFlinger服務就會從這個SharedClient對象中取出一個SharedBufferStack出來,以便可以用作這個Surface的UI中繼資料緩衝區。在接下來的一篇文章中,我們將詳細描述Android應用程式請求SurfaceFlinger服務建立Surface的過程,敬請期待!
老羅的新浪微博:http://weibo.com/shengyangluo,歡迎關注!