
InputManagerService(IMS)
Linux內(nèi)核,接受輸入設(shè)備的中斷,并將原始事件的數(shù)據(jù)寫(xiě)入設(shè)備節(jié)點(diǎn)中
設(shè)備接電,作為內(nèi)核與IMS的橋梁,將原始事件的數(shù)據(jù)暴露給用戶空間,以便IMS可以從中讀取事件
InputManagerService,一個(gè)android系統(tǒng)服務(wù),分為Java層和Native層兩部分,java層負(fù)責(zé)與WMS通信,而Native層則是InputReader和InputDispatcher兩個(gè)輸入系統(tǒng)關(guān)鍵組件的運(yùn)行容器
EventHub,直接訪問(wèn)所有的設(shè)備節(jié)點(diǎn),通過(guò)一個(gè)名為getEvents()的函數(shù)將所有輸入系統(tǒng)相關(guān)的待處理的底層事件返回給使用者,包括原始輸入事件,設(shè)備節(jié)點(diǎn)的增刪等
InputReader,是IMS中的關(guān)鍵組件之一,它運(yùn)行一個(gè)獨(dú)立的線程中,負(fù)責(zé)管理輸入設(shè)備的列表和配置,以及進(jìn)行輸入事件的加工處理,它通過(guò)其線程循環(huán)不斷地通過(guò)getEvents()函數(shù)從EventHub中將事件取出并進(jìn)行處理,對(duì)于設(shè)備節(jié)點(diǎn)的增刪事件,它會(huì)更新輸入設(shè)備列表與配置,對(duì)于原始輸入事件,InputReader對(duì)其進(jìn)行翻譯,組裝,封裝為包含更多信息,更多可讀性的輸入事件,然后交給InputDispatcher進(jìn)行派發(fā)
InputReaderPolicy,為InputReader的事件加工處理提供一些策略配置
InputDispatcher,是IMS中的另一個(gè)關(guān)鍵組件,運(yùn)行于一個(gè)獨(dú)立的線程中,InputDispatcher中保管來(lái)自WMS的所有窗口的信息,收到InputReader的輸入事件后,會(huì)在其保管的窗口中尋找合適的窗口,并將事件派發(fā)給此窗口
InputDispatcherPolicy,為InputDispatcher的派發(fā)過(guò)程提供策略控制,例如HOME鍵被InputDispatcherPolicy截取到PhoneWindowManager中處理,并阻止窗口收到HOME鍵按下的事件
WMS,并不是輸入系統(tǒng)的一員,新建窗口時(shí),WMS為新窗口和IMS創(chuàng)建了事件傳遞所用的通道,會(huì)將窗口的可點(diǎn)擊區(qū)域,焦點(diǎn)窗口等信息實(shí)時(shí)更新到IMS的InputDispatcher中,使得InputDispatcher可以正確將事件派發(fā)到指定窗口
ViewRootImpl,對(duì)某些窗口,如壁紙窗口,SurfaceView的窗口來(lái)說(shuō),窗口就是輸入事件派發(fā)的終點(diǎn),而對(duì)其他的如Activity,對(duì)話框等使用了Android控件系統(tǒng)的窗口來(lái)說(shuō),輸入事件的終點(diǎn)是控件
IMS構(gòu)成
SystemServer->ServerThread.run()
1.創(chuàng)建新的IMS對(duì)象
->com_android_server_input_InputManagerService.cpp->nativeInit()
創(chuàng)建了NativeInputManager對(duì)象,該對(duì)象實(shí)現(xiàn)了InputReaderPolicyInterface與InputDispatcherPolicyInterface接口,創(chuàng)建EventHub和InputManager,InputManager創(chuàng)建了InputReader與InputDispatcher以及InputReaderThread與InputDispatcherThread
2.調(diào)用IMS對(duì)象的start函數(shù)完成啟動(dòng)
![Upload Paste_Image.png failed. Please try again.]
![Upload Paste_Image.png failed. Please try again.]

InputReader的總流程
InputReader.cpp->InputReaderThread::threadLoop()
分三步:
1.首先從EventHub抽取未處理的時(shí)間列表,一類(lèi)是從設(shè)備節(jié)點(diǎn)讀取的原始輸入事件,另一類(lèi)則是輸入設(shè)備可用性變化事件,簡(jiǎn)稱(chēng)設(shè)備事件
2.processEventsLocked對(duì)事件進(jìn)行處理,對(duì)于設(shè)備事件,此函數(shù)對(duì)根據(jù)設(shè)備的可用性加載或移除設(shè)備對(duì)應(yīng)的配置信息,對(duì)原始輸入事件,則在進(jìn)行轉(zhuǎn)譯,封裝與加工后將結(jié)果暫存到mQueuedListener
3.所有事件處理完畢后,調(diào)用mQueuedListener.flush將所有暫存的輸入事件一次性地交給InputDispatcher
深入理解EventHub
1.設(shè)備節(jié)點(diǎn)監(jiān)聽(tīng)的建立
通過(guò)INotify與Epoll機(jī)制建立起對(duì)設(shè)備節(jié)點(diǎn)增刪事件以及可讀狀態(tài)的監(jiān)聽(tīng)
EventHub.cpp:EventHub
2.getEvents
使用Epoll的核心是mPendingEventItems數(shù)組,它是一個(gè)事件池,getEvents包含了原始輸入事件讀取,輸入設(shè)備加載/卸載等操作
3.輸入設(shè)備管理
每個(gè)輸入設(shè)備在dev/input/下有一個(gè)設(shè)備節(jié)點(diǎn),設(shè)備節(jié)點(diǎn)包含輸入設(shè)備的所有信息,EventHub負(fù)責(zé)在設(shè)備節(jié)點(diǎn)可用時(shí)加載并維護(hù)這些信息,并在設(shè)備節(jié)點(diǎn)被刪除時(shí)將其移除,名為Device的私有結(jié)構(gòu)體保存
4.原始輸入事件的監(jiān)聽(tīng)與讀取
當(dāng)設(shè)備的原始輸入事件到來(lái)之時(shí),getevents函數(shù)將會(huì)獲得一個(gè)Epoll事件,然后根據(jù)Epoll事件讀取文件描述符的原始輸入事件,將其填充到RawEvents結(jié)構(gòu)體并放入buffer中被調(diào)用者取走

深入理解InputReader
1.原始輸入事件的加工
InputReader:processEventsLocked
->inputReader:processEventsForDeviceLocked
->InputReader:InputDevice::process
InputDevice描述一個(gè)輸入設(shè)備,是一個(gè)存儲(chǔ)輸入設(shè)備信息的類(lèi)
InputMapper是InputReader中實(shí)際進(jìn)行原始輸入事件加工的場(chǎng)所
2.InputDevice與InputMapper
inputDevice創(chuàng)建InputReader:addDeviceLocked
->InputReader:createDeviceLocked

3.keyboard類(lèi)型事件的加工處理
(1)keyboardInputMapper配置(屏幕旋轉(zhuǎn)狀態(tài))
(2)鍵盤(pán)掃描碼與虛擬鍵值
掃描碼是硬件實(shí)現(xiàn),虛擬鍵值是操作系統(tǒng)實(shí)現(xiàn)
(3)掃描碼到虛擬鍵值的映射
InputReader->KeyboardInputMapper:process
(4)按鍵事件的加工處理
InputReader->keyboardInputMapper:processKey
4.Touch類(lèi)型事件的加工處理
(1)Touch類(lèi)型事件的信息與原始事件的組織方式
(2)TouchInputMapper的體系
![Upload Paste_Image.png failed. Please try again.]
(3)MultiTouchInputMapper的配置
MultiTouchInputMapper的configureRawPointerAxes獲取來(lái)自設(shè)備節(jié)點(diǎn)的各項(xiàng)觸控信息,同時(shí)構(gòu)建傳感器的物理坐標(biāo)系
TouchInputMapper的configureSurface獲取來(lái)自DisplayViewPort的屏幕方向以及屏幕坐標(biāo)系的信息,并計(jì)算物理坐標(biāo)系到屏幕坐標(biāo)系的差異信息
(4)點(diǎn)擊事件的信息收集
InputReader->MultiTouchInputMapper:process
->MultiTouchMotionAccumulator:process
(5)點(diǎn)擊事件信息的整合,變換與高級(jí)事件的生成
輸入事件的派發(fā)
1.將事件注入派發(fā)隊(duì)列
InputDispatcher實(shí)現(xiàn)了InputListenerInterface,并在InputReader循環(huán)的最后,QueuedInputListener調(diào)用此接口將InputReader產(chǎn)生的事件以及NotifyXXXArgs結(jié)構(gòu)體的形式提交給InputDispatcher
->InputDispatcher:notifyMotionLocked
->InputDispatcher:enqueueInboundEventLocked
2.派發(fā)線程的線程循環(huán)
InputDispatcher:dispatchOnce
派發(fā)線程的一次循環(huán)包括以下三項(xiàng):
進(jìn)行一次事件派發(fā),事件的派發(fā)工作僅當(dāng)命令隊(duì)列中沒(méi)有命令時(shí)才會(huì)進(jìn)行,派發(fā)工作會(huì)設(shè)置nextWakeupTime指明隨后休眠時(shí)間長(zhǎng)短
執(zhí)行命令列表中的命令
陷入休眠狀態(tài)
3.派發(fā)工作的整體流程
dispatchOnceInnerLocked函數(shù)體現(xiàn)派發(fā)過(guò)程
InputDispatcher:dispatchOnceInnerLocked
4.事件被丟棄的原因
.....
5.Motion事件目標(biāo)窗口的確定
InputDispatcher:dispatchMotionLocked
三項(xiàng)工作:
對(duì)于被丟棄的事件,返回true
為事件尋找合適的窗口,窗口分為普通窗口和監(jiān)聽(tīng)窗口,普通通過(guò)按點(diǎn)和焦點(diǎn)查找,監(jiān)聽(tīng)窗口則無(wú)條件監(jiān)聽(tīng)所有輸入事件
如果成功地找到可以接收事件的目標(biāo)窗口,通過(guò)dispatchEventLocked完成實(shí)際的派發(fā)工作
6.向窗口發(fā)送事件
InputDispatcher:dispatchEventLocked
按鍵事件的派發(fā)
1.將事件注入派發(fā)隊(duì)列

2.額外的派發(fā)策略查詢(xún)
InputDispatcher:dispatchOnceInnerLocked
3.重復(fù)按鍵事件
InputDispatcher:dispatchOnceInnerLocked
->InputDispatcher:dispatchKeyLocked 開(kāi)啟與關(guān)閉重復(fù)按鍵模擬
->InputDispatcher:synthesizeKeyRepeatLocked重復(fù)按鍵的生成
4.按鍵事件派發(fā)總結(jié)
按鍵事件通過(guò)notifyKey函數(shù)進(jìn)入InputDispatcher,在注入派發(fā)隊(duì)列前,使用DispatcherPolicy的interceptKeyBeforeQueueing函數(shù)詢(xún)問(wèn)后續(xù)的派發(fā)策略policyFlag
按鍵事件在正式派發(fā)給窗口前,進(jìn)行一次額外的派發(fā)策略查詢(xún),查詢(xún)的結(jié)果保存在keyEntry:interceptKeyResult,結(jié)果覺(jué)得事件是正常派發(fā),稍后派發(fā)還是丟棄
當(dāng)按鍵按下到按鍵抬起之間的時(shí)間里,dispatchOnceInnerLocked和dispatchKeyLocked會(huì)協(xié)同工作完成對(duì)重復(fù)按鍵事件的模擬
按鍵事件的派發(fā)目標(biāo)僅通過(guò)焦點(diǎn)方式進(jìn)行查找
輸入事件的發(fā)送,接收和反饋
InputDispatcher運(yùn)行于system_server進(jìn)程,窗口運(yùn)行于其它的應(yīng)用進(jìn)程中
深入理解InputChannel
InputChannel的本質(zhì)是一對(duì)SocketPair,SocketPair用來(lái)實(shí)現(xiàn)在本機(jī)內(nèi)進(jìn)行進(jìn)程間的通信
InputTransport->InputChannel:openInputChannelPair

連接InputDispatcher和窗口
WinodwManagerService:addwindow
WMS添加窗口時(shí),會(huì)創(chuàng)建一對(duì)InputChannel,其中一個(gè)保存在WindowState中,并注冊(cè)給IMS,它是服務(wù)端,另一個(gè)則通過(guò)傳出參數(shù)outInputChannel交給調(diào)用者,是客戶端
1.服務(wù)端連接的建立
addwindow函數(shù)中,有以下三項(xiàng)工作:
通過(guò)WindowState.setInputChannel函數(shù)保存服務(wù)端的InputChannel
通過(guò)IMS.registerInputChannel將InputChannel注冊(cè)到IMS
通過(guò)InputMonitor.updateInputWindowsLw將所有窗口的信息更新到IMS
2.窗口端連接的建立
當(dāng)窗口端通過(guò)addwindow函數(shù)獲取InputChannel,便會(huì)使用它創(chuàng)建一個(gè)InputEventReceiver對(duì)象,可以接收來(lái)自InputChannel的輸入事件,觸發(fā)onInputEvent回調(diào)
InputEventRecevier如何工作?將InputChannel的可讀事件注冊(cè)到Looper,然后在事件到來(lái)時(shí)從InputChannel中讀取InputMessage,并翻譯成InputEvent,然后回調(diào)InputEventReceiver的onInputEvent
3.InputDispatcher與窗口的連接

事件的發(fā)送
派發(fā)循環(huán)是指InputDispatcher不斷地派發(fā)隊(duì)列取出事件,尋找合適的窗口并進(jìn)行發(fā)送的過(guò)程,是InputDispatcher線程的主要工作
事件發(fā)送循環(huán)是InputDispatcher通過(guò)Connection對(duì)象將事件發(fā)送給窗口,并接受其反饋的過(guò)程
InputDispatcher->dispatchEventLocked:dispatchEventLocked根據(jù)InputTarget中的InputChannel找到對(duì)應(yīng)的Connection
->InputDispatcher:prepareDispatcCycleLocked
->InputDispatcher:enqueueDispatchEntriesLocked
->InputDispatcher:startDispatchCycleLocked
輸入事件被InputPublisher以InputMessage的形式寫(xiě)入InputChannel,然后將事件轉(zhuǎn)存到waitQueue中等待窗口的反饋
事件的接收
當(dāng)InputPublisher將事件以InputMessage的形式寫(xiě)入InputChannel中,窗口端的Looper會(huì)因此而被喚醒,并執(zhí)行NativeInputEventReceiver的handleEvent調(diào)用consumeEvent
->android_view_InputEventReceiver->NativeInputEventReceiver:consumeEvent讀取一個(gè)InputEvent,生成java層的InputEvent對(duì)象,最后通過(guò)JNI回調(diào)
->InputEventReceier:dispatchInputEvent
事件的反饋與發(fā)送
->inputEventReceiver:finishInputEvent
->android_view_InputEventReceiver->NativeInputEventReceiver:finishInputEvent觸發(fā)服務(wù)端InputChannel回調(diào)
->InputDispatcher:handleReceiveCallback
->InputDispatcher:doDispatchCycleFinishedLockedInterruptible
對(duì)于輸入事件反饋的處理主要有兩個(gè)方面
將事件從Connection的waitQueue隊(duì)列中刪除,這個(gè)刪除動(dòng)作標(biāo)志著此事件的派發(fā)流程完成
最后調(diào)用startDispatchCycleLocked繼續(xù)嘗試發(fā)送隊(duì)列中的下一個(gè)事件
輸入事件ANR的產(chǎn)生
->InputDispatcher:findFocusedWindowTargetsLocked
1.窗口可以接收事件的條件
->InputDispatcher:isWindowReadyForMoreInputLocked判斷窗口是否可以接收事件:InputPublisher是否被阻塞以及Connection兩個(gè)隊(duì)列的狀態(tài)
2.重試派發(fā)與ANR的引發(fā)
->InputDispatcher:handleTargetsNotReadyLocked