輸入事件的源頭位于/dev/input/下的設(shè)備節(jié)點,輸入事件的終點是WMS管理的某個窗口。所以輸入系統(tǒng)的主要工作是讀取設(shè)備節(jié)點中的原始事件,接著進行加工封裝,然后派發(fā)給一個特定的窗口或者窗口中的控件。整個流程由InputManagerService系統(tǒng)服務(wù)為核心的多個參與者共同完成,如下圖所示。

輸入系統(tǒng)簡介.png
流程大致為:
- 內(nèi)核將原始事件寫入設(shè)備節(jié)點
- InputReader不斷地通過EventHub將原始事件取出來并翻譯加工成Android輸入事件,然后交給InputDispather
- InputDispather根據(jù)WMS提供的窗口信息將事件交給合適的窗口
- 窗口的ViewRootImpl對象再沿著控件樹將事件派發(fā)給感興趣的控件
- 控件對齊收到的事件做出響應(yīng),更新自己的畫面、執(zhí)行特定的動作
下面介紹下參與者:
- Linux內(nèi)核:
接收輸入設(shè)備的中斷,將原始事件的數(shù)據(jù)寫入設(shè)備節(jié)點中。 - 設(shè)備節(jié)點:
內(nèi)核與IMS的橋梁,它將原始事件暴露給用戶空間,以便IMS可以從中讀取事件。 - InputManagerService:
一個Android的系統(tǒng)服務(wù),分為Java層和Native層。
Java層負責(zé)與WMS通信。
Native層則是InputReader和InputDispatcher兩個輸入系統(tǒng)關(guān)鍵組件的運行容器。 - EventHub:
通過getevents訪問設(shè)備節(jié)點,并把訪問到的原始輸入事件以及設(shè)備節(jié)點的增刪返回給使用者。 - InputReader:
運行在一個獨立的線程中。通過線程循環(huán)不斷的從EventHub中讀取原始事件,然后進行加工處理封裝為包含更多信息、更具可讀性的輸入事件,然后交給InputDispatcher進行派發(fā)。
當設(shè)備節(jié)點有增刪時,更新輸入設(shè)備列表和配置。 - InputReaderPolicy:
為InputReader加工處理原始事件,提供策略配置信息。例如:鍵盤布局。 - InputDispatcher:
運行在一個獨立的線程中。保管來自WMS的所有窗口的信息,其收到來自InputReader的輸入事件后,會在其保管的窗口中尋找合適的窗口,并將事件派發(fā)給此窗口。 - InputDispatcherPolicy:
為InputDispatcher派發(fā)過程提供策略。例如截取某些特定的輸入事件用作特殊用途,或者阻止將某些事件派發(fā)給目標窗口。
示例:截取HOME鍵到PhoneWindowManager中進行處理,阻止窗口收到HOME鍵按下的事件。 - WMS:
當新建窗口時,WMS為新窗口和IMS創(chuàng)建了事件傳遞所用的通道。
WMS實時更新窗口的可點擊區(qū)域、焦點窗口等信息給IMS的InputDispatcher。 - ViewRootImpl:
對某些窗口,如壁紙窗口、SurfaceView的窗口來說,窗口就是輸入事件派發(fā)的終點。而其他的,比如說Activity、對話框等使用了Android控件系統(tǒng)的窗口來說,輸入事件的終點是控件(View)。ViewRootImpl將窗口所接收的輸入事件沿著控件樹將事件派發(fā)給感興趣的控件。