Android輸入事件流程中的EventHub分析及源碼演示

Android2.3的輸入事件流程與以前版本有了較大的不同,這裏做一下詳細的分析,最後我把自己分析時用的演示代碼放在了這裏:

http://code.google.com/p/flying-on-android/

下面的分析都是基於這些源碼的,大家可以下載下來一邊看源碼一邊看文檔。源碼裏只要關注FlyingEvent這個類就可以了。如果只想看一下演示結果,可以直接把包裏的flying放到機器的/system/bin目錄執行,打開logcat後就可以看到演示輸出。運行程序時,機器屏幕會有異象產生,很正常,因爲這個程序原本是用於顯示SurfaceFlinger的,這次爲了演示EventHub稍微改了一下。大家只要關注FlyingEvent.cpp這個文件就好了。

大家也可以用源碼自己編譯出演示程序,只要把解壓後的flying文件夾放到/frameworks/base/cmds/目錄下,然後切換到flying目錄下使用mm編譯。

 

先大致介紹一下整個流程,再做重點分析。輸入事件流程一共涉及到下面這幾個文件:

/frameworks/base/services/java/com/android/server/WindowManagerService.java

/frameworks/base/services/java/com/android/server/InputManager.java

/frameworks/base/services/jni/com_android_server_InputManager.cpp

/frameworks/base/libs/ui/InputReader.cpp

/frameworks/base/libs/ui/InputDispatcher.cpp

/frameworks/base/libs/ui/EventHub.cpp

其中,WindowManagerService.java和InputManager.java主要向Android爲窗口系統提供服務,EventHub.cpp主要用來讀取設備文件中的RawEvent,而InputReader.cpp和InputDispatcher.cpp算是它們之間的對接層。

 

它們的關係是:WindowManagerService通過InputManager提供的接口開啓一個線程驅動InputReader不斷地從/dev/input/目錄下面的設備文件讀取事件,然後通過InputDispatcher分發給連接到WindowManagerService服務的客戶端。

InputReader從設備文件中讀取的是RawEvent,在交給InputDispatcher進行分發之前,它需要先把RawEvent進行轉化分類,拆分成KeyEvent、MotionEvent、TrackEvent各種類型等。這篇文章主要關注的就是這個RawEvent的拆分過程,所以我們的重點在EventHub.cpp中。並且,爲了簡單化分析過程,在這裏我的分析只關注觸摸屏事件。看它是如何從RawEvent被拆分成應用層用戶事件MotionEvent的。

 

看下面的分析之前,最好先去上面提到的地址把源碼下載下來,參照裏面的FlyingEvent.cpp。

 

整個過程大致分成這麼幾步:

一、初始化。

先new一個EventHub的實例:mEventHub(new EventHub),

接下來,開啓一個線程通過mEventHub不停地從設備文件中讀取RawEvent並處理:

while (1) {

    RawEvent event;

    mEventHub->getEvent(&event);

    process(event);

}

EventHub在初始化的時候做一些事情,

1、搜索當前的輸入設備每搜索到一個就會產生一個類型爲DEVICE_ADDED的事件,當讀取這種RawEvent時,InputReader會把搜索到的這個設備記錄下來。

2、如果搜索到了鍵盤時,就會加載鍵盤佈局文件。加載完成後產生一個類型爲FINISHED_DEVICE_SCAN的事件。這樣,後邊從驅動讀取用戶按鍵時,就會去加載的鍵盤佈局文件中尋找映射的鍵值封裝成KeyEvent返回給用戶。

 

二、EventHub初始化完畢後,就開始等待用戶輸入。線程一直阻塞在mEventHub->getEvent(&event),直到有用戶事件產生纔會返回。

當有一個事件產生時,傳遞給process進行處理。

 

三、事件拆分

FlyingEvent.process裏面主要調用了FlyingEvent.consume方法來處理用戶事件。這裏只分析touch事件。touch事件可以分爲三種:down,move,up。

down類型的touch事件需要四個RawEvent來完成,第一個是X座標(ABS_X),第二個是Y座標(ABS_Y),第三個代表方向(ABS_PRESSURE)(0的時候是up,1的時候是down,所以這裏應該是1),第四個是結束標誌(SYN_REPORT)。

move類型的touch事件需要三個RawEvent來完成,第一個是X座標,第二個是Y座標,第三個是結束標誌。

up類型的touch事件需要兩個RawEvent來完成,第一個代表方向(0的時候是up,1的時候是down,所以這裏應該是0),第四個是結束標誌。

可能你已經注意到了up事件是沒有座標信息的,它的座標信息與down(沒有move時)或最後一個move(down和up之間有move事件產生)事件的座標相同。

 

從FlyingEvent.consume方法中,每一個事件最終都會生成一個TouchEvent,然後調用printTouchEvent進行打印,最後把它存儲到eventBuffer中。

 

 

參考文章

李先靜的“Android輸入事件流程“,不過使用的Android版本比較老了。

http://blog.csdn.net/absurd/archive/2009/05/17/4195363.aspx


發佈了3 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章