Android-2.2display系統介紹-SW架構
一、Overview
上圖的原型取自高通的文檔,由於原圖無法描述現有的架構,我在原圖的基礎了做了些修改,主要是增加了overlay部分,另外其他部分根據現有的軟件也做了些許改動。下面先對上圖做個大概的介紹,後面會針對重點部分做詳細的分析。
最上面一層爲應用程序,根據數據類型以及應用的不同可以分爲幾種。
第一種是最普通的應用,如UI界面的顯示,這部分通常數據類型爲RGB格式,數據無須再經過特殊的處理。該應用可以說遍佈各個應用程序,幾乎是實時存在的。
第二種是針對大塊YUV數據的應用,如camera的preview、視頻的播放等。該應用只針對特定的應用程序,開啓時通過overlay直接把大塊的YUV數據送到kernel顯示。
第三種其實和第一種類似,只不過由於應用的需求在顯示之前需要對數據進行2D、3D的處理(使用OpenGL、OpenVG、SVG、SKIA),處理之後的流程和普通的顯示就沒什麼差別了。一般在Game、地圖、Flash等應用中會用到。
應用之下是framework,其中最核心的就是surfaceflinger了,它爲所有的應用程序的顯示提供服務。由於overlay的接口掛在surfaceflinger裏面(雖然2者在功能上不相干),所有使用overlay的AP需要通過surfaceflinger纔可以訪問overlay;另外,由於surfaceflinger需要使用OpenGL來compose surface,這也就是爲什麼surfacelfinger會調用EGL wrapper了,EGL wrapper是對Graphics HAL的封裝,除了surfaceflinger會調用它來compose surface外,上層的2D、3D應用也會調用它來進行圖形處理。
再下一層就是HAL了。
首先一個是overlay模塊,對上提供control channel和data channel;對下則通過系統調用到kernel中的MDP driver。
再一個是Gralloc模塊,注意它是和overlay並列的,它包含2個部分,一部分是爲上層提供pmem的接口,另一部分則是對framebuffer進行刷新,這裏的framebuffer其實就是UI的數據。由此可見上層有2個通道把顯示數據送到kernel中,framebuffer是傳統的方式,overlay是android(éclair以後)後增加的。
紅色及右邊部分是OpenGL的HAL,其中紅色部分代表HW solution,高通提供的,這部分是沒有源碼的;右邊的software graphics library是SW solution,android自身的。HW和SW solution可以同時存在也可以只有一個,後面會講解。
再往下就是kernel中的driver了,最主要的就是fb設備驅動以及MDP4 overlay的驅動,從硬件上看2者是並列的,framebuffer最終也是通過overlay方式送入MDP的。PMEM和KGSL分別對應kernel中pmem的driver(/dev/pmem)和Adreno220的driver。
二、Surfaceflinger詳解
1.overview
Surfaceflinger可以說是Android顯示系統中的核心,在android當中它是一個service,提供系統範圍內的surface composer 功能,它能夠將各種應用程序的2D 、3D surface 進行組合,合併最終得到的一個main surface數據會送入顯存。簡單的說,surfaceflinger就像是畫布,它不關心畫上去的內容,只是一味的執行合成功能,當然要根據畫的位置、大小以及效果等參數。這很像Photoshop中的各個Layer,你可以在不同的layer畫任意的內容,每個layer可以設置位置、大小、效果參數等,最終通過merge合成一個layer。
從應用的角度看,每個應用程序可能對應一個或多個圖形界面,每個界面可以看作是一個surface。首先每個surface有它的位置、大小、內容等元素,這些元素是可以隨便變化的;另外不同的surface的位置會有重疊,會涉及到透明度等效果處理問題,這些都是通過surfaceflinger來完成的。當然了,surfaceflinger擔任是一個管理的職責,對於效果處理及合成它是通過OpenGL來做的,但前提是surfaceflinger需要把相關參數計算好,如重疊的位置等。
2.Surfaceflinger在系統中的位置
Android中的圖形系統採用Client/Server架構。服務端負責Surface的合成等處理工作,客戶端提供接口給上層操作自己的Surface,並向服務端發送消息完成實際處理工作。服務端 (即SurfaceFlinger)主要由c++代碼編寫而成。客戶端端代碼分爲兩部分,一部分是由Java提供的供應用使用的api,另一部分則是由c++寫成的底層實現。如下圖所示:
除去最上層的應用不算,surface最上層的接口就是java surface了,文件路徑如下:
frameworks/base/core/java/android/view/Surface.java,該文件中的接口會被應用間接調用。
我們從JNI開始看,surface的JNI文件路徑如下:
frameworks/base/core/jni/android_view_Surface.cpp,裏面的接口大概分爲2類,一類是負責管理ibinder通信的;另一類纔是和顯示控制相關的,第二類接口會直接調用C實現函數。
C實現的文件路徑如下:
frameworks/base/libs/ui/Surface.cpp
我們來看看JNI中一些重要的接口:
SurfaceSession_init:本接口只會被調用一次,負責創建surfacecomposerclient,主要爲進程間通信做準備。對應的銷燬函數有SurfaceSession_destroy和SurfaceSession_kill。
Surface_init:負責創建surface,最終會調用到surfaceflinger中的createSurface,對應的銷燬函數有Surface_destroy和Surface_release。
Surface_lockCanvas:當對一個surface進行繪圖之前要調用的,將該surface鎖定,並且得到surface的back buffer,應用可以繪圖。
Surface_unlockCanvasAndPost:當上層繪圖完畢後,通過該函數通知底層back buffer已繪製完畢,可以更新
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
Surface_setLayer\
Surface_setPosition\
Surface_setSize\
Surface_hide\
Surface_show\
Surface_setOrientation\
Surface_freeze\
Surface_unfreeze
Surface_setFlags\
Surface_setAlpha\
Surface_setMatrix:設置surface的一些屬性,如大小、位置、方位、截取範圍,Z-order等。其最終改變的都是surface的結構體屬性,如下:
uint32_t what;//哪一項屬性改變
int32_t x;//顯示位置
int32_t y; //顯示位置
uint32_t z; //layer順序
uint32_t w;//寬度
uint32_t h;//高度
float alpha;//透明度
uint32_t tint;//色彩,未使用
uint8_t flags;// 標誌
uint8_t mask;//屏蔽命令
uint8_t reserved;
matrix22_t matrix;//截取範圍
Region transparentRegion;//透明度設置
|
3.JNI與Surfaceflinger的連接通訊
由於JNI及C函數實現與surfaceflinger不在同一個進程(一個在應用端-客戶端,另一個在服務端),android中通過IPC(Binder)方式實現進程間通信,下圖來源於網上,不過我修改了裏面的一些錯誤,它演示了JNI和surfaceflinger建立連接以及創建surface的流程。
JNI和C函數實現我們看作是一個部分
這裏看到一個比較重要的部分——SurfaceComposerClient,它是surfacelinger的客戶端,通過它上層纔可以和surfaceflinger使用Binder聯繫到一起,IsurfaceComposer和IsurfaceFlingerClient都是用來實現Binder通信的。具體流程講解 如下:
應用程序通過JNI接口SurfaceSession_init創建SurfaceComposerClient。通過SurfaceComposerClient函數中調用getComposerService獲得IsurfaceComposer的IBinder對象,然後通過這個對象的createConnection又獲得IsurfaceFlingerClient的IBinder,通過這個IBinder,JNI就可以調用Surfaceflinger中的接口了,如createSurface。由於採用Binder方式,代碼部分稍微複雜一些,需要多看幾遍才能把流程理清楚。
4.Surfaceflinger與libui、OpenGL、顯示設備的連接
這裏不得不提到android對媒體框架中一個很重要的部分,那就是libui,它是一個框架庫提供對底層操作的接口,比如會調用Gralloc、Overlay等HAL層接口。其他的庫類繼承的方式來調用libui,surfaceflinger就是這樣和顯示設備連接的(包括寫顯存和對pmem的使用)
Surfaceflinger使用OpenGL來合成surface,所以surfaceflinger會直接調用到OpenGL的接口。
它們的架構如下:
這部分的流程比較複雜,主要是各個類的繼承繞的比較多,我也是看了很多遍代碼以及參考了些資料才理出來,下面來詳細解釋下這個圖:
Surfaceflinger在設計時考慮到支持多個屏幕,但目前的版本只支持一個,在surfaceflinger當中一個顯示設備對應一個圖中的DisplayHardware,surfaceflinger在初始化時會新建Displayhardware(請參考surfaceflinger.cpp中的readyToRun函數),它完成的主要任務一個是建立FramebufferNativeWindow,確定數據輸出設備接口(請參考FramebufferNativeWindow.cpp),再一個就是初始化OpenGL,並創建main surface,後續surfaceflinger中所有的layer最終都將被畫到這個main surface上(請參考displayhardware.cpp的init函數)。這樣main surface、OpenGL和libui中的FramebufferNativeWindow接口就綁定在一起。
由於libEGL負責所有layer的最終合成,所以最後數據送往HAL一定要libEGL來觸發,對應的函數流程是:
postFrameBuffer(surfaceflinger)->Flip(displayhardware)-> eglSwapBuffers(OpenGL)-> queueBuffer(libui)->fbpost(gralloc)
另外圖中的GraphicBuffer是libui中提供的對pmem的操作接口,它會直接調用gralloc模塊。關於OpenGL和Grall