3.2 、應用 程序對窗口的控制和畫圖php
Surface 建立之後,應用程序就能夠在 buffer 中畫圖了,這裏就面對着兩個問題了,一個是怎麼知道在哪一個 buffer 上來畫圖,還一個就是畫圖之後如何通知 SurfaceFlinger 來進行 flip 。除了畫圖以外,若是咱們移動窗口以及改變窗口大小的時候,如何告訴SurfaceFlinger 來進行處理呢 ?在明白這些問題以前,首先咱們要了解 SurfaceFlinger 這個服務 是如何運做的:java
從類圖中能夠看到 SurfaceFlinger 是一個線程類,它繼承了 Thread 類。當建立 SurfaceFlinger 這個服務的時候會啓動一個SurfaceFlinger 監聽線程,這個線程會一直等待事件的發生,好比說須要進行 sruface flip ,或者說窗口位置大小發生了變化等等,一旦產生這些事件, SurfaceComposerClient 就會經過 IBinder 發出信號,這個線程就會結束等待處理這些事件,處理完成之後會繼續等待,如此循環。ide
SurfaceComposerClient 和 SurfaceFlinger 是經過 SurfaceFlingerSynchro 這個類來同步信號的,其實說穿了就是一個條件變量。監聽線程等待條件的值變成 OPEN ,一旦變成 OPEN 就結束等待並將條件置成 CLOSE 而後進行事件處理,處理完成之後再繼續等待條件的值變成OPEN ,而 Client 的 Surface 一旦改變就經過 IBinder 通知 SurfaceFlinger 將條件變量的值變成 OPEN ,並喚醒等待的線程,這樣就經過線程類和條件變量實現了一個動態處理機制。post
瞭解了 SurfaceFlinger 的事件機制咱們再回頭看看前面提到的問題了。首先在對 Surface 進行畫圖以前必須鎖定 Surface 的 layer ,實際上就是鎖定了 Layer_cblk_t 裏的 swapstate 這個變量。 SurfaceComposerClient 經過 swapsate 的值來肯定要使用哪一個 buffer 畫圖,若是 swapstate 是下面的值就會阻塞 Client ,就不翻譯了直接 copy 過來:ui
// We block the client if:this
// eNextFlipPending: we've used both buffers already, so we need tospa
// wait for one to become availlable..net
// eResizeRequested: the buffer we're going to acquire is being線程
// resized. Block until it is done.翻譯
// eFlipRequested && eBusy: the buffer we're going to acquire is
// currently in use by the server.
// eInvalidSurface: this is a special case, we don't block in this
// case, we just return an error.
因此應用程序先調用 lockSurface() 鎖定 layer 的 swapstate ,並得到畫圖的 buffer 而後就能夠在上面進行畫圖了,完成之後就會調用 unlockSurfaceAndPost() 來通知 SurfaceFlinger 進行 Flip 。或者僅僅調用 unlockSurface() 而不通知 SurfaceFlinger 。
通常來講畫圖的過程須要重繪 Surface 上的全部像素,由於通常狀況下顯示事後的像素是不作保存的,不過也能夠經過設定來保存一些像素,而只繪製部分像素,這裏就涉及到像素的拷貝了,須要將 Front buffer 的內容拷貝到 Back buffer 。在 SurfaceFlinger 服務實現中像素的拷貝是常常須要進行的操做,並且還可能涉及拷貝過程的轉換,好比說屏幕的旋轉,翻轉等一系列操做。所以 Android 提供了拷貝像素的 hal ,這個也多是咱們未來須要實現的,由於用硬件完成像素的拷貝,以及拷貝過程當中可能的矩陣變換等操做,比用 memcpy 要有效率並且節省資源。這個 HAL 頭文件 在: /hardware/libhardware/hardware/include/copybit.h
窗口狀態變化的處理是一個很複雜的過程,首先要說明一下, SurfaceFlinger 只是執行 Windows manager 的指令,由 Windows manager 來決定什麼是偶改變大小,位置,設置 透明度,以及如何調整 layer 之間的順序, SurfaceFlinger 僅僅只是執行它的指令。 PS: Windows Manager 是 java 層的一個服務,提供對全部窗口的管理 功能,這部分的內容我沒細看過,以爲是未來須要瞭解的內容。
窗口狀態的變化包括位置的移動,窗口大小,透明度, z-order 等等,首先咱們來了解一下 SurfaceComposerClient 是如何和SurfaceFlinger 來交互這些信息的。當應用程序須要改變窗口狀態的時候它將全部的狀態改變信息打包,而後一塊兒發送給 SurfaceFlinger, SurfaceFlinger 改變這些狀態信息之後,就會喚醒等待的監聽線程,並設置一個標誌位告訴監聽線程窗口的狀態已經改變了,必需要進行處理,在 Android 的實現中,這個打包的過程就是一個 Transaction ,全部對窗口狀態 (layer_state_t) 的改變都必須在一個Transaction 中。
到這裏應用程序客戶端的處理過程已經說完了,基本分爲兩個部分,一個就是在窗口畫圖,還一個就是窗口狀態改變的處理。
4 、 SurfaceFlinger 的處理過程
瞭解了 Flinger 和客戶端的交互,咱們再來仔細看看 SurfaceFlinger 的處理過程,前面已經說過了 SurfaceFlinger 這個服務在建立的時候會啓動一個監聽的線程,這個線程負責每次窗口更新時候的處理,下面咱們來仔細看看這個線程的事件的處理,大體就是下面的這個圖:
先大體講一下 Android 組合各個窗口的原理 : Android 其實是經過計算每個窗口的可見區域,就是咱們在屏幕上可見的窗口區域 ( 用 Android 的詞彙來講就是 visibleRegionScreen ) ,而後將各個窗口的可見區域畫到一個主 layer 的相應部分,最後就拼接成了一個完整的屏幕,而後將主 layer 輸送到 FB 顯示。在將各個窗口可見區域畫到主 layer 過程當中涉及到一個硬件實現和一個軟件實現的問題,若是是軟件實現則經過 Opengl 從新畫圖,其中還包括存在透明度的 alpha 計算;若是實現了 copybit hal 的話,能夠直接將窗口的這部分數據 直接拷貝過來,並完成可能的旋轉,翻轉,以及 alhpa 計算等。
下面來看看 Android 組合各個 layer 並送到 FB 顯示的具體過程:
4.1 、 handleConsoleEvent
當接收到 signal 或者 singalEvent 事件之後,線程就中止等待開始對 Client 的請求進行處理,第一個步驟是 handleConsoleEvent,這個步驟我看了下和 /dev/console 這個設備有關,它會取得屏幕或者釋放屏幕,只有取得屏幕的時候纔可以在屏幕上畫圖。
4.2 、 handleTransaction
前面提到過,窗口狀態的改變只能在一個 Transaction 中進行。由於窗口狀態的改變可能形成本窗口和其餘窗口的可見區域變化,因此就必須從新來計算窗口的可見區域。在這個處理子過程當中 Android 會根據標誌位來對全部 layer 進行遍歷,一旦發現哪一個窗口的狀態發生了變化就設置標誌位以在未來從新計算這個窗口的可見區域。在完成全部子 layer 的遍歷之後, Android 還會根據標誌位來處理主 layer ,舉個例子,好比說傳感器感應到手機橫過來了,會將窗口橫向顯示,此時就要從新設置主 layer 的方向。
4.3 、 handlePageFlip
這裏會處理每一個窗口 surface buffer 之間的翻轉,根據 layer_state_t 的 swapsate 來決定是否要翻轉,當 swapsate 的值是eNextFlipPending 是就會翻轉。處理完翻轉之後它會從新計算每一個 layer 的可見區域,這個從新計算的過程我還沒看太明白,但大體是一個這麼的過程:
從 Z 值最大的 layer 開始計算,也就是說從最上層的 layer 計算,去掉自己的透明區域和覆蓋在它上面的不透明區域,獲得的就是這個layer 的可見區域。而後這個 layer 的不透明區域就會累加到不透明覆蓋區域,這個 layer 的可見區域會放入到主 layer 的可見區域,而後計算下一個 layer ,直到計算完全部的 layer 的可見區域。這中間的計算是經過定義在 skia 中的一種與或非的圖形邏輯運算實現的,相似咱們數學中的與或非邏輯圖。
4.4 、 handleRepaint
計算出每一個 layer 的可見區域之後,這一步就是將全部可見區域的內容畫到主 layer 的相應部分了,也就是說將各個 surface buffer裏面相應的內容拷貝到主 layer 相應的 buffer ,其中可能還涉及到 alpha 運算,像素的翻轉,旋轉等等操做,這裏就像我前面說的能夠用硬件來實現也能夠用軟件來實現。在使用軟件的 opengl 作計算的過程當中還會用到 PixFlinger 來作像素的合成,這部份內容我還沒時間來細看。
4.5 、 postFrameBuffer
最後的任務就是翻轉主 layer 的兩個 buffer ,將剛剛寫入的內容放入 FB 內顯示了。