Android2.3中的消息擷取過程如下所示:
這裡涉及到以下名詞:
(1) 客戶視窗ViewRoot:應用程式添加視窗時,會在本地建立一個ViewRoot對象,也就是說ViewRoot對象的數量與視窗數量一緻;
(2) Pipe:Linux的Pipe機制,也就是管道,Android2.3使用Pipe傳遞ViewRoot和InputDispatcher之間的消息;
(3) JNI:Java Native Interface,Java本地接口,實作Java和其他語言的互動,在Android裡主要是和C語言的互動;
(4) WindowManagerService:簡稱WmS,視窗管理服務;
(5) InputReader:對應一個線程,該線程會持續調用輸入裝置的驅動,讀取所有使用者輸入的消息,該線程在系統程序system process空間中運作;
(6) InputDispatcher:對應一個線程,InputReader讀取到使用者輸入消息後,将消息傳入InputDispatcher的消息隊列中;
(7) NativeInputManager:InputManager.java對應的c對象com_android_server_InputManager.cpp中定義的一個類,主要用來存儲視窗資訊;
(8) InputManager:上文提到的InputManager.jara對象,Java代碼通過InputManager的方法通路NativeInputManager擷取視窗資訊;
(9) InputMonitor:WmS中用于儲存視窗資訊的對象。
從添加視窗開始分析。
應用程式添加視窗時,會在本地建立一個ViewRoot對象,然後通過IPC調用WmS中的Session對象的addWindow方法,進而請求WmS建立一個視窗。
WmS建立視窗時,把視窗資訊儲存在InputMonitor内,然後通過InputManager把視窗資訊送出給InputDispatcher,同時也存儲在NativeInputManager中。
過程如下圖所示:
視窗建立完成後,則等待使用者消息。
上面提到過,InputReader線程會持續調用輸入裝置的驅動來讀取使用者消息,然後把使用者消息傳遞給InputDispatcher線程,InputDispatcher中儲存了視窗資訊,是以可以根據使用者消息找到對應的視窗資訊,找到後連同視窗資訊一起傳給NativeInputManager。
NativeInputManager擷取到消息及視窗資訊後,與内部儲存的視窗資訊比對,判斷是否按鍵消息, 若是按鍵消息,則傳遞給WmS,否則傳回客戶視窗。
WmS擷取到按鍵消息後,通過InputMonitor内部儲存的視窗資訊比對及内部的一些函數,判斷是否是系統按鍵,若不是,則傳回給InputDispatcher,InputDispatcher通過Pipe傳回ViewRoot;若是系統按鈕,則直接調用内部函數處理,不再傳回使用者視窗。
過程如下所示:
由上文可知,InputDispatcher和使用者視窗之間存在兩個管道(Pipe),用來實作InputDispatcher和ViewRoot之間的雙向互動。
補充一點Pipe的知識:Pipe是Linux的一種系統調用,Linux會在核心位址空間中開辟一段共享記憶體,并産生一個Pipe對象,每個Pipe對象内部都會自動建立兩個檔案描述符,一個用于讀,一個用于寫。檔案描述符是全局唯一的,進而使得兩個程序之間可以借助這兩個描述符,一個往管道中寫資料,另一個從管道中讀取資料,故而,管道是單向的,這也是為什麼說InputDispatcher和使用者視窗之間的雙向通信需要借助兩個管道。