圖解Android - Android GUI 系統 (1) - 概論
Android的GUI
系統是Android
最重要也最複雜的系統之一。它包括以下部分:
- 視窗和圖形系統 - Window and View Manager System.
- 顯示合成系統 - Surface Flinger
- 使用者輸入系統 - InputManager System
- 應用框架系統 - Activity Manager System.
它們之間的關係如下圖所示
只有對這些系統的功能和工作原理有基本的瞭解,我們才能夠解答一些經常縈繞在腦海裡的問題,比如說:
- Activity啟動過程是怎樣的?Activity的onXXX()在後臺都做了什麼工作?Activity的show()和hide()是如何控制的?
- Surface是什麼時候被誰建立的?
- Android是如何把一個個的控制元件畫到Surface上的?然後顯示到手機螢幕上的?
- 應用程式視窗是如何獲取焦點的?使用者的按鍵(觸控式螢幕或鍵盤)是怎樣傳遞到當前的視窗?
- Android是一個多視窗的系統嗎?
- Android是怎麼支援多屏互動的?(Wifi Display)
- 輸入法視窗到底屬於哪個程式?為什麼不管什麼應用,只要有輸入框的地方都能彈出它?
本文將從框架和流程角度出發,試圖對Android的GUI系統做一個簡要但全面的介紹,希望藉此能夠幫助大家找到上述問題的答案。
所有的內容可以濃縮在下面這張圖裡,裡面有很多的名稱和概念我們需要事先解釋一下:
1. Window, PhoneWindow 和 Activity
Activity
是 Android 應用的四大元件之一(Activity, Service, Content Provider, Broadcast Receiver
), 也是唯一一個與使用者直接互動的元件。Window
在 不同的地方有著不同的含義。在Activity
裡,Window
是一個抽象類,代表了一個矩形的不可見的容器,裡面佈局著若干個可視的區域(View).每個Activity都會有一個Window
類成員變數,mWindow
.而在WindowManagerService
裡,Window指的是WindowState
物件,從圖中可以看出,WindowState
與一個ViewRootImpl
裡的mWindow
物件相對應。所以說,WindowManagerService
裡管理的Window其實是Acitivity的ViewRoot
。我們下面提到的Window
,如果沒有做特殊說明,均指的是WindowManagerService
裡的‘Window’概念,即一個特定的顯示區域。從使用者角度來看,Android是個多視窗的作業系統,不同尺寸的視窗區域根據尺寸,位置,z-order
及是否透明等引數疊加起來一起並最終呈現給使用者。這些視窗既可以是來自一個應用,也可以來自與多個應用,這些視窗既可以顯示在一個平面,也可以是不同的平面。總而言之,視窗是有層次的顯示區域,每個視窗在底層最終體現為一個個的矩形Buffer
,這些Buffer
經過計算合成為一個新的Buffer
,最終交付Display系統進行顯示。為了輔助最後的視窗管理,Android定義了一些不同的視窗型別:- 應用程式視窗 (Application Window): 包括所有應用程式自己建立的視窗,以及在應用起來之前系統負責顯示的視窗。
- 子視窗(Sub Window):比如應用自定義的對話方塊,或者輸入法視窗,子視窗必須依附於某個應用視窗(設定相同的token)。
- 系 統視窗(System Window): 系統設計的,不依附於任何應用的視窗,比如說,狀態列(Status Bar),
導航欄(Navigation Bar), 桌布(Wallpaper), 來電顯示視窗(Phone),鎖屏視窗(KeyGuard),
資訊提示視窗(Toast), 音量調整視窗,滑鼠游標等等。
PhoneWindow
是Activity Window的擴充套件,是為手機或平板裝置專門設計的一個視窗布局方案,就像大家在手機上看到的,一個PhoneWindow
的佈局大致如下:
2. View, DecorView, ViewGroup, ViewRoot
View
是一個矩形的可見區域。
ViewGroup
是一種特殊的View, 它可以包含其他View並以一定的方式進行佈局。Android支援的佈局有FrameLayout, LinearLayout, RelativeLayout
等。
DecorView
是FrameLayout
的子類,FrameLayout
也叫單幀佈局,是最簡單的一種佈局,所有的子View
在垂直方向上按照先後順序依次疊加,如果有重疊部分,後面的View
將會把前面的View
擋住。我們經常看到的彈出框,把後面的視窗擋住一部分,就是用的FrameLayout
佈局。Android的視窗基本上用的都是FrameLayout
佈局, 所以DecorView
也就是一個Activity Window
的頂級View
, 所有在視窗裡顯示的View
都是它的子View
.
ViewRoot
. 我們可以定義所有被addView()
呼叫的View
是ViewRoot
, 因為介面將會生成一個ViewRootImpl
物件,並儲存在WindowManagerGlobal
的mRoots[]
陣列裡。一個程式可能有很多了ViewRoot
(只要多次呼叫addView()
), 在WindowManagerService
端看來,就是多個Window
。但在Activity
的預設實現裡,只有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, WindowManagerGlobals
WindowManagerImpl
: 實現了WindowManager
和 ViewManager
的介面,但大部分是呼叫WindowManagerGlobals
的介面實現的。
WindowManagerGlobals
: 一個SingleTon
物件,物件裡維護了三個陣列:
mRoots[ ]
: 存放所有的ViewRootImpl
mViews[ ]
: 存放所有的ViewRoot
mParams[ ]
: 存放所有的LayoutParams
.
同時,它還維護了兩個全域性IBinder
物件,用於訪問WindowManagerService
提供的兩套介面:
IWindowManager
: 主要介面是OpenSession()
, 用於在WindowManagerService
內部建立和初始化Session
, 並返回IBinder
物件。ISession
: 是Activity Window
與WindowManagerService
進行對話的主要介面.
ViewRootImpl
:
ViewRootImpl
在整個Android的GUI系統中佔據非常重要的位置,如果把Activity
和View
看作 ‘MVC’ 中的V, 把各種後臺服務看作Modal
,ViewRootImpl
則是’MVC’ 中的’C’ - Controller. Controller
在MVC架構裡承擔著承上啟下的作用,一般來說它的邏輯最為複雜。從下圖可以看到,ViewRootImpl
與 使用者輸入系統(接收使用者按鍵,觸控式螢幕輸入), 視窗系統(複雜視窗的佈局,重新整理,動畫),顯示合成系統(包括定時器Choreograph
, SurfaceFlinger
), 乃至Audio
系統(音效輸出)等均有密切的關聯。研究ViewRootImpl
是研究Android
整個視窗系統的核心和切入點,我們將在後面詳細討論ViewRootImpl
的實現和作用。
三 者( ViewRootImpl, WindowManagerImpl, WindowManagerGlobal
) 都存在於應用(有Activity
)的程式空間裡,一個Activity
對應一個WindowManagerImpl
, 一個DecorView(ViewRoot)
,以及一個ViewRootImpl
(上面說過,實際一個Activity
只有一個DecorView
),而WindowManagerGlobals
是一個全域性物件,一個應用永遠只有一 個。
注意的是,在某些情況下,一個應用可能會有幾個ViewRootImpl
物件,比如說ANR
是彈出的對話方塊,或是網頁裡面一個視訊視窗 (SurfaceView
), 在WindowManagerService
看來,它們也是一個視窗。同時,SystemServer
的程式空間也有自己的 WindowManagerGlobals
和若干個ViewRoot
, 因為WindowManagerService
內部也會管理某些系統視窗,如手機頂部的StatusBar
, 手機底部的NavigationBar
, 以及 鎖屏(KeyGuard
)視窗,這些視窗不屬於某個特定的Activity
。
4. WindowManager, WindowManagerService
和 WindowManagerPolicyService
WindowManager
: 是一個介面類,定義了一些介面來管理Acitivity
裡的視窗。WindowManager
是Android應用程式空間裡的一個物件,不提供IPC
服務。
WindowManagerService
: 是SystemServer
程式裡的一個Service
,它的主要功能有
- 窗 口的顯示重新整理。這裡的’
Window
’ 其實是ViewRoot
, 和上面WindowManager
管理的’Window
'是不一樣的,前者是實實在在要進行顯示的‘視窗’,而後者只是一個View
的容器,並不會顯示出來。大部分情況下,Android
同時只有一個Activity
工作,但這並不意思著只有一個Window
被顯示,Android
可能會同時顯示來自相同或不同應用的多個Window
,比如說,螢幕的上方有一個狀態列,最下方有一個導航欄,有時會彈出一些對話方塊,背景可能會顯示牆紙,在應用啟動過程中,會有動畫效果,這個時候兩個Activity
的視窗會有所變形且同時顯示出來,這一切都需要WindowManager
來控制何時,何地,以何種方式將所有的視窗整合在一起顯示。 - 預處理使用者輸入時間(
GlobalKey
?SystemKey
), 並分發給合適的視窗進行處理。 - 輸出顯示(
Display
)管理。包括WifiDisplay
.
WindowManagerService
是Android Framework
裡最為龐大複雜的模組之一,我們後面會從各個方面對它進行儘可能詳細的分析。
5. Token, WindowToken, AppWindowToken, ApplicationToken, appToken
Token
在英語中表示標記,信物的意思,在程式碼中,有點類似Handle
,Cookie
, ID
, 用來標識某個特定的物件。在Android的視窗系統中,有很多的’Token
’, 它們代表著不同的含義。
WindowToken
: 是在WindowManagerService
中定義的一個基類,顧名思義,它是用來標識某一個視窗。和下面的appWindowToken
相比, 它不屬於某個特定的Activity
, 比如說輸入法視窗,狀態列視窗等等。
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
則從實現角度出發,是工程師關係和考慮的類。Window
的內容是變化 的,Surface
需要有空間來記錄每個時刻Window
的內容。在Android的SurfaceFlinger
實現裡,通常一個Surface
有兩塊 Buffer
, 一塊用於繪畫,一塊用於顯示,兩個Buffer按照固定的頻率進行交換,從而實現Window
的動態重新整理。
Layer
是SurfaceFlinger
進行合成的基本操作單元。Layer
在應用請求建立Surface
的時候在SurfaceFlinger
內部建立,因此一個Surface
對應一個 Layer
, 但注意,Surface
不一定對應於Window
,Android
中有些Surface
並不跟某個Window
相關,而是有程式直接建立,比如說 StrictMode
, 一塊紅色的背景,用於提示示Java程式碼中的一些異常, 還有SurfaceView
, 用於顯示有硬體輸出的視訊內容等。
當多個Layer
進行合成的時候,並不是整個Layer
的空間都會被完全顯示,根據這個Layer
最終的顯示效果,一個Layer
可以被劃分成很多的Region
, Android SurfaceFlinger
定義了以下一些Region
型別:
TransparantRegion
: 完全透明的區域,在它之下的區域將被顯示出來。OpaqueRegion
: 完全不透明的區域,是否顯示取決於它上面是否有遮擋或是否透明。VisibleRegion
: 可見區域,包括完全不透明無遮擋區域或半透明區域。visibleRegion = Region -above OpaqueRegion
.CoveredRegion
: 被遮擋區域,在它之上,有不透明或半透明區域。DirtyRegion
: 可見部分改變區域,包括新的被遮擋區域,和新的露出區域。
Android 系統支援多種顯示裝置,比如說,輸出到手機螢幕,或者通過WiFi
投射到電視螢幕。Android
用Display
類來表示這樣的裝置。不是所有的Layer
都會輸出到所有的Display
, 比如說,我們可以只將Video Layer
投射到電視, 而非整個螢幕。LayerStack
就是為此設 計,LayerStack
是一個Display
物件的一個數值, 而類Layer
裡也有成員變數mLayerStack
, 只有兩者的mLayerStack
值相同,Layer
才會被輸出到給該Display
裝置。所以LayerStack
決定了每個Display
裝置上可以顯示的Layer
數目。
SurfaceFlinger
的工作內容,就是定期檢查所有Layer
的引數更新(LayerStack
等),計算新的DirtyRegion
, 然後將結果推送給底層顯示驅動進行顯示。這裡面有很多的細節,我們將在另外的章節專門研究。
上面描述的幾個概念,均是針對於顯示這個層面,更多是涉及到中下層模組,應用層並不參與也無需關心。對於應用而言,它關心的是如何將內容畫出來。Canvas
是Java層定義的一個類,它對應與Surface
上的某個區域並提供了很多的2D繪製函式(藉助於底層的Skia
或OpenGL
)。應用只需通過 LockCanvas()
來獲取一個Canvas
物件,並呼叫它的繪畫方法,然後 unLockCanvasAndPost()
來通知底層將更新內容進行顯示。當然,並不是所有應用程式都需要直接操作Canva
, 事實上只有少量應用需要直接操作Canvas
, Android提供了很多封裝好的控制元件 Widget
,應用只需提供素材,如文字,圖片,屬性等等,這些控制元件會呼叫Canvas
提供的介面幫使用者完成繪製工作。
7. SurfaceFlinger, HWComposer, OpenGL
和 Display
SurfaceFlinger
是一個獨立的Service
, 它接收所有Window
的Surface
作為輸入,根據ZOrder
, 透明度,大小,位置等引數,計算出每個Surface
在最終合成影象中的位置,然後交由HWComposer
或OpenGL
生成最終的顯示Buffer
, 然後顯示到特定的顯示裝置上。
HWComposer
是 Andrid 4.0後推出的新特性,它定義一套HAL
層介面,然後各個晶片廠商根據各種硬體特點來實現。它的主要工作是將SurfaceFlinger
計算好的Layer
的顯示引數最終合成到一個顯示Buffer
上。注意的是,Surface Flinger
並非是HWComposer
的唯一輸入,有的Surface
不由Android的WindowManager
管理,比如說攝像頭的預覽輸入Buffer
, 可以有硬體直接寫入,然後作為HWComposer
的輸入之一與SurfaceFlinger
的輸出做最後的合成。
OpenGL
是一個2D/3D圖形庫,需要底層硬體(GPU)和驅動的支援。在Android 4.0
後,它取代Skia
成為Android 的2D 繪圖圖形庫,大部分的控制元件均改用它來實現,應用程式也可以直接呼叫OpenGl
函式來實現複雜的圖形介面。
Display
是Android對輸出顯示裝置的一個抽象,傳統的Display
裝置是手機上的LCD屏,在Andrid 4.1 後,Android
對SurfaceFlinger
進行了大量的改動,從而支援其他外部輸入裝置,比如HDMI
, Wifi Display
等等。Display
的輸入是根據上面的LayerStack
值進行過濾的所有Window
的Surface
, 輸出是和顯示裝置尺寸相同的Buffer
, 這個Buffer
最終送到了硬體的FB裝置,或者HDMI
裝置,或者遠處的Wifi Display Sink
裝置進行顯示。輸入到輸出這條路徑上有SurfaceFlinger
, OpenGL
和 HWComposer
。
有了上述概念的解析,對Android的GUI
系統應該有了一些模糊的認識,接下來我們將按下面的順序將一步步深入其中的細節。
相關文章
- 圖解Android - Android GUI 系統 (2) - 視窗管理 (View, Canvas, Window Manager)圖解AndroidGUIViewCanvas
- 作業系統1—作業系統概論(上)作業系統
- 圖解 Android 系列(一)揭祕 Android 系統啟動過程圖解Android
- Android系統架構圖Android架構
- Android 系統原始碼-1:Android 系統啟動流程原始碼分析Android原始碼
- Android系統架構詳解(2)--Android RuntimeAndroid架構
- Android View 系統 1 - View樹AndroidView
- 【Android系統】Android系統架構簡介Android架構
- Android 儲存概覽Android
- [RK3399][Android7.1]GPIO子系統框架圖解Android框架圖解
- Android系統耳機圖示顯示Android
- Android Q (Android 10.0)系統新特性Android
- 第1章 概論
- Android SMSSDK無GUI介面整合方法AndroidGUI
- Android 向量圖詳解Android
- 作業系統2—作業系統概論(下)作業系統
- Android埋點技術概覽Android
- Android系統開篇Android
- Android 12(S) 圖形顯示系統 - 開篇Android
- Android輪播圖從0到1Android
- Android初級之路-Android系統架構簡介Android架構
- 統計學習一:1.概論:基本概念
- Android實現拼圖解鎖Android圖解
- Android Bitmap(點陣圖)詳解Android
- 01 知識圖譜概論
- 資料庫系統概論 第一章 緒論資料庫
- Android系統常用分割槽Android
- Android-系統架構Android架構
- Android 系統啟動流程Android
- 【android 7.1.2】系統啟動Android
- Android系統安全機制Android
- 適配Android4.4~Android11,呼叫系統相機,系統相簿,系統圖片裁剪,轉換檔案(對圖片進行上傳等操作)Android
- Android FrameWork學習(二)Android系統原始碼除錯AndroidFramework原始碼除錯
- [RK3399][Android7.1]Linux核心I2C子系統框架圖解AndroidLinux框架圖解
- Android 12(S) 圖形顯示系統 - 示例應用(二)Android
- Android 12(S) 圖形顯示系統 - 基本概念(一)Android
- Android 12(S) 圖形顯示系統 - createSurface的流程(五)Android
- 2-1 電機篇-概論