Android Input事件獲取與分發簡單總結

一、整體流程

系統Input事件傳遞主要經過如下幾個部分:

1.1輸入系統部分

輸入子系統

手機的輸入設備(包括屏幕、鍵盤、鼠標等),當前可用,會在文件系統/dev/input中創建對應的設備節點,用戶操作輸入設備會產生輸入事件(按鍵事件、觸摸事件、鼠標事件)等。

/dev/input/event0
/dev/input/event1
/dev/input/event2
...

InputManagerService
IMS初始化過程主要構造了如下結構:

從結構看,IMS核心功能實現在Native層:

  • IMS由SystemServer創建。

  • 在system_server進程中包含兩個重要的線程InputReaderThread和InputDispatcherThread,其內部分別對應InputReader和InputDispatcher兩個工作類。

  • InputReader負責讀取底層收集的input事件:從EventHub讀InputEvent并且傳給InputDispatcher來進行分發。

  • InputDispatcher負責分發input事件到應用層。WindowManagerService在app端setView的時候就創建了一對Socket連接,InputDispatcher利用這個Socket連接和app端通信。

1.2 WMS處理部分

WMS的職責之一就是輸入系統的中轉站,WMS作為Window的管理者,會配合IMS將輸入事件交由合適的Window來處理。

1.3 View處理部分

app端的ViewRootImpl里面的InputEventReceiver會接到從Socket得到的InputEvent。最終走APP的事件傳遞,消費事件。

二、InputManagerService初始化過程

通過流程圖可以看出,這部分主要是做了一系列的初始化工作:

  • startOtherServices中,創建了IMS以及WMS,并將WMS中的monitor傳給了IMS,作為回調,最后啟動IMS。

  • IMS的初始化中執行了nativeInit,該方法中創建了一個NativeInputManager實例,并且和java層使用的是同一個looper。

  • 在NativeInputManager的初始化中創建了一個Eventhub,同時將這個Eventhub傳給新建的Inputmanager,Eventhub就是將數據從硬件驅動上讀出來然后傳遞上來的通道。

  • InputManager初始化時創建了兩個重要線程:InputReaderThread和InputDispatcherThread。

  • InputManager的start方法,讓兩個線程開啟了循環執行操作。

三、InputReader處理InputEvent流程

簡單總結:

  • InputReader啟動后執行loopOnce,它是一個可阻塞循環。

  • loopOnce循環中會通過Eventhub調用getEvents,來獲取底層input事件,getEvents其實分成了三部分,首先是進行device的讀取和處理,掃描/dev/input/目錄來生成device數據。二是看有沒有需要處理的時間,如果有那么就處理了返回。最后是進行等待,等待對應事件的發生。

  • 讀到了事件就會調用processEventsLocked處理事件:循環獲取EventHub給過來的事件,這里事件包括來自Kernel的input事件和對Input事件的插入和刪除操作(這個不管),針對Kernel的input事件,交給processEventsForDeviceLocked處理。

  • processEventsForDeviceLocked 調用對應的InputDevice處理Input事件,而InputDevice又會去匹配上對應的InputMapper來處理對應事件。(在InputDevice中,存儲著許多InputMapper,每種InputMapper對應一類Device,例如:Touch、Keyboard、Vibrator等等……)而調用InputDevice的process函數,就是將Input事件傳遞給每一個InputMapper,匹配的InputMapper就會對Input事件進行處理,不匹配的則會忽略。

  • InputMapper將數據綜合打包成三種數據封裝:NotifyKeyArgs、NotifyMotionArgs和NotifySwichArgs,分別對應key、Motion和Swich事件。

  • 最后調用mQueuedListener->flush(),將事件隊列中的所有事件交給在InputReader中注冊過的InputDispatcher。InputDispatcher先于InputReader被創建,InputDispatcher沒有輸入事件處理時會進入睡眠狀態,等待InputReader通知喚醒。InputDispatcher的notifyKey函數中會根據按鍵數據來判斷InputDispatcher是否要被喚醒,InputDispatcher被喚醒后,會重新調用dispatchOnceInnerLocked函數將輸入事件分發給合適的Window。

InputReader從EventHub獲取input event,將input event打包成Args放到InputDispacher的mInboundQueue,然后通過notifyKey喚醒InputDispacher。

四、InputDispatch分發流程

簡單總結:

上節InputReader把input event放入了mInboundQueue(NotifyMotionArgs轉換為MotionEntry,添加到隊尾)。InputDispatcherThread被喚醒后,通過InputDispatcher主要任務是找到對應的window,并建立進程間通信,把input event 傳遞過去。

  • InputDispatcher中,由dispatchOnceInnerLocked處理input event:

1)從mInboundQueue取出事件
2)通過EventEntry的類型,對不同事件進行不同處理,下面以TYPE_KEY為例
3)TYPE_KEY對應會執行dispatchKeyLocked,將事件分發出去

  • dispatchKeyLocked中做三件事情:

1)postCommandLocked 讓policy處理Home、Menu等系統按鍵,policy對應的是NativeInputManager
2)findFocusedWindowTargetsLocked 判斷發生按鍵事件的Window并得到對應的inputTargets
3)dispatchEventLocked 通過InputTarget獲取對應的Connection,每個焦點窗口在InputDispacher里都有一個對應的Connection,通過這個Connection可以跟InputDispacher通信。然后發送事件EventEntry,先是將eventEntry放入Connection的outboundQueue,再通過InputPublisher將Entry發送給窗口,再將Entry從outboundQueue移到waitQueue里,最后由InputPublisher調用InputChanel的SendMessage(),SendMessage()再動用socket的send()函數,將打包好的Message發送給窗口。

  • InputChannel封裝了窗口與InputDispatcher間的跨進程通信

應用在ViewRootImpl的setView(),最終會調用IWindowSession的addToDisplay()函數,該函數帶上了mInputChannel參數,向WMS注冊Channel。

五、App端處理流程

簡單總結:

  • WindowInputEventReceiver中的onInputEvent回調執行enqueueInputEvent,從隊列中獲取一個QueuedInputEvent,判斷是立刻執行還是延遲執行,但是最終都會走doProcessInputEvents。

  • doProcessInputEvents中主要通過deliverInputEvent進行事件分發。這里核心是InputStage體系,責任鏈模式。最終會匹配上對應Stage來進行事件分發處理。

  • 以Activity,View的按鍵分發流程相關的InputStage:ViewPostImeInputStage為例,執行ProcessKeyEvent

第一步是調用PhoneWindow.DecorView的dispatchKeyEvent函數,DecorView是View層次結構的根節點,按鍵從根節點開始按View的事件傳遞流程走。

第二步是判斷按鍵是否是四向鍵,或者是TAB鍵,如果是則需要移動焦點。

本文只是參考了網上的文章,針對input系統總結了一個模糊的流程,input總體來看還是比較復雜的,想要深入學習還是需要針對源碼進行詳細分析。

參考
https://zhuanlan.zhihu.com/p/29152319
https://blog.csdn.net/urdfmqcul2/article/details/78146424
https://blog.csdn.net/xingchenxuanfeng/article/details/79208005
https://blog.csdn.net/chenweiaiyanyan/article/details/72884141

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
禁止轉載,如需轉載請通過簡信或評論聯系作者。

推薦閱讀更多精彩內容