古詩詞大全網 - 成語經典 - SurfaceFlinger 原理分析

SurfaceFlinger 原理分析

SurfaceFlinger是Android multimedia的壹個部分,在Android 的實現中它是壹個service,提供系統範圍內的surface composer功能,它能夠將各種應用程序的2D、3D surface進行組合。

每個應用程序可能對應著壹個或者多個圖形界面,而每個界面我們就稱之為壹個surface ,或者說是window ,在上面的圖中我們能看到4 個surface ,壹個是home 界面,還有就是紅、綠、藍分別代表的3個surface ,而兩個button 實際是home surface 裏面的內容。我們需要考慮壹下情況:

在實際中對這些Surface 進行merge 可以采用兩種方式,壹種就是采用軟件的形式來merge ,還壹種就是采用硬件的方式,軟件的方式就是我們的 SurfaceFlinger ,而硬件的方式就是 Overlay

因為硬件merge 內容相對簡單,我們首先來看overlay 。以IMX51 為例子,當IPU 向內核申請FB 的時候它會申請3 個FB ,壹個是主屏的,還壹個是副屏的,還壹個就是Overlay 的。 簡單地來說,Overlay就是我們將硬件所能接受的格式數據和控制信息送到這個Overlay FrameBuffer,由硬件驅動來負責merge Overlay buffer和主屏buffer中的內容。

壹般來說現在的硬件都只支持壹個Overlay,主要用在視頻播放以及camera preview上,因為視頻內容的不斷變化用硬件Merge比用軟件Merge要有效率得多,下面就是使用Overlay和不使用Overlay的過程:

surfaceFlinger 只是負責 merge Surface 的控制,比如說計算出兩個 Surface 重疊的區域,至於 Surface 需要顯示的內容,則通過 skia,opengl 和 pixflinger 來計算。

創建過程

SurfaceFlinger 是壹個線程類,它繼承了 Thread 類。當創建 SurfaceFlinger 這個服務的時候會啟動壹個 SurfaceFlinger 監聽線程,這個線程會壹直等待事件的發生,比如說需要進行 sruface flip ,或者說窗口位置大小發生了變化等,壹旦產生這些事件,SurfaceComposerClient 就會通過 IBinder 發出信號,這個線程就會結束等待處理這些事件,處理完成以後會繼續等待,如此循環。

SurfaceComposerClient 和 SurfaceFlinger 是通過 SurfaceFlingerSynchro 這個類來同步信號的,其實說穿了就是壹個條件變量。監聽線程等待條件的值壹旦變成 OPEN 就結束等待並將條件置成 CLOSE 然後進行事件處理,處理完成以後再繼續等待條件的值變成 OPEN ,而 Client 的Surface 壹旦改變就通過 IBinder 通知 SurfaceFlinger 將條件變量的值變成 OPEN ,並喚醒等待的線程,這樣就通過線程類和條件變量實現了壹個動態處理機制。

窗口狀態變化的處理是壹個很復雜的過程,SurfaceFlinger 只是執行 Windows Manager 的指令,由 Windows manager 來決定什麽是偶改變大小、位置、透明度、以及如何調整layer 之間的順序, SurfaceFlinger 僅僅只是執行它的指令。

普通的Android控件,例如TextView、Button和CheckBox等,它們都是將自己的UI繪制在宿主窗口的繪圖表面之上,這意味著它們的UI是在應用程序的主線程中進行繪制的。由於應用程序的主線程除了要繪制UI之外,還需要及時地響應用戶輸入,否則系統就會認為應用程序沒有響應了。而對於壹些遊戲畫面,或者攝像頭預覽、視頻播放來說,它們的UI都比較復雜,而且要求能夠進行高效的繪制。這時候就必須要給那些需要復雜而高效UI的視圖生成壹個獨立的繪圖表面,以及使用壹個獨立的線程來繪制這些視圖的UI。

SurfaceFlinger服務運行在Android系統的System進程中,它負責管理Android系統的幀緩沖區(Frame Buffer)。Android應用程序為了能夠將自己的UI繪制在系統的幀緩沖區上,它們就必須要與SurfaceFlinger服務進行通信。

在APP端執行draw的時候,數據很明顯是要繪制到APP的進程空間,但是視圖窗口要經過SurfaceFlinger圖層混排才會生成最終的幀,而SurfaceFlinger又運行在另壹個獨立的服務進程,那麽View視圖的數據是如何在兩個進程間傳遞的呢,普通的Binder通信肯定不行,因為Binder不太適合這種數據量較大的通信,那麽View數據的通信采用的是什麽IPC手段呢?答案就是***享內存,更精確的說是匿名***享內存。***享內存是Linux自帶的壹種IPC機制,Android直接使用了該模型,不過做出了自己的改進,進而形成了Android的匿名***享內存(Anonymous Shared Memory-Ashmem)。通過Ashmem,APP進程同SurfaceFlinger***用壹塊內存,如此,就不需要進行數據拷貝,APP端繪制完畢,通知SurfaceFlinger端合成,再輸出到硬件進行顯示即可。

在每壹個Android應用程序與SurfaceFlinger服務之間的連接上加上壹塊用來傳遞UI元數據的匿名***享內存,這個***享內存就是 SharedClient

在每壹個SharedClient裏面,有至多31個SharedBufferStack。SharedBufferStack就是Android應用程序和SurfaceFlinger 的緩沖區堆棧。用來緩沖 UI 元數據。

壹般我們就繪制UI的時候,都會采用壹種稱為“雙緩沖”的技術。雙緩沖意味著要使用兩個緩沖區,其中壹個稱為Front Buffer,另外壹個稱為Back Buffer。UI總是先在Back Buffer中繪制,然後再和Front Buffer交換,渲染到顯示設備中。這下就可以理解SharedBufferStack的含義了吧?SurfaceFlinger服務只不過是將傳統的“雙緩沖”技術升華和抽象為了壹個SharedBufferStack。可別小看了這個升華和抽象,有了SharedBufferStack之後,SurfaceFlinger 服務就可以使用N個緩沖區技術來繪制UI了。N值的取值範圍為2到16。例如,在Android 2.3中,N的值等於2,而在Android 4.1中,據說就等於3了。

在SurfaceFlinger服務中,每壹個SharedBufferStack都對應壹個Surface,即壹個窗口。這樣,我們就可以知道為什麽每壹個SharedClient裏面包含的是壹系列SharedBufferStack而不是單個SharedBufferStack: 壹個SharedClient對應壹個Android應用程序,而壹個Android應用程序可能包含有多個窗口 ,即Surface。從這裏也可以看出,壹個Android應用程序至多可以包含31個Surface。

SharedBufferStack中的 緩沖區只是用來描述UI元數據的 ,這意味著它們不包含真正的UI數據。 真正的UI數據保存在GraphicBuffer中 ,後面我們再描述GaphicBuffer。因此,為了完整地描述壹個UI,SharedBufferStack中的每壹個已經使用了的緩沖區都對應有壹個GraphicBuffer,用來描述真正的UI數據。當SurfaceFlinger服務緩制Buffer-1和Buffer-2的時候,就會找到與它們所對應的GraphicBuffer,這樣就可以將對應的UI繪制出來了。

當Android應用程序需要 更新壹個Surface 的時候,它就會找到與它所對應的SharedBufferStack,並且從它的空閑緩沖區列表的尾部取出壹個空閑的Buffer。我們假設這個取出來的空閑Buffer的編號為index。接下來Android應用程序就請求SurfaceFlinger服務為這個編號為index的 Buffer分配壹個圖形緩沖區GraphicBuffer

SurfaceFlinger 服務分配好圖形緩沖區 GraphicBuffer 之後,會將它的編號設置為 index,然後再將這個圖形緩沖區 GraphicBuffer 返回給 Android 應用程序訪問。Android應用程序得到了 SurfaceFlinger 服務返回的圖形緩沖區 GraphicBuffer 之後,就在裏面 寫入UI數據 。寫完之後,就將與它所對應的緩沖區,即編號為 index 的 Buffer,插入到對應的 SharedBufferStack 的已經使用了的 緩沖區列表的頭部 去。這壹步完成了之後,Android 應用程序就通知 SurfaceFlinger 服務去繪制那些保存在已經使用了的緩沖區所描述的圖形緩沖區GraphicBuffer了。用上面例子來說,SurfaceFlinger服務需要繪制的是編號為1和2的Buffer所對應的圖形緩沖區GraphicBuffer。由於SurfaceFlinger服務知道編號為1和2的 Buffer 所對應的圖形緩沖區 GraphicBuffer 在哪裏,因此,Android 應用程序只需要告訴 SurfaceFlinger 服務要繪制的 Buffer 的編號就OK了。 當壹個已經被使用了的Buffer被繪制了之後,它就重新變成壹個空閑的 Buffer 了

SharedBufferStack 是在 Android 應用程序和 SurfaceFlinger 服務之間***享的,但是,Android 應用程序和 SurfaceFlinger 服務使用 SharedBufferStack 的方式是不壹樣的,具體來說,就是 Android 應用程序關心的是它裏面的空閑緩沖區列表,而 SurfaceFlinger 服務關心的是它裏面的已經使用了的緩沖區列表。從SurfaceFlinger服務的角度來看,保存在 SharedBufferStack中 的已經使用了的緩沖區其實就是在排隊等待渲染。

為了方便 SharedBufferStack 在 Android 應用程序和 SurfaceFlinger 服務中的訪問,Android 系統分別使用 SharedBufferClient 和 SharedBufferServer 來描述 SharedBufferStack ,其中,SharedBufferClient 用來在Android 應用程序這壹側訪問 SharedBufferStack 的空閑緩沖區列表,而 SharedBufferServer 用來在SurfaceFlinger 服務這壹側訪問 SharedBufferStack 的排隊緩沖區列表。

只要 SharedBufferStack 中的 available 的 buffer 的數量大於0, SharedBufferClient 就會將指針 tail 往前移壹步,並且減少 available 的值,以便可以獲得壹個空閑的 Buffer。當 Android 應用程序往這個空閑的 Buffer 寫入好數據之後,它就會通過 SharedBufferClient 來將它添加到 SharedBufferStack 中的排隊緩沖區列表的尾部去,即指針 queue_head 的下壹個位置上。

當 Android 應用程序通知 SurfaceFlinger 服務更新UI的時候,只要對應的 SharedBufferStack 中的 queued 的緩沖區的數量大於0,SharedBufferServer 就會將指針 head 的下壹個Buffer繪制出來,並且將指針 head 向前移壹步,以及將 queued 的值減1。

參考:

/luoshengyang/article/details/7846923