Android SurfaceFlinger中的SharedClient

來源:互聯網
上載者:User
文章目錄
  •     1. SharedClient
  •     2. SharedBufferStack、SharedBufferServer、SharedBufferClient

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:

 

view plain
  1. void SurfaceComposerClient::_init(  
  2.         const sp<ISurfaceComposer>& sm, const sp<ISurfaceFlingerClient>& conn)  
  3. {  
  4.     ......  
  5.     mClient = conn;  
  6.     if (mClient == 0) {  
  7.         mStatus = NO_INIT;  
  8.         return;  
  9.     }  
  10.   
  11.     mControlMemory = mClient->getControlBlock();  
  12.     mSignalServer = sm;  
  13.     mControl = static_cast<SharedClient *>(mControlMemory->getBase());  
  14. }  
獲得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對象:
view plain
  1. sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection()  
  2. {  
  3.     Mutex::Autolock _l(mStateLock);  
  4.     uint32_t token = mTokens.acquire();  
  5.   
  6.     sp<Client> client = new Client(token, this);  
  7.     if (client->ctrlblk == 0) {  
  8.         mTokens.release(token);  
  9.         return 0;  
  10.     }  
  11.     status_t err = mClientsMap.add(token, client);  
  12.     if (err < 0) {  
  13.         mTokens.release(token);  
  14.         return 0;  
  15.     }  
  16.     sp<BClient> bclient =  
  17.         new BClient(this, token, client->getControlBlockMemory());  
  18.     return bclient;  
  19. }  
  • 再進入Client的建構函式中,它分配了4K大小的共用記憶體,並在這塊記憶體上構建了SharedClient對象:
view plain
  1. Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger)  
  2.     : ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)  
  3. {  
  4.     const int pgsize = getpagesize();  
  5.     const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1));  
  6.   
  7.     mCblkHeap = new MemoryHeapBase(cblksize, 0,  
  8.             "SurfaceFlinger Client control-block");  
  9.   
  10.     ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase());  
  11.     if (ctrlblk) { // construct the shared structure in-place.  
  12.         new(ctrlblk) SharedClient;  
  13.     }  
  14. }  
  • 回到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數組的索引:

view plain
  1. int32_t id = client->generateId(pid);  

  

 然後以Client對象和索引值以及其他參數,建立不同類型的Layer對象,一普通的Layer對象為例:

view plain
  1. layer = createNormalSurfaceLocked(client, d, id,  
  2.                         w, h, flags, format);  

在createNormalSurfaceLocked中建立Layer對象:

view plain
  1. sp<Layer> layer = new Layer(this, display, client, id);  

構造Layer時會先構造的父類LayerBaseClient,LayerBaseClient中建立了SharedBufferServer對象,SharedBufferStack 數組的索引值和SharedClient被傳入SharedBufferServer對象中。

view plain
  1. LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,  
  2.         const sp<Client>& client, int32_t i)  
  3.     : LayerBase(flinger, display), lcblk(NULL), client(client), mIndex(i),  
  4.       mIdentity(uint32_t(android_atomic_inc(&sIdentity)))  
  5. {  
  6.     lcblk = new SharedBufferServer(  
  7.             client->ctrlblk, i, NUM_BUFFERS,  
  8.             mIdentity);  
  9. }  

 

    自此,Layer通過lcblk成員變數(SharedBufferServer)和SharedClient共用記憶體區建立了關聯,並且每個Layer對應於SharedBufferStack 數組中的一項。

    回到SurfaceFlinger的用戶端Surface.cpp中,Surface的建構函式如下:

view plain
  1. Surface::Surface(const sp<SurfaceControl>& surface)  
  2.     : mClient(surface->mClient), mSurface(surface->mSurface),  
  3.       mToken(surface->mToken), mIdentity(surface->mIdentity),  
  4.       mFormat(surface->mFormat), mFlags(surface->mFlags),  
  5.       mBufferMapper(GraphicBufferMapper::get()), mSharedBufferClient(NULL),  
  6.       mWidth(surface->mWidth), mHeight(surface->mHeight)  
  7. {  
  8.     mSharedBufferClient = new SharedBufferClient(  
  9.             mClient->mControl, mToken, 2, mIdentity);  
  10.   
  11.     init();  
  12. }  

SharedBufferClient構造參數mClient->mControl就是共用記憶體塊中的SharedClient對象,mToken就是SharedBufferStack 數組索引值。

到這裡我們終於知道,Surface中的mSharedBufferClient成員和Layer中的lcblk成員(SharedBufferServer),通過SharedClient中的同一個SharedBufferStack,共同管理著Surface(Layer)中的兩個緩衝區。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.