|
隨筆- 9
文章- 0
評論- 27
圖解Android - Android GUI 系統(tǒng) (1) - 概論Android的GUI系統(tǒng)是Android最重要也最復雜的系統(tǒng)之一。它包括以下部分:
它們之間的關系如下圖所示
只有對這些系統(tǒng)的功能和工作原理有基本的了解,我們才能夠解答一些經(jīng)??M繞在腦海里的問題,比如說:
本文將從框架和流程角度出發(fā),試圖對Android的GUI系統(tǒng)做一個簡要但全面的介紹,希望借此能夠幫助大家找到上述問題的答案。 所有的內容可以濃縮在下面這張圖里,里面有很多的名稱和概念我們需要事先解釋一下: 1. Window, PhoneWindow 和 Activity
2. View, DecorView, ViewGroup, ViewRootView 是一個矩形的可見區(qū)域。 ViewGroup 是一種特殊的View, 它可以包含其他View并以一定的方式進行布局。Android支持的布局有FrameLayout, LinearLayout, RelativeLayout 等。 DecorView 是FrameLayout的子類,F(xiàn)rameLayout 也叫單幀布局,是最簡單的一種布局,所有的子View在垂直方向上按照先后順序依次疊加,如果有重疊部分,后面的View將會把前面的View擋住。我們 經(jīng)??吹降膹棾隹?,把后面的窗口擋住一部分,就是用的FrameLayout布局。Android的窗口基本上用的都是FrameLayout布局, 所以DecorView也就是一個Activity Window的頂級View, 所有在窗口里顯示的View都是它的子View. ViewRoot . 我們可以定義所有被addView()調用的View是ViewRoot, 因為接口將會生成一個ViewRootImpl 對象,并保存在WindowManagerGlobal的mRoots[] 數(shù)組里。一個程序可能有很多了ViewRoot(只要多次調用addView()), 在WindowManagerService端看來,就是多個Window。但在Activity的默認實現(xiàn)里,只有mDecorView 通過addView 添加到WindowManagerService里( 見如下代碼) //frameworks/base/core/java/android/app/Activity.java void makeVisible() { if (!mWindowAdded) { ViewManager wm = getWindowManager(); wm.addView(mDecor, getWindow().getAttributes()); mWindowAdded = true; } mDecor.setVisibility(View.VISIBLE); }
因此一般情況下,我們可以說,一個應用可以有多個Activity,每個 Activity 一個Window(PhoneWindow), 每個Window 有一個DecorView, 一個ViewRootImpl, 對應在WindowManagerService 里有一個Window(WindowState). 3. ViewRootImple, WindowManagerImpl, WindowManagerGlobalsWindowManagerImpl: 實現(xiàn)了WindowManager 和 ViewManager的接口,但大部分是調用WindowManagerGlobals的接口實現(xiàn)的。 WindowManagerGlobals: 一個SingleTon對象,對象里維護了三個數(shù)組:
同時,它還維護了兩個全局IBinder對象,用于訪問WindowManagerService 提供的兩套接口:
ViewRootImpl: ViewRootImpl 在整個Android的GUI系統(tǒng)中占據(jù)非常重要的位置,如果把Activity和View 看作 'MVC' 中的V, 把各種后臺服務看作Modal,ViewRootImpl 則是'MVC' 中的'C' - Controller. Controller在MVC架構里承擔著承上啟下的作用,一般來說它的邏輯最為復雜。從下圖可以看到,ViewRootImpl 與 用戶輸入系統(tǒng)(接收用戶按鍵,觸摸屏輸入), 窗口系統(tǒng)(復雜窗口的布局,刷新,動畫),顯示合成系統(tǒng)(包括定時器Choreograph, SurfaceFlinger), 乃至Audio系統(tǒng)(音效輸出)等均有密切的關聯(lián)。研究ViewRootImpl 是研究Android整個窗口系統(tǒng)的核心和切入點,我們將在后面詳細討論ViewRootImpl的實現(xiàn)和作用。
三 者( ViewRootImpl, WindowManagerImpl, WindowManagerGlobal) 都存在于應用(有Activity)的進程空間里,一個Activity對應一個WindowManagerImpl, 一個DecorView(ViewRoot),以及一個ViewRootImpl (上面說過,實際一個Activity只有一個DecorView),而WindowManagerGlobals是一個全局對象,一個應用永遠只有一 個。 注意的是,在某些情況下,一個應用可能會有幾個ViewRootImpl對象,比如說ANR是彈出的對話框,或是網(wǎng)頁里面一個視頻窗口 (SurfaceView), 在WindowManagerService看來,它們也是一個窗口。同時,SystemServer的進程空間也有自己的 WindowManagerGlobals 和若干個ViewRoot, 因為WindowManagerService 內部也會管理某些系統(tǒng)窗口,如手機頂部的StatusBar, 手機底部的NavigationBar, 以及 鎖屏(KeyGuard)窗口,這些窗口不屬于某個特定的Activity。 4. WindowManager, WindowManagerService 和 WindowManagerPolicyServiceWindowManager: 是一個接口類,定義了一些接口來管理Acitivity里的窗口。WindowManager 是Android應用進程空間里的一個對象,不提供IPC服務。 WindowManagerService: 是SystemServer進程里的一個Service,它的主要功能有
WindowManagerService 是Android Framework里最為龐大復雜的模塊之一,我們后面會從各個方面對它進行盡可能詳細的分析。 5. Token, WindowToken, AppWindowToken, ApplicationToken, appTokenToken在英語中表示標記,信物的意思,在代碼中,有點類似Handle,Cookie, ID, 用來標識某個特定的對象。在Android的窗口系統(tǒng)中,有很多的’Token', 它們代表著不同的含義。 WindowToken: 是在WindowManagerService 中定義的一個基類,顧名思義,它是用來標識某一個窗口。和下面的appWindowToken相比, 它不屬于某個特定的Activity, 比如說輸入法窗口,狀態(tài)欄窗口等等。 appWindowToken: 顧名思義,它是用來標識app, 跟準確的說法,是用來標識某個具體的Activity. ApplicationToken: 指的是ActivityRecord 類里的Token子類。appWindowToken里的appToken也就是它。 appToken: 和applicationToken是一個意思。 下 圖描繪了各個Token之間的關系。一個Token下面帶一個WindowList隊列,里面存放著隸屬與這個Token的所有窗口。當一個Window 加入WindowManagerService 管理時,必須指定他的Token值,WindowManagerService維護著一個Token與WindowState的鍵值Hash表。 通過 ‘dumpsys window tokens' 我們可以列出WindowManagerService當前所有的Token 和 窗口。比如, WINDOW MANAGER TOKENS (dumpsys window tokens) All tokens: WindowToken{4ea639c4 null}: //token = NULL windows=[Window{4ea7670c u0 Application Not Responding: jackpal.androidterm}, Window{4ea63a08 u0 Keyguard}] windowType=-1 hidden=false hasVisible=true AppWindowToken{4eb29760 token=Token{4eb289d4 ActivityRecord{4ea87a20 u0 com.android.launcher/com.android.launcher2.Launcher}}}: //Launcher2 windows=[Window{4ea837c8 u0 com.android.launcher/com.android.launcher2.Launcher}] windowType=2 hidden=true hasVisible=true ... WindowToken{4eb1fd48 android.os.BinderProxy@4eae8a5c}: windows=[Window{4ea92b78 u0 PopupWindow:4ea0240c}] //對話框 windowType=-1 hidden=false hasVisible=false AppWindowToken{4eb5d6c0 token=Token{4ea35074 ActivityRecord{4ea68590 u0 jackpal.androidterm/.Term}}}: windows=[Window{4eb314e4 u0 jackpal.androidterm/jackpal.androidterm.Term}] windowType=2 hidden=false hasVisible=true app=true
6. Surface, Layer 和 Canvas, SurfaceFlinger, Region, LayerStack在Android中,Window與Surface一一對應。 如果說Window關心的是層次和布局,是從設計者角度定義的類,Surface則從實現(xiàn)角度出發(fā),是工程師關系和考慮的類。Window的內容是變化 的,Surface需要有空間來記錄每個時刻Window的內容。在Android的SurfaceFlinger實現(xiàn)里,通常一個Surface有兩塊 Buffer, 一塊用于繪畫,一塊用于顯示,兩個Buffer按照固定的頻率進行交換,從而實現(xiàn)Window的動態(tài)刷新。 Layer是SurfaceFlinger 進行合成的基本操作單元。Layer在應用請求創(chuàng)建Surface的時候在SurfaceFlinger內部創(chuàng)建,因此一個Surface對應一個 Layer, 但注意,Surface不一定對應于Window,Android中有些Surface并不跟某個Window相關,而是有程序直接創(chuàng)建,比如說 StrictMode, 一塊紅色的背景,用于提示示Java代碼中的一些異常, 還有SurfaceView, 用于顯示有硬件輸出的視頻內容等。 當多個Layer進行合成的時候,并不是整個Layer的空間都會被完全顯示,根據(jù)這個Layer最終的顯示效果,一個Layer可以被劃分成很多的Region, Android SurfaceFlinger 定義了以下一些Region類型:
Android 系統(tǒng)支持多種顯示設備,比如說,輸出到手機屏幕,或者通過WiFi 投射到電視屏幕。Android用Display類來表示這樣的設備。不是所有的Layer都會輸出到所有的Display, 比如說,我們可以只將Video Layer投射到電視, 而非整個屏幕。LayerStack 就是為此設 計,LayerStack 是一個Display 對象的一個數(shù)值, 而類Layer里也有成員變量mLayerStack, 只有兩者的mLayerStack 值相同,Layer才會被輸出到給該Display設備。所以LayerStack 決定了每個Display設備上可以顯示的Layer數(shù)目。 SurfaceFlinger的工作內容,就是定期檢查所有Layer的參數(shù)更新(LayerStack等),計算新的DirtyRegion, 然后將結果推送給底層顯示驅動進行顯示。這里面有很多的細節(jié),我們將在另外的章節(jié)專門研究。 上面描述的幾個概念,均是針對于顯示這個層面,更多是涉及到中下層模塊,應用層并不參與也無需關心。對于應用而言,它關心的是如何將內容畫出來。Canvas 是Java層定義的一個類,它對應與Surface上的某個區(qū)域并提供了很多的2D繪制函數(shù)(借助于底層的Skia或OpenGL)。應用只需通過 LockCanvas() 來獲取一個Canvas對象,并調用它的繪畫方法,然后 unLockCanvasAndPost()來通知底層將更新內容進行顯示。當然,并不是所有應用程序都需要直接操作Canva, 事實上只有少量應用需要直接操作Canvas, Android提供了很多封裝好的控件 Widget,應用只需提供素材,如文字,圖片,屬性等等,這些控件會調用Canvas提供的接口幫用戶完成繪制工作。
7. SurfaceFlinger, HWComposer, OpenGL 和 DisplaySurfaceFlinger 是一個獨立的Service, 它接收所有Window的Surface作為輸入,根據(jù)ZOrder, 透明度,大小,位置等參數(shù),計算出每個Surface在最終合成圖像中的位置,然后交由HWComposer或OpenGL生成最終的顯示Buffer, 然后顯示到特定的顯示設備上。 HWComposer 是 Andrid 4.0后推出的新特性,它定義一套HAL層接口,然后各個芯片廠商根據(jù)各種硬件特點來實現(xiàn)。它的主要工作是將SurfaceFlinger計算好的Layer的顯示參數(shù)最終合成到一個顯示Buffer上。注意的是,Surface Flinger 并非是HWComposer的唯一輸入,有的Surface 不由Android的WindowManager 管理,比如說攝像頭的預覽輸入Buffer, 可以有硬件直接寫入,然后作為HWComposer的輸入之一與SurfaceFlinger的輸出做最后的合成。 OpenGL 是一個2D/3D圖形庫,需要底層硬件(GPU)和驅動的支持。在Android 4.0后,它取代Skia成為Android 的2D 繪圖圖形庫,大部分的控件均改用它來實現(xiàn),應用程序也可以直接調用OpenGl函數(shù)來實現(xiàn)復雜的圖形界面。 Display 是Android 對輸出顯示設備的一個抽象,傳統(tǒng)的Display 設備是手機上的LCD屏,在Andrid 4.1 后,Android 對SurfaceFlinger 進行了大量的改動,從而支持其他外部輸入設備,比如HDMI, Wifi Display 等等。Display的輸入是根據(jù)上面的LayerStack值進行過濾的所有Window的Surface, 輸出是和顯示設備尺寸相同的Buffer, 這個Buffer 最終送到了硬件的FB設備,或者HDMI設備,或者遠處的Wifi Display Sink設備進行顯示。輸入到輸出這條路徑上有SurfaceFlinger, OpenGL 和 HWComposer。
有了上述概念的解析,對Android的GUI 系統(tǒng)應該有了一些模糊的認識,接下來我們將按下面的順序將一步步深入其中的細節(jié)。 1. 圖解Android - Android GUI 系統(tǒng) (2) - 窗口管理系統(tǒng)在這一章里,我們將試圖解答下面幾個問題:
2. 圖解Android - Android GUI 系統(tǒng) (3) - Surface Flinger (TBD)在這一章里,我們將探討:
3. 圖解Android - Android GUI 系統(tǒng) (4) - Activity的生命周期
4. 圖解Android - Android GUI 系統(tǒng) (5) - Android的用戶輸入處理
|
|
|
來自: 老匹夫 > 《Graphics》