一旗芬、整體流程
系統(tǒng)Input事件傳遞主要經(jīng)過如下幾個部分:
1.1輸入系統(tǒng)部分
輸入子系統(tǒng)
手機(jī)的輸入設(shè)備(包括屏幕疮丛、鍵盤、鼠標(biāo)等)履恩,當(dāng)前可用暇屋,會在文件系統(tǒng)/dev/input中創(chuàng)建對應(yīng)的設(shè)備節(jié)點咐刨,用戶操作輸入設(shè)備會產(chǎn)生輸入事件(按鍵事件、觸摸事件定鸟、鼠標(biāo)事件)等联予。
/dev/input/event0
/dev/input/event1
/dev/input/event2
...
InputManagerService
IMS初始化過程主要構(gòu)造了如下結(jié)構(gòu):
從結(jié)構(gòu)看材原,IMS核心功能實現(xiàn)在Native層:
IMS由SystemServer創(chuàng)建余蟹。
在system_server進(jìn)程中包含兩個重要的線程InputReaderThread和InputDispatcherThread子刮,其內(nèi)部分別對應(yīng)InputReader和InputDispatcher兩個工作類。
InputReader負(fù)責(zé)讀取底層收集的input事件:從EventHub讀InputEvent并且傳給InputDispatcher來進(jìn)行分發(fā)葵孤。
InputDispatcher負(fù)責(zé)分發(fā)input事件到應(yīng)用層橱赠。WindowManagerService在app端setView的時候就創(chuàng)建了一對Socket連接狭姨,InputDispatcher利用這個Socket連接和app端通信。
1.2 WMS處理部分
WMS的職責(zé)之一就是輸入系統(tǒng)的中轉(zhuǎn)站绑莺,WMS作為Window的管理者惕耕,會配合IMS將輸入事件交由合適的Window來處理诫肠。
1.3 View處理部分
app端的ViewRootImpl里面的InputEventReceiver會接到從Socket得到的InputEvent栋豫。最終走APP的事件傳遞,消費事件蛤铜。
二丛肢、InputManagerService初始化過程
通過流程圖可以看出,這部分主要是做了一系列的初始化工作:
startOtherServices中穆刻,創(chuàng)建了IMS以及WMS杠步,并將WMS中的monitor傳給了IMS,作為回調(diào)朵锣,最后啟動IMS诚些。
IMS的初始化中執(zhí)行了nativeInit,該方法中創(chuàng)建了一個NativeInputManager實例助析,并且和java層使用的是同一個looper椅您。
在NativeInputManager的初始化中創(chuàng)建了一個Eventhub,同時將這個Eventhub傳給新建的Inputmanager雪隧,Eventhub就是將數(shù)據(jù)從硬件驅(qū)動上讀出來然后傳遞上來的通道员舵。
InputManager初始化時創(chuàng)建了兩個重要線程:InputReaderThread和InputDispatcherThread马僻。
InputManager的start方法,讓兩個線程開啟了循環(huán)執(zhí)行操作措近。
三女淑、InputReader處理InputEvent流程
簡單總結(jié):
InputReader啟動后執(zhí)行l(wèi)oopOnce鸭你,它是一個可阻塞循環(huán)。
loopOnce循環(huán)中會通過Eventhub調(diào)用getEvents阁谆,來獲取底層input事件瓣窄,getEvents其實分成了三部分,首先是進(jìn)行device的讀取和處理裳凸,掃描/dev/input/目錄來生成device數(shù)據(jù)。二是看有沒有需要處理的時間逗宁,如果有那么就處理了返回梦湘。最后是進(jìn)行等待,等待對應(yīng)事件的發(fā)生哼拔。
讀到了事件就會調(diào)用processEventsLocked處理事件:循環(huán)獲取EventHub給過來的事件瓣颅,這里事件包括來自Kernel的input事件和對Input事件的插入和刪除操作(這個不管)宫补,針對Kernel的input事件,交給processEventsForDeviceLocked處理健民。
processEventsForDeviceLocked 調(diào)用對應(yīng)的InputDevice處理Input事件贫贝,而InputDevice又會去匹配上對應(yīng)的InputMapper來處理對應(yīng)事件。(在InputDevice中凤优,存儲著許多InputMapper蜈彼,每種InputMapper對應(yīng)一類Device幸逆,例如:Touch暮现、Keyboard、Vibrator等等……)而調(diào)用InputDevice的process函數(shù)拍顷,就是將Input事件傳遞給每一個InputMapper塘幅,匹配的InputMapper就會對Input事件進(jìn)行處理,不匹配的則會忽略踏揣。
InputMapper將數(shù)據(jù)綜合打包成三種數(shù)據(jù)封裝:NotifyKeyArgs捞稿、NotifyMotionArgs和NotifySwichArgs,分別對應(yīng)key彰亥、Motion和Swich事件衰齐。
最后調(diào)用mQueuedListener->flush(),將事件隊列中的所有事件交給在InputReader中注冊過的InputDispatcher仁卷。InputDispatcher先于InputReader被創(chuàng)建犬第,InputDispatcher沒有輸入事件處理時會進(jìn)入睡眠狀態(tài)歉嗓,等待InputReader通知喚醒。InputDispatcher的notifyKey函數(shù)中會根據(jù)按鍵數(shù)據(jù)來判斷InputDispatcher是否要被喚醒哮幢,InputDispatcher被喚醒后志珍,會重新調(diào)用dispatchOnceInnerLocked函數(shù)將輸入事件分發(fā)給合適的Window。
InputReader從EventHub獲取input event,將input event打包成Args放到InputDispacher的mInboundQueue敛纲,然后通過notifyKey喚醒InputDispacher淤翔。
四、InputDispatch分發(fā)流程
簡單總結(jié):
上節(jié)InputReader把input event放入了mInboundQueue(NotifyMotionArgs轉(zhuǎn)換為MotionEntry监嗜,添加到隊尾)。InputDispatcherThread被喚醒后稚补,通過InputDispatcher主要任務(wù)是找到對應(yīng)的window框喳,并建立進(jìn)程間通信五垮,把input event 傳遞過去。
- InputDispatcher中润绎,由dispatchOnceInnerLocked處理input event:
1)從mInboundQueue取出事件
2)通過EventEntry的類型诞挨,對不同事件進(jìn)行不同處理惶傻,下面以TYPE_KEY為例
3)TYPE_KEY對應(yīng)會執(zhí)行dispatchKeyLocked,將事件分發(fā)出去
- dispatchKeyLocked中做三件事情:
1)postCommandLocked 讓policy處理Home涂佃、Menu等系統(tǒng)按鍵蜈敢,policy對應(yīng)的是NativeInputManager
2)findFocusedWindowTargetsLocked 判斷發(fā)生按鍵事件的Window并得到對應(yīng)的inputTargets
3)dispatchEventLocked 通過InputTarget獲取對應(yīng)的Connection抓狭,每個焦點窗口在InputDispacher里都有一個對應(yīng)的Connection,通過這個Connection可以跟InputDispacher通信辐宾。然后發(fā)送事件EventEntry,先是將eventEntry放入Connection的outboundQueue,再通過InputPublisher將Entry發(fā)送給窗口叠纹,再將Entry從outboundQueue移到waitQueue里,最后由InputPublisher調(diào)用InputChanel的SendMessage()敞葛,SendMessage()再動用socket的send()函數(shù)惹谐,將打包好的Message發(fā)送給窗口驼卖。
- InputChannel封裝了窗口與InputDispatcher間的跨進(jìn)程通信
應(yīng)用在ViewRootImpl的setView()酌畜,最終會調(diào)用IWindowSession的addToDisplay()函數(shù)卿叽,該函數(shù)帶上了mInputChannel參數(shù),向WMS注冊Channel贩虾。
五缎罢、App端處理流程
簡單總結(jié):
WindowInputEventReceiver中的onInputEvent回調(diào)執(zhí)行enqueueInputEvent策精,從隊列中獲取一個QueuedInputEvent崇棠,判斷是立刻執(zhí)行還是延遲執(zhí)行,但是最終都會走doProcessInputEvents酬蹋。
doProcessInputEvents中主要通過deliverInputEvent進(jìn)行事件分發(fā)抽莱。這里核心是InputStage體系食铐,責(zé)任鏈模式。最終會匹配上對應(yīng)Stage來進(jìn)行事件分發(fā)處理象泵。
- 以Activity偶惠,View的按鍵分發(fā)流程相關(guān)的InputStage:ViewPostImeInputStage為例朗涩,執(zhí)行ProcessKeyEvent
第一步是調(diào)用PhoneWindow.DecorView的dispatchKeyEvent函數(shù),DecorView是View層次結(jié)構(gòu)的根節(jié)點兄一,按鍵從根節(jié)點開始按View的事件傳遞流程走出革。
第二步是判斷按鍵是否是四向鍵,或者是TAB鍵骂束,如果是則需要移動焦點栖雾。
本文只是參考了網(wǎng)上的文章析藕,針對input系統(tǒng)總結(jié)了一個模糊的流程,input總體來看還是比較復(fù)雜的竞慢,想要深入學(xué)習(xí)還是需要針對源碼進(jìn)行詳細(xì)分析治泥。
參考
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