俗話說,一個好漢三個幫!WMS的強大是由很多重要的成員互相協調工作而實現的。了解WMS的構成將會為我們深入探索WMS打下良好的基礎,進而分析它的啟動過程,這是再合適不過了。
#### 1.WMS的誕生
和其他的系統服務一樣,WMS的啟動位于SystemServer.java中ServerThread類的run()函數內。
**SystemServer.java::ServerThread.run()**
```
Public void run() {
......
WindowManagerService wm = null;
......
try {
......
// **①創建WMS實例**
/* 通過WindowManagerService的靜態函數main()創建WindowManagerService的實例。
注意main()函數的兩個參數wmHandler和uiHandler。這兩個Handler分別運行于由
ServerThread所創建的兩個名為“WindowManager”和“UI”的兩個HandlerThread中 */
wm =WindowManagerService.main(context, power, display, inputManager,
uiHandler,wmHandler,
factoryTest !=SystemServer.FACTORY_TEST_LOW_LEVEL,
!firstBoot, onlyCore);
// 添加到ServiceManager中去
ServiceManager.addService(Context.WINDOW_SERVICE,wm);
......
catch(RuntimeException e) {
......
}
......
try {
//**②初始化顯示信息**
wm.displayReady();
} catch(Throwable e) {......}
......
try {
// ③通知WMS,系統的初始化工作完成
wm.systemReady();
} catch(Throwable e) {......}
......
}
```
由此可以看出,WMS的創建分為三個階段:
- 創建WMS的實例。
- 初始化顯示信息。
- 處理systemReady通知。
接下來,將通過以上三個階段分析WMS從無到有的過程。
看一下WMS的main()函數的實現:
**WindowManagerService.java::WindowManagerSrevice.main()**
```
public static WindowManagerService main(finalContext context,
finalPowerManagerService pm, final DisplayManagerService dm,
finalInputManagerService im,
finalHandler uiHandler, final Handler wmHandler,
finalboolean haveInputMethods, final boolean showBootMsgs,
finalboolean onlyCore) {
finalWindowManagerService[] holder = new WindowManagerService[1];
// 通過由SystemServer為WMS創建的Handler新建一個WindowManagerService對象
// 此Handler運行在一個名為WindowManager的HandlerThread中
wmHandler.runWithScissors(newRunnable() {
@Override
publicvoid run() {
holder[0]= new WindowManagerService(context, pm, dm, im,
uiHandler,haveInputMethods, showBootMsgs, onlyCore);
}
}, 0);
returnholder[0];
}
```
* * * * *
**注意** Handler類在Android 4.2中新增了一個API:runWithScissors()。這個函數將會在Handler所在的線程中執行傳入的Runnable對象,同時阻塞調用線程的執行,直到Runnable對象的run()函數執行完畢。
* * * * *
WindowManagerService.main()函數在ServerThread專為WMS創建的線程“WindowManager”上創建了一個WindowManagerService的新實例。WMS中所有需要的Looper對象,例如Handler、Choreographer等,將會運行在“WindowManager”線程中。
接下來看一下其構造函數,看一下WMS定義了哪些重要的組件。
**WindowManagerService.java::WindowManagerService.WindowManagerService()**
```
private WindowManagerService(Context context,PowerManagerService pm,
DisplayManagerService displayManager, InputManagerService inputManager,
Handler uiHandler,
booleanhaveInputMethods, boolean showBootMsgs, boolean onlyCore)
......
mDisplayManager=
(DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mDisplayManager.registerDisplayListener(this,null);
Display[]displays = mDisplayManager.getDisplays();
/* 初始化DisplayContent列表。DisplayContent是Android4.2為支持多屏幕輸出所引入的一個
概念。一個DisplayContent指代一塊屏幕,屏幕可以是手機自身的屏幕,也可以是基于Wi-FiDisplay
技術的虛擬屏幕[3]*/
for(Display display : displays) {
createDisplayContentLocked(display);
}
.....
/* 保存InputManagerService。輸入事件最終要分發給具有焦點的窗口,而WMS是窗口管理者,
所以WMS是輸入系統中的重要一環。關于輸入系統的內容將在第5章中深入探討*/
mInputManager= inputManager;
// 這個看起來其貌不揚的mAnimator,事實上具有非常重要的作用。它管理著所有窗口的動畫
mAnimator= new WindowAnimator(this, context, mPolicy);
// 在“UI“線程中將對另一個重要成員mPolicy,也就是WindowManagerPolicy進行初始化
initPolicy(uiHandler);
// 將自己加入到Watchdog中
Watchdog.getInstance().addMonitor(this);
......
}
```
第二步,displayReady()函數的調用主要是初始化顯示尺寸的信息。其內容比較瑣碎,這里就先不介紹了。不過值得注意的一點是,再displayReady()完成后,WMS會要求ActivityManagerService進行第一次Configuration的更新。
第三步,在systemReady()函數中,WMS本身將不會再做任何操作了,直接調用mPolicy的systemReady()函數。
#### 2.WMS的重要成員
總結一下在WMS的啟動過程中所創建的重要成員,參考圖4-3。
:-: 
圖 4-3 WMS的重要成員
以下是對圖4-3中重要成員的簡單介紹:
- mInputManager,InputManagerService(輸入系統服務)的實例。用于管理每個窗口的輸入事件通道(InputChannel)以及向通道上派發事件。關于輸入系統的詳細內容將在本書第5章詳細探討。
- mChoreographer,Choreographer的實例,在SampleWindow的例子中已經見過了。Choreographer的意思是編舞指導。它擁有從顯示子系統獲取VSYNC同步事件的能力,從而可以在合適的時機通知渲染動作,避免在渲染的過程中因為發生屏幕重繪而導致的畫面撕裂。從這個意義上來講,Choreographer的確是指導Android翩翩起舞的大師。WMS使用Choreographer負責驅動所有的窗口動畫、屏幕旋轉動畫、墻紙動畫的渲染。
- mAnimator,WindowAnimator的實例。它是所有窗口動畫的總管(窗口動畫是一個WindowStateAnimator的對象)。在Choreographer的驅動下,逐個渲染所有的動畫。
- mPolicy,WindowPolicyManager的一個實現。目前它只有PhoneWindowManager一個實現類。mPolicy定義了很多窗口相關的策略,可以說是WMS的首席顧問!每當WMS要做什么事情的時候,都需要向這個顧問請教應當如何做。例如,告訴WMS某一個類型的Window的ZOrder的值是多少,幫助WMS矯正不合理的窗口屬性,會為WMS監聽屏幕旋轉的狀態,還會預處理一些系統按鍵事件(例如HOME、BACK鍵等的默認行為就是在這里實現的),等等。所以,mPolicy可謂是WMS中最重要的一個成員了。
- mDisplayContents,一個DisplayContent類型的列表。Android4.2支持基于Wi-fi Display的多屏幕輸出,而一個DisplayContent描述了一塊可以繪制窗口的屏幕。每個DisplayContent都用一個整型變量作為其ID,其中手機默認屏幕的ID由Display.DEFAULT\_DISPLAY常量指定。DisplayContent的管理是由DisplayManagerService完成的,在本章不會去探討DisplayContent的實現細節,而是關注DisplayContent對窗口管理與布局的影響。
下面的幾個成員的初始化并沒有出現在構造函數中,不過它們的重要性一點也不亞于上面幾個。
- mTokenMap,一個HashMap,保存了所有的顯示令牌(類型為WindowToken),用于窗口管理。在SampleWindow例子中曾經提到過,一個窗口必須隸屬于某一個顯示令牌。在那個例子中所添加的令牌就被放進了這個HashMap中。從這個成員中還衍生出幾個輔助的顯示令牌的子集,例如mAppTokens保存了所有屬于Activity的顯示令牌(WindowToken的子類AppWindowToken),mExitingTokens則保存了正在退出過程中的顯示令牌等。其中mAppTokens列表是有序的,它與AMS中的mHistory列表的順序保持一致,反映了系統中Activity的順序。
- mWindowMap,也是一個HashMap,保存了所有窗口的狀態信息(類型為WindowState),用于窗口管理。在SampleWindow例子中,使用IWindowSession.add()所添加的窗口的狀態將會被保存在mWindowMap中。與mTokenMap一樣,mWindowMap一樣有衍生出的子集。例如mPendingRemove保存了那些退出動畫播放完成并即將被移除的窗口,mLosingFocus則保存了那些失去了輸入焦點的窗口。在DisplayContent中,也有一個windows列表,這個列表存儲了顯示在此DisplayContent中的窗口,并且它是有序的。窗口在這個列表中的位置決定了其最終顯示時的Z序。
- mSessions,一個List,元素類型為Session。Session其實是SampleWindow例子中的IWindowSession的Bn端。也就是說,mSessions這個列表保存了當前所有想向WMS尋求窗口管理服務的客戶端。注意Session是進程唯一的。
- mRotation,只是一個int型變量。它保存了當前手機的旋轉狀態。
WMS定義的成員一定不止這些,但是它們是WMS每一種功能最核心的變量。讀者在這里可以線對它們有一個感性的認識。在本章后續的內容里將會詳細分析它們在WMS的各種工作中所發揮的核心作用。
- 前言
- 推薦序
- 第1章 開發環境部署
- 1.1獲取Android源代碼
- 1.2Android的編譯
- 1.3在IDE中導入Android源代碼
- 1.3.1將Android源代碼導入Eclipse
- 1.3.2將Android源代碼導入SourceInsight
- 1.4調試Android源代碼
- 1.4.1使用Eclipse調試Android Java源代碼
- 1.4.2使用gdb調試Android C/C 源代碼
- 1.5本章小結
- 第2章 深入理解Java Binder和MessageQueue
- 2.1概述
- 2.2Java層中的Binder分析
- 2.2.1Binder架構總覽
- 2.2.2初始化Java層Binder框架
- 2.2.3窺一斑,可見全豹乎
- 2.2.4理解AIDL
- 2.2.5Java層Binder架構總結
- 2.3心系兩界的MessageQueue
- 2.3.1MessageQueue的創建
- 2.3.2提取消息
- 2.3.3nativePollOnce函數分析
- 2.3.4MessageQueue總結
- 2.4本章小結
- 第3章 深入理解AudioService
- 3.1概述
- 3.2音量管理
- 3.2.1音量鍵的處理流程
- 3.2.2通用的音量設置函數setStreamVolume()
- 3.2.3靜音控制
- 3.2.4音量控制小結
- 3.3音頻外設的管理
- 3.3.1 WiredAccessoryObserver 設備狀態的監控
- 3.3.2AudioService的外設狀態管理
- 3.3.3音頻外設管理小結
- 3.4AudioFocus機制的實現
- 3.4.1AudioFocus簡單的例子
- 3.4.2AudioFocus實現原理簡介
- 3.4.3申請AudioFocus
- 3.4.4釋放AudioFocus
- 3.4.5AudioFocus小結
- 3.5AudioService的其他功能
- 3.6本章小結
- 第4章 深入理解WindowManager-Service
- 4.1初識WindowManagerService
- 4.1.1一個從命令行啟動的動畫窗口
- 4.1.2WMS的構成
- 4.1.3初識WMS的小結
- 4.2WMS的窗口管理結構
- 4.2.1理解WindowToken
- 4.2.2理解WindowState
- 4.2.3理解DisplayContent
- 4.3理解窗口的顯示次序
- 4.3.1主序、子序和窗口類型
- 4.3.2通過主序與子序確定窗口的次序
- 4.3.3更新顯示次序到Surface
- 4.3.4關于顯示次序的小結
- 4.4窗口的布局
- 4.4.1從relayoutWindow()開始
- 4.4.2布局操作的外圍代碼分析
- 4.4.3初探performLayoutAndPlaceSurfacesLockedInner()
- 4.4.4布局的前期處理
- 4.4.5布局DisplayContent
- 4.4.6布局的階段
- 4.5WMS的動畫系統
- 4.5.1Android動畫原理簡介
- 4.5.2WMS的動畫系統框架
- 4.5.3WindowAnimator分析
- 4.5.4深入理解窗口動畫
- 4.5.5交替運行的布局系統與動畫系統
- 4.5.6動畫系統總結
- 4.6本章小結
- 第5章 深入理解Android輸入系統
- 5.1初識Android輸入系統
- 5.1.1getevent與sendevent工具
- 5.1.2Android輸入系統簡介
- 5.1.3IMS的構成
- 5.2原始事件的讀取與加工
- 5.2.1基礎知識:INotify與Epoll
- 5.2.2 InputReader的總體流程
- 5.2.3 深入理解EventHub
- 5.2.4 深入理解InputReader
- 5.2.5原始事件的讀取與加工總結
- 5.3輸入事件的派發
- 5.3.1通用事件派發流程
- 5.3.2按鍵事件的派發
- 5.3.3DispatcherPolicy與InputFilter
- 5.3.4輸入事件的派發總結
- 5.4輸入事件的發送、接收與反饋
- 5.4.1深入理解InputChannel
- 5.4.2連接InputDispatcher和窗口
- 5.4.3事件的發送
- 5.4.4事件的接收
- 5.4.5事件的反饋與發送循環
- 5.4.6輸入事件的發送、接收與反饋總結
- 5.5關于輸入系統的其他重要話題
- 5.5.1輸入事件ANR的產生
- 5.5.2 焦點窗口的確定
- 5.5.3以軟件方式模擬用戶操作
- 5.6本章小結
- 第6章 深入理解控件系統
- 6.1 初識Android的控件系統
- 6.1.1 另一種創建窗口的方法
- 6.1.2 控件系統的組成
- 6.2 深入理解WindowManager
- 6.2.1 WindowManager的創建與體系結構
- 6.2.2 通過WindowManagerGlobal添加窗口
- 6.2.3 更新窗口的布局
- 6.2.4 刪除窗口
- 6.2.5 WindowManager的總結
- 6.3 深入理解ViewRootImpl
- 6.3.1 ViewRootImpl的創建及其重要的成員
- 6.3.2 控件系統的心跳:performTraversals()
- 6.3.3 ViewRootImpl總結
- 6.4 深入理解控件樹的繪制
- 6.4.1 理解Canvas
- 6.4.2 View.invalidate()與臟區域
- 6.4.3 開始繪制
- 6.4.4 軟件繪制的原理
- 6.4.5 硬件加速繪制的原理
- 6.4.6 使用繪圖緩存
- 6.4.7 控件動畫
- 6.4.8 繪制控件樹的總結
- 6.5 深入理解輸入事件的派發
- 6.5.1 觸摸模式
- 6.5.2 控件焦點
- 6.5.3 輸入事件派發的綜述
- 6.5.4 按鍵事件的派發
- 6.5.5 觸摸事件的派發
- 6.5.6 輸入事件派發的總結
- 6.6 Activity與控件系統
- 6.6.1 理解PhoneWindow
- 6.6.2 Activity窗口的創建與顯示
- 6.7 本章小結
- 第7章 深入理解SystemUI
- 7.1 初識SystemUI
- 7.1.1 SystemUIService的啟動
- 7.1.2 狀態欄與導航欄的創建
- 7.1.3 理解IStatusBarService
- 7.1.4 SystemUI的體系結構
- 7.2 深入理解狀態欄
- 7.2.1 狀態欄窗口的創建與控件樹結構
- 7.2.2 通知信息的管理與顯示
- 7.2.3 系統狀態圖標區的管理與顯示
- 7.2.4 狀態欄總結
- 7.3 深入理解導航欄
- 7.3.1 導航欄的創建
- 7.3.2 虛擬按鍵的工作原理
- 7.3.3 SearchPanel
- 7.3.4 關于導航欄的其他話題
- 7.3.5 導航欄總結
- 7.4 禁用狀態欄與導航欄的功能
- 7.4.1 如何禁用狀態欄與導航欄的功能
- 7.4.2 StatusBarManagerService對禁用標記的維護
- 7.4.3 狀態欄與導航欄對禁用標記的響應
- 7.5 理解SystemUIVisibility
- 7.5.1 SystemUIVisibility在系統中的漫游過程
- 7.5.2 SystemUIVisibility發揮作用
- 7.5.3 SystemUIVisibility總結
- 7.6 本章小結
- 第8章 深入理解Android壁紙
- 8.1 初識Android壁紙
- 8.2深入理解動態壁紙
- 8.2.1啟動動態壁紙的方法
- 8.2.2壁紙服務的啟動原理
- 8.2.3 理解UpdateSurface()方法
- 8.2.4 壁紙的銷毀
- 8.2.5 理解Engine的回調
- 8.3 深入理解靜態壁紙-ImageWallpaper
- 8.3.1 獲取用作靜態壁紙的位圖
- 8.3.2 靜態壁紙位圖的設置
- 8.3.3 連接靜態壁紙的設置與獲取-WallpaperObserver
- 8.4 WMS對壁紙窗口的特殊處理
- 8.4.1 壁紙窗口Z序的確定
- 8.4.2 壁紙窗口的可見性
- 8.4.3 壁紙窗口的動畫
- 8.4.4 壁紙窗口總結
- 8.5 本章小結