時間真的是很巧,原本沒打算寫Surface系統的(相比AudioFlinger來講,Surface變化以後的難度真的是毛毛雨了),但爲了慶祝瀧澤蘿拉發第二部大做,我決定仍是要堅持一下。
下面將延續Audio的分析風格,從幾個層面來介紹Surface系統的變化(JB號稱在Surface這塊作過大量的優質的改進,無非就是引入在PC機上早都爛熟的VSYNC,Triple Buffering。可是JB,您能確保這套機制在單核機器上跑得開麼?Win Phone 單核,都比多核Android機器流暢。恐怕仍是Android上層Display架構有問題吧??!)
同Audio同樣,想真正理解Surface系統工做原理,最好了解它的演化歷史。
《深刻理解Android 卷I》第8章已經把2.2的Surface系統從上到下都擼過一遍了。那幫成天吵嚷着由於大片裏邊有馬賽克而不爽的屌絲們,大家是否把書裏由於不懂而產生的」馬賽克「搞清楚了??
一 Surface工做流程
先說一下Surface的工做流程(只在Native層):
- Java層Surface的建立將致使JNI的Surface_init函數的調用。這個Surface還不是APP使用的Surface,中間會經歷過乾坤大挪移的過程,請參考上面所提的書籍,寫得很是詳細。
- Surface_writeToParcel,將Surface傳遞到APP所在進程去使用。
- APP所在進程經過Surface_readFromParcel,還原一個Surface對象。此時,你的APP就有臉了。
- APP調用Surface_lockCanvas得到一塊畫布,APP而後在這塊畫布上做畫。
- APP調用Surface_unlockCanvasAndPost,將數據推向SurfaceFlinger,完成這次做畫。
上面這個流程,在JB中,是沒有變化的。從2.2一直到4.1,都是這個流程。
這塊流程變化基本沒有,你們能夠直接殺進去看看。
二 SurfaceFlinger變化說明
3.1 SF成員變化說明
SF變化很大,主要是它的兄弟們變化較大。咱們分別來講,先看圖1。
圖1 DisplayHardware和兄弟們
圖1的簡單說明以下:
-
-
VSYNC原則上顯示芯片(之後簡稱顯卡)提供的。但JB走得太快了,不少硬件或者沒支持,或者接口上沒支持。因此,不能保證每臺JB手機都有來自硬件的VSYNC事件。咋整?終於,JB幹出了一個VSyncThread,它是一個線程,用來定時回調以模擬硬件VSYNC事件(這個時間必須比較準確,因此線程優先級必須比較高)。看,這又是一個鐵證,說明JB不適合在單核CPU上跑(我以爲雙核也可能不太適合)。
-
爲了支持硬件VSYNC事件,HardwareComposer也增長了相應接口。
-
DisplayHardware同時從DisplayHardwareBase和HardwareComposer的內部類EventHandler派生。從EventHandler派生無非是想基礎它的onVsyncReceived函數。這個函數將在到VSYNC事件時被調用。
-
因爲層層的封裝(就和國內工程層層轉包同樣),DisplayHardware內部又定義了一個VsyncHandler虛類,但願人家去繼承它的onVsyncReceived函數。因爲使用DH的是SF,因此,你們可大膽猜想這個onVsyncReceived會由SF這一層去處理了。若是去看代碼的話,屌絲們會發現DisplayHardware實現的onVsyncReceived函數其實沒幹什麼有毛意義的事情,就是去調用某個實現了VsyncHandler對象的onVsyncReceived函數。(有點繞口令吧?再仔細看看!)
再來看圖2:
圖2 SF和它的兄弟們
圖2解釋以下:
-
先看左上部分。對,你沒看錯。這裏也有MessageHandler,Looper,MessageBase。這之前僅是Java層的東西(因此說,原理是相通的,語言只是工具,若是你懂Java層Message相關的知識,這裏又有神馬理由說不懂呢?除非你沒真正理解Java層Message的東西,參考這篇博客吧
http://blog.csdn.net/innost/article/details/6055793)。注意其中的MessageBase,它是一個虛類,一方面它實現了父類的handleMessage函數,另外一方面須要子類實現handle函數。這一點和Java層的Message不同。因此,當你在SF中發現有地方往MessageQueue拋消息的時候,就不要去找Handler了,先直接看看這個消息的handle函數!
-
SF保存了一個MessageQueue對象,做爲顯示的服務端,它也採起了消息隊列的方式來驅動本身工做。這種方式在4.0中已經這麼作了,但還不夠徹底,不夠完全。JB中,SF的threadLoop函數就一句話:waitForEvent()。對於這種改變,我只能說:很好,很強大!
-
SF保存了一個EventThread對象,這又是一個線程類,它從VsyncHandler派生,實現了onVsyncReceived函數。
-
SF新增IDisplayEventConnection跨binder接口,數據通道是BitTube(MD,Tube的意思就是pipe。無語了。開發SF的人必定和開發AF的人坐得很遠很遠..)。這個類的做用就是收集底層的VSYNC事件,而後派發給各個Connection。大膽猜想下,是否是有些APP所須要的FPS不一樣,因此須要先由DisplayHardware提供一個最小單位的VSYNC時間,而後再由EventThread根據應用申請的VSYNC時間去觸發。相似時鐘分頻嘛!
大膽猜想,當心求證。恩,但願大家掌握這個方法。
3.2 createSurface變化說明
從流程上說,這個函數並無變化,有變化的仍是那幾個兄弟。見圖3,這裏只討論NormalSurface的狀況:
圖3 Layer和SurfaceTexture的關係
稍加解釋:
-
圖3左邊三個是Layer的派生關係。Layer是什麼?Layer是SF中表明每一個顯示層的東西,裏邊處理了繪畫等衆多邏輯。
-
右邊是ISurfaceTexture。它實際上是Android Native顯示層的接口,其做用相似AudioTrack和AudioRecord。之後偶會給一個例子,就是直接使用ISurfaceTexture API繪畫的。相比其餘版本,JB在SurfaceTexure這一塊又抽象出了BufferQueue一層。我我的以爲是越搞越複雜了。BufferQueue,再處理PageFlip的時候,可能有些好處吧。
-
客戶端調用getSurfaceTexture的時候,在Layer的createSurface中,將返回SurfaceTextureLayer給客戶端。客戶端而後調用requestBuffer,queueBuffer,dequeueBuffer獲取GraphicBuffer(簡單認爲爲顯存吧)。
-
ISurfaceTexture內部定義了兩個POD結構體,QueueBufferInput/Output,POD結構體,其實就是一個沒有什麼static成員的struct。這兩個結構體內部包含一些諸如寬度,高度,時間戳方面的信息,將作爲queueBuffer函數的參數傳遞。具體做用,沒細看。
折騰來,折騰去,無非是搞得更復雜了.....要是能看到相關設計文檔就行了....夠咱們學一陣子了。
3.3 dequeueBuffer和queueBuffer變化說明
-
dequeueBuffer:取空閒顯卡內存,以給app做畫。若是編譯的時候打開了TARGET_DISABLE_TRIPLE_BUFFERING,則顯卡內存默認是2塊,不然是3塊。相關queue/dequeue操做的代碼,早在2.2的時候就不是僅支持2塊的。也就是說,代碼裏邊實際上是能夠支持3,4,5等等。不就是一個數組來回倒騰麼,固然不會蠢到寫死爲2!這部分邏輯相比ICS,沒有太大的變化。只是把代碼挪到BufferQueue裏邊來了。
下面來看看圖4,即queueBuffer函數的流程圖。這部分變化比較大。
圖4 queueBuffer的流程
整個這麼複雜的流程,其實從第4步開始,基本上都是一個簡單的回調。這就是層次太多帶來的負面做用。
根據圖1,最後調用的是EventThread的requestNextSync,這個函數巨簡單,就是觸發一個同步廣播對象.....
還有不少知識點,但不能放在這一節裏扯了。下面,咱們來看SurfaceFlinger和EventThread的關係。
3.4 SurfaceFlinger和EventThread的工做流程說明
上一節,有個地方無法說明的就是EventThread究竟是幹嗎的,它和SF分別是兩個線程(MD,又是多線程編程,同步很重要啊!)
在SF的readyToRun函數中,將經過MesssageQueue的setEventThread函數創建SF和ET的關係。看看代碼吧:
void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
{
mEventThread = eventThread;
mEvents = eventThread->createEventConnection();
mEventTube = mEvents->getDataChannel();
mLooper->addFd(mEventTube->getFd(), 0, ALOOPER_EVENT_INPUT,
MessageQueue::cb_eventReceiver, this);
}
也就是說,當EventThread有什麼鳥事的時候,都會經過cb_eventReceiver回調到SF線程。
注意:JB之前,Android總是喜歡用pipe做爲進程間通訊的手段,如今改爲socketpair了。這是一個很大的變化。因此,會網絡編程的同窗能夠happy一下了。不會的淫,也無所謂,反正是把socket當pipe來使,都是IPC通訊手段,你管它用得是什麼呢!
EventThread的requestSync被調用後,會觸發EventThread的線程經過Connection發送一個消息給SF所在的線程,即剛纔那個cb_eventReceiver被調用,圖4是此後的工做流程。(SF系統如今變得也是磨磨唧唧了,不懂POSIX編程屌絲們,大家不管如何得花點功夫研究了。)
圖5 SF工做流程
正如圖5最後的第10,11步,終於看到了熟悉的handlePageFlip。FT,相比ICS的版本,函數是越調越多,層次愈來愈複雜。到時候別搞得和Java Framework同樣,那效率就.....
四總結
相比AF來講,SF主要是層次增長,函數調用繞來繞去。另外,新增了IDisplayEventConnection接口,這玩意兒還有待後續研究。今天講得這些東西,應該能夠幫助你們對JB SF有一個大略的瞭解。