原創(chuàng)內(nèi)容,轉(zhuǎn)載請(qǐng)注明出處,多謝配合。
WMS(WindowManagerService)是系統(tǒng)核心服務(wù),它職責(zé)主要包含如下幾個(gè)部分:

窗口管理和Surface管理,幾乎貫穿了之前圖形系統(tǒng)系列,這里相當(dāng)于單獨(dú)拎出來分析下,同時(shí)也是對(duì)之前圖形系統(tǒng)的知識(shí)點(diǎn)進(jìn)行回顧。本篇先針對(duì)窗口管理部分進(jìn)行梳理。
一、捋清幾個(gè)關(guān)系
關(guān)系1:Activity 、Window、View
這部分牽扯到的是窗口視圖架構(gòu)。
Activity是系統(tǒng)可視化交互組件,四大組件都由AMS統(tǒng)一管理生命周期,事實(shí)上它的職責(zé)只是生命周期的管理,由設(shè)計(jì)模式的單一職責(zé)的原則,那勢(shì)必需要將Activity和其上的視圖View進(jìn)行解耦,那么就引入Window的概念,它是個(gè)抽象類,對(duì)于Activity來說,它的具體實(shí)現(xiàn)類是PhoneWindow,在Activity執(zhí)行attach的時(shí)候,會(huì)創(chuàng)建一個(gè)PhoneWindow對(duì)象。PhoneWindow作為裝載根視圖DecorView的頂級(jí)容器,Activity通過setContentView實(shí)際上是調(diào)用PhoneWindow來創(chuàng)建DecorView,并解析xml布局加載到DecorView的contentView部分。

關(guān)系2:WindowManager、WindowManagerImpl、WindowManagerGlobal
這部分牽扯到的是應(yīng)用端的窗口管理架構(gòu)。
WindowManager是一個(gè)接口類,繼承自接口ViewManager,負(fù)責(zé)窗口的管理(增、刪、改)。它的實(shí)現(xiàn)類是WindowManagerImpl,而具體操作實(shí)際上又會(huì)交給WindowManagerGlobal來處理,它是個(gè)單例,進(jìn)程唯一。WindowManagerGlobal執(zhí)行addView的方法中會(huì)傳入DecorView, 還會(huì)初始化一個(gè)ViewRootImpl。WindowManagerGlobal因?yàn)槭菃卫?,它?nèi)部會(huì)有兩個(gè)List來分別保存這兩個(gè)對(duì)象,來統(tǒng)一管理。

關(guān)系3:ViewRootImpl、WindowManagerService
這份部分牽扯到的是具體窗口操作的binder IPC。
WindowManagerGlobal負(fù)責(zé)對(duì)DecorView和對(duì)應(yīng)的ViewRootImpl進(jìn)行統(tǒng)一管理,而具體功能是由ViewRootImpl來處理。
以addView為例,具體window是由WMS統(tǒng)一管理的,所以這里會(huì)進(jìn)行binder IPC。
binder IPC:
IWindowSession: 應(yīng)用程序通過Session與WMS通信,并且每個(gè)應(yīng)用程序進(jìn)程都會(huì)對(duì)應(yīng)一個(gè)Session。
IWindow: 作為WMS主動(dòng)與應(yīng)用程序通信的client端,因?yàn)椴煌腤indow是不同的client,因此它也被作為識(shí)別window的key。

具體可以參考之前圖形系統(tǒng)系列文章:
Android圖形系統(tǒng)(一)-Window加載視圖過程
Android圖形系統(tǒng)(二)-DecorView布局加載流程
Android圖形系統(tǒng)(三)-View繪制流程
Android圖形系統(tǒng)(四)-Activity、Window、View關(guān)系總結(jié)
二、Activity與Window關(guān)聯(lián)分析
Activity與Window聯(lián)系是非常緊密,很多顯示相關(guān)操作需要兩者密切配合,那么如何保證他們的一致性呢?Android通過token來保證兩者的一致性校驗(yàn):
token流向簡(jiǎn)單歸納如下:
1)new ActivityRecord的時(shí)候會(huì)new一個(gè)token與之對(duì)應(yīng)。
2)ApplicationThread scheduleLaunchActivity的時(shí)候,ActivityClientRecord 接收這個(gè)token。
3)activity.attach傳入該token。
4)setWindowManager的時(shí)候傳入該token,最終由Window的AppToken接收。
5)在WindowManagerGlobal的addView方法中,執(zhí)行adjustLayoutParamsForSubWindow,將WindowManager.LayoutParams wp,wp.token賦值appToken,并在之后的流程中,WindowManager.LayoutParams wp作為參數(shù)傳入WMS的addWindow方法對(duì)應(yīng)attrs.token。
6)WMS中通過WindowToken與之對(duì)應(yīng)。
那么其實(shí),Activity的token,Window中的token,連傳入addWindow的attrs.token,都是同一個(gè)token,都是ActivityRecord構(gòu)造函數(shù)中創(chuàng)建的Token對(duì)象。這樣做保證了一致性,主要體現(xiàn)在如下兩點(diǎn):
- 將AMS中創(chuàng)建的ActivityRecord和Window掛鉤,當(dāng)前的window明確知道自己是哪一個(gè)Activity創(chuàng)建的。
- Window和AMS有聯(lián)系,同時(shí)又和WMS有關(guān)系,appToken則保證了這種同步機(jī)制。
三、窗口屬性與類型
WindowManagerGlobal的addView函數(shù)有個(gè)重要參數(shù):WindowManager.LayoutParams,它對(duì)應(yīng)有兩個(gè)重要的值:flag與type。
-flags:表示W(wǎng)indow的屬性:
| flags | 意義 |
|---|---|
| FLAG_NOT_FOCUSABLE | 表示W(wǎng)indow不需要獲取焦點(diǎn),也不需要接收各種輸入事件,此標(biāo)記會(huì)同時(shí)啟用FLAG_NOT_TOUCH_MODAL,最終事件會(huì)直接傳遞給下層具有焦點(diǎn)的Window。 |
| FLAG_NOT_TOUCH_MODAL | 系統(tǒng)會(huì)將當(dāng)前Window區(qū)域以外的單擊事件傳遞給底層的Window,當(dāng)前Window區(qū)域以內(nèi)的單擊事件則自己處理,這個(gè)標(biāo)記很重要,一般來說都需要開啟此標(biāo)記,否則其他Window將無法接收到單擊事件。 |
| FLAG_SHOW_WHEN_LOCKED | 開啟此模式可以讓W(xué)indow顯示在鎖屏的界面上。 |
-type: 表示窗口的類型(具體值太多了就不一一列舉了,具體可以去WindowManager的LayoutParams看詳細(xì)類型描述),窗口類型大體上就分三類:
| window類型 | 特點(diǎn) | 層級(jí)范圍 | 典型window代表 |
|---|---|---|---|
| system window | 獨(dú)立存在 | 2000~2999 | Toast 、警告提示window、鍵盤window等 |
| application window | 屬于應(yīng)用的窗口 | 1~99 | 對(duì)應(yīng)的就是activity、dialog的window |
| sub window | 需要依附于父window,不能獨(dú)立存在 | 1000~1999 | popupWindow |
四、窗口組織方式(分組與分層)
Android采用的是層疊式的布局

這個(gè)部分邏輯主要在WMS.addWindow中,這個(gè)方法非常非常重要!
分組:
子窗口與其依附的父窗口屬于同一組,共用相同的token。
分層:
WindowState在WMS中對(duì)應(yīng)一個(gè)具體的窗口。它有兩個(gè)重要屬性:
- mBaseLayer:它按窗口類型來決定z-order順序。
- mSubLayer:它按值的大小與正負(fù)關(guān)系來決定多個(gè)子窗口在父窗口中的前后關(guān)系,以及相互之間的順序。
然后,按如下流程來調(diào)整窗口的層級(jí)關(guān)系:

最終SurfaceFlinger會(huì)根據(jù)z-order順序來決定視圖的合成。