Android 4.1 Surface系統變化說明


時間真的是很巧,本來沒打算寫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的簡單說明如下:
  • JB為了支持VSYNC(不懂的同學們,參考這篇文章 http://blog.sina.com.cn/s/blog_4a3946360100wjoo.html),修改了DisplayHardware和HardwareComposer(這個鬼類,其實是3.0出現的,)。簡單來說,VSYNC就是一個同步事件。同步嘛,都是到這個點了,大家把狀態對一下。就好像美國大片那些特工們,干某些事情前總要晃晃手表,對下時間一樣。至於拿到這個同步事件后到底去干什么,以后看代碼就知道了。
  • 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有一個大略的了解。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM