Android應用程序與SurfaceFlinger服務之間的共享UI元數據(SharedClient)的創建過程分析

 在前面一篇文章中,我們分析瞭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文件中,如下所示:

[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類的構造函數接著就可以調用它的成員函數createUserClient來獲得一個類型為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 文件中,如下所示:

[cpp] 
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 文件中,如下所示:

[cpp] 
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

[cpp]
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

[cpp] 
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

[cpp] 
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的過程,敬請期待!

發佈留言