同以往一樣,本節通過IMS的啟動過程,探討IMS的構成。上一節提到,IMS分為Java層與Native層兩個部分,其啟動過程是從Java部分的初始化開始,進而完成Native部分的初始化。
#### 1. IMS的誕生
同其他系統服務一樣,IMS在SystemServer中的ServerThread線程中啟動。
**SystemServer.java-->ServerThread.run()**
```
public void run() {
......
InputManagerService inputManager = null;
......
// **① 新建IMS對象。**注意第二個參數wmHandler,這說明IMS的一部分功能可能會在WMS的線程中完成
inputManager= new InputManagerService(context, wmHandler);
// 將IMS發布給ServiceManager,以便其他人可以訪問IMS提供的接口
ServiceManager.addService(Context.INPUT_SERVICE,inputManager);
// 設置向WMS發起回調的callback對象
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
// **② 正式啟動IMS**
inputManager.start();
......
/* 設置IMS給DisplayManagerService。DisplayManagerService將會把屏幕的信息發送給輸入
系統作為事件加工的依據。在5.2.4節將會討論到這些信息的作用 */
display.setInputManager(inputManager);
}
```
IMS的誕生分為兩個階段:
- 創建新的IMS對象。
- 調用IMS對象的start()函數完成啟動。
##### (1) IMS的創建
IMS的構造函數如下:
**InputManagerService.java-->InputManagerService.InputManagerService()**
```
public InputManagerService(Context context,Handler handler) {
/* 使用wmHandler的Looper新建一個InputManagerHandler。InputManagerHandler將運行在
WMS的主線程中*/
this.mHandler = new InputManagerHandler(handler.getLooper());
......
// 每一個分為Java和Native兩部分的對象在創建時都會有一個nativeInput函數
mPtr =nativeInit(this, mContext, mHandler.getLooper().getQueue());
}
```
可以看出,IMS的構造函數非常簡單。看來絕大部分的初始化工作都位于Native層。參考nativeInit()函數的實現。
**com_android_server_input_InputManagerService.cpp-->nativeInit()**
```
static jint nativeInit(JNIEnv* env, jclass clazz,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
sp<MessageQueue> messageQueue =android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
/* 新建了一個NativeInputManager對象,NativeInputManager,此對象將是Native層組件與
Java層IMS進行通信的橋梁 */
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(serviceObj);
// 返回了NativeInputManager對象的指針給Java層的IMS,IMS將其保存在mPtr成員變量中
returnreinterpret_cast<jint>(im);
}
```
nativeInit()函數創建了一個類型為NativeInputManager的對象,它是Java層與Native層互相通信的橋梁。
看下這個類的聲明可以發現,它實現了InputReaderPolicyInterface與InputDispatcherPolicyInterface兩個接口。這說明上一節曾經介紹過的兩個重要的輸入系統參與者InputReaderPolicy和InputDispatcherPolicy是由NativeInputManager實現的,然而它僅僅為兩個策略提供接口實現而已,并不是策略的實際實現者。NativeInputManager通過JNI回調Java層的IMS,由它完成決策。這一小節暫不討論其實現細節,讀者只要先記住兩個策略參與者的接口實現位于NativeInputManager即可。
接下來看一下NativeInputManager的創建:
**com_android_server_input_InputManagerService.cpp-->NativeInputManager::NativeInputManager()**
```
NativeInputManager::NativeInputManager(jobjectcontextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper) {
......
// 出現重點了, NativeInputManager創建了EventHub
sp<EventHub> eventHub = new EventHub();
// 接著創建了Native層的InputManager
mInputManager = new InputManager(eventHub, this, this);
}
```
在NativeInputManager的構造函數中,創建了兩個關鍵人物,分別是EventHub與InputManager。EventHub復雜的構造函數使其在創建后便擁有了監聽設備節點的能力,這一小節中暫不討論它的構造函數,讀者僅需知道EventHub在這里初始化即可。緊接著便是InputManager的創建了,看一下其構造函數:
**InputManager.cpp-->InputManager::InputManager()**
```
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
// 創建InputDispatcher
mDispatcher = new InputDispatcher(dispatcherPolicy);
// 創建 InputReader
mReader= new InputReader(eventHub, readerPolicy, mDispatcher);
// 初始化
initialize();
}
```
再看initialize()函數:
**InputManager.cpp-->InputManager::initialize()**
```
void InputManager::initialize() {
// 創建供InputReader運行的線程InputReaderThread
mReaderThread = new InputReaderThread(mReader);
// 創建供InputDispatcher運行的線程InputDispatcherThread
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
```
InputManager的構造函數也比較簡潔,它創建了四個對象,分別為IMS的核心參與者InputReader與InputDispatcher,以及它們所在的線程InputReaderThread與InputDispatcherThread。注意InputManager的構造函數的參數readerPolicy與dispatcherPolicy,它們都是NativeInputManager。
至此,IMS的創建完成了。在這個過程中,輸入系統的重要參與者均完成創建,并得到了如圖5-2所描述的一套體系。
:-: 
圖 5-2 IMS的結構體系
##### (2) IMS的啟動與運行
完成IMS的創建之后,ServerThread執行了InputManagerService.start()函數以啟動IMS。InputManager的創建過程分別為InputReader與InputDispatcher創建了承載它們運行的線程,然而并未將這兩個線程啟動,因此IMS的各員大將仍處于待命狀態。此時start()函數的功能就是啟動這兩個線程,使得InputReader于InputDispatcher開始工作。
當兩個線程啟動后,InputReader在其線程循環中不斷地從EventHub中抽取原始輸入事件,進行加工處理后將加工所得的事件放入InputDispatcher的派發發隊列中。InputDispatcher則在其線程循環中將派發隊列中的事件取出,查找合適的窗口,將事件寫入到窗口的事件接收管道中。窗口事件接收線程的Looper從管道中將事件取出,交由事件處理函數進行事件響應。整個過程共有三個線程首尾相接,像三臺水泵似的一層層地將事件交付給事件處理函數。如圖5-3所示。
:-: 
圖 5-3 三個線程,三臺水泵
InputManagerService.start()函數的作用,就像為Reader線程、Dispatcher線程這兩臺水泵按下開關,而Looper這臺水泵在窗口創建時便已經處于運行狀態了。自此,輸入系統動力十足地開始運轉,設備節點中的輸入事件將被源源不斷地抽取給事件處理者。本章的主要內容便是討論這三臺水泵的工作原理。
#### 2. IMS的成員關系
根據對IMS的創建過程的分析,可以得到IMS的成員關系如圖5-4所示,這幅圖省略了一些非關鍵的引用與繼承關系。
**注意** IMS內部做了很多的抽象工作,EventHub、nputReader以及InputDispatcher等實際上都繼承自相應的名為XXXInterface的接口,并且僅通過接口進行相互之間的引用。鑒于這些接口各自僅有唯一的實現,為了簡化敘述我們將不提及這些接口,但是讀者在實際學習與研究時需要注意這一點。
:-: 
圖 5-4 IMS的成員關系
在圖5-4中,左側部分為Reader子系統對應于圖5-3中的第一臺水泵,右側部分為Dispatcher子系統,對應于圖5-3中的第二臺水泵。了解了IMS的成員關系后便可以開始我們的IMS深入理解之旅了!
- 前言
- 推薦序
- 第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 本章小結