天天看點

Android入門之從輸入裝置中擷取消息——綜述

        Android2.3中的消息擷取過程如下所示:

Android入門之從輸入裝置中擷取消息——綜述

這裡涉及到以下名詞:

        (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中。

        過程如下圖所示:

Android入門之從輸入裝置中擷取消息——綜述

        視窗建立完成後,則等待使用者消息。

        上面提到過,InputReader線程會持續調用輸入裝置的驅動來讀取使用者消息,然後把使用者消息傳遞給InputDispatcher線程,InputDispatcher中儲存了視窗資訊,是以可以根據使用者消息找到對應的視窗資訊,找到後連同視窗資訊一起傳給NativeInputManager。

        NativeInputManager擷取到消息及視窗資訊後,與内部儲存的視窗資訊比對,判斷是否按鍵消息, 若是按鍵消息,則傳遞給WmS,否則傳回客戶視窗。

        WmS擷取到按鍵消息後,通過InputMonitor内部儲存的視窗資訊比對及内部的一些函數,判斷是否是系統按鍵,若不是,則傳回給InputDispatcher,InputDispatcher通過Pipe傳回ViewRoot;若是系統按鈕,則直接調用内部函數處理,不再傳回使用者視窗。

        過程如下所示:

Android入門之從輸入裝置中擷取消息——綜述

        由上文可知,InputDispatcher和使用者視窗之間存在兩個管道(Pipe),用來實作InputDispatcher和ViewRoot之間的雙向互動。

        補充一點Pipe的知識:Pipe是Linux的一種系統調用,Linux會在核心位址空間中開辟一段共享記憶體,并産生一個Pipe對象,每個Pipe對象内部都會自動建立兩個檔案描述符,一個用于讀,一個用于寫。檔案描述符是全局唯一的,進而使得兩個程序之間可以借助這兩個描述符,一個往管道中寫資料,另一個從管道中讀取資料,故而,管道是單向的,這也是為什麼說InputDispatcher和使用者視窗之間的雙向通信需要借助兩個管道。