Android輸入系統筆記

InputDispatcher的線程循環由InputDispatchr::diapatchOnce()完成


InputDispatcher::diapatchOnce(){
1、通過dispatcherInnerOnceLocked()進行輸入事件的派發,其傳出參數nextWeakupTime決定下次派發線程的循還執行時間
2、執行命令隊列中的命令,可以通過InputDispatcher::postCommandLocked()函數將命令追加到命令列表中
3,如果有必要,將派發線程進入休眠狀態,並由nextWeakupTime確定具體的休眠時間,Looper的pollOnce的實質就是epoll_wait()
  派發線程在三種情況下將被喚醒:
1、有事件注入派發列隊時,調用Looper::wake()主動喚醒
2、epol_wait()堅挺的fd有epoll_event發生時
3、到達nextWeakupTime的時間點時
}




//該函數體現了派發過程的整體流程
InputDispatcher::dispatcherInnerOnceLocked(nextWeakUpTime){
1、setInputDispatchMode()函數可以使InputDispatcher在禁用,凍結,和正常三種狀態下切換
2、從派發隊列中取出一事件進行派發
如果派發隊列爲空,則直接返回。nextWeakupTime保持LONG_LONG_MAX,派發隊列進入無限的休眠期
   resetANRTimeoutsLocked(),爲事件重置ANR信息
3、檢查時間是否需要被丟棄,dropReason描述了時間是否需要被丟棄
4、執行dispatchMotionLocked()進行Motion事件的派發
}


DropReason枚舉完整的描述了是事件被丟棄的所有原因:
1、DROP_REASON_POLICY:
2、DROP_REASON_APP_SWITCH
3、DROP_REASON_BLOCKED
4、DROP_REASON_DISABLED
5、DROP_REASON_STALE


//專門爲Motion事件尋找合適的目標窗口
dispatchMotionLocked(){
1、根據Motion事件,尋找合適的窗口,injectionResult保存尋找結果,找到的合適的窗口將會被保存在inputTarget列表中
findTouchedWindowTargetsLocked(correntTime,entry,inputTargets,nextWakeupTime,&conflictPointerActions)
2、調用dispatchEventLocked()將事件派發給inputTargets中
}


InputDispatcher::findTouchedWindowTargetsLocked(){
1、遍歷mWindowsHandles列表中所有的WindowHandle,檢查事件座標點是否落在其上
2、檢查TempTouchState中所有的目標窗口是否已準備好接受新的輸入事件
3、若窗口查找成功,設置injectionResult爲SUCCEEDED,並將生成的InputTarget放入參數inputTargets中
}


InputDispatcher::dispatchEventLocked(){
//根據InputTarget中的InputChannel獲取對應的Connection對象的索引
1、getConnectionIndexLocked(inputTarget,inputChannel)
//調用prepareDispatchCycleLocked()針對當前的InputTarget啓動發送事件循環
}




prepareDispatchCycleLocked(){
//將事件添加到Connection的發送隊列中
 enqueueDiapatchEntriesLocked(curentTime,connection,eventEntry,inputTarget)
}


enqueueDiapatchEntriesLocked(curentTime,connection,eventEntry,inputTarget){
//將事件信息封裝成DispatchEntry,然後注入Connection的發送隊列中
enqueueDiapatchEntryLocked(connection,eventEntry,inputTarget,InputTarget::FLAG_DISPATCH_AS_IS)

//啓動發送循環
startDispatchCycleLocked(currentTime,connection)
}
FLAG_DISPATCH_AS_IS表示不修改事件的action類型
startDispatchCycleLocked(currentTime,connection){
//不斷的從發送隊列中獲取DispatchEntry,並將事件發送到InputChannel中

//根據不同的事件類型,選擇InputPublisher不同的發送函數

//將DispatchEntry轉存到waitQueue中
}

//派發按鍵事件
dispatchKeyLocked(){

}


//將事件注入派發列隊
InputDispatcher::notifyKey(){
1、根據policyF了該修改事件的mateState
2、詢問按鍵事件上的派發策略
interceptKeyBeforeQueueing()
3、構建KeyEntry
}




Command命令執行doInterceptKeyBeforeDispatcher()函數想DispatcherPolicy查詢派發策略,將結果保存在interceptKeyResult中
InputDispatcher::doInterceptKeyBeforeDispatcher(){
//創建KeyEvent對象
//調用interceptKeyBeforeDiapatching()從DispatcherPolicy中獲取派發策略,返回延遲派發的時間delay
}


delay的三種取值:
1、INTERCEPT_KEY_RESULT_SKIP:表示DispatcherPolicy自己處理按鍵事件,不希望派發給用戶
2、INTERCEPT_KEY_RESULT_CONTINUE:表示可以正常的派發給用戶
3、INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER:表示DispatcherPolicy尚未決定好如何處理這個按鍵事件,暫停派發工作,時間又delay決定



DispatcherPolicy是一個實現了DispatcherPolicyInterface的對象,保存在InputDispatcher的mPolicy成員變量中


interceptMotionBeforeQueueing()的調用發生在Reader線程中,其主要作用是返回policyFlags派發策略,PhoneWindowManager可以根據設備的狀態返回如下策略:
POLICY_FLAG_WOKE_HERE:
POLICY_FLAG_BRIGHT_HERE
POLICY_FLAG_PASS_TO_USER

InputManagerService::InputManagerService.filterInputEvent(InputEvent event,int policyFlags){

}




輸入事件的發送,接收與反饋
InputChannel的本質是一對SocketPair(非網絡套接字),用來實現在本機內進行進程的通信
InputChannel::openInputChannelPair(){

}


public int addWindow(......,InputChannel outInputChannel){
//openInputChannelPair()調用Native層的openInputChannelPair()函數,並將兩個Native層的InputChannel對象封裝爲Java對象返回


//其中一個InputChannel端交給WindowState保存
1、win.setInputChannel(inputChannels[0])

//另一個InputChannel則通過transferTo函數傳遞給調用者
 2、inputChannels[1].transferTo(outInputChannel)

//將WindowState所保存的InputChannel向IMS進行註冊
 3、registerInputChannel(win.mInputChannel,win.mInputWindowHandle)


//將所有的窗口信息更新到InputManagerService
 mInputMonitor.updateInputWindowsLw(false)
}


registerInputChannel(InputChannel inputChannel,INputWindowHandle inputWindowHandle){
//直接調用nativeRegisterInputChannel,由Native層完成註冊工作
 nativeRegisterInputChannel(mPtr,inputChannel,inputWindowHandle,false)
}


實際的註冊過程在InputDispatcher的同名函數完成
InputChannel(const sp<InputChannel>& inputChannel,const sp<InputWindowHandle>& inputWindowHandle,bool monitor){
1、爲傳入的InputChannel創建一個Connection對象並進行封裝
new Connection(inpputChannel,inputWindowHandle,monitor)

2、監聽InputChannel的可讀性。Looper對象具有監聽文件描述符可讀性時間的能力
}




InputMonitor.updateInputWindowsLw(boolean force){
//獲取用於遍歷所有WMS窗口的枚舉器,其參數表示採用反向遍歷
//將窗口的佈局信息轉存到inputWindowHandle中,然後將inputWindowHandle保存到mInputWindowHandles列表中
 addInputWindowHandleLw();
 
//mInputWindowHandles列表提交給InputManagerService
 mServic.mInputManager.setInputWindows(mInputWindowHandles)
 
//清空mInputWindowHandles列表
 clearInputWindowHandleLw()
}


setInputWindows(mInputWindowHandles){
1使用傳入的InputWindowHandle列表替換現有的列表

2、調用updateInfo()函數,將JAVA層的佈局信息搬運到其InputWindowInfo

3、將焦點窗口保存到mInputWindowHandle中
}




窗口端連接的建立
窗口端通過addWindow()函數獲得InputChannel後,便會使用它創建一個InputEventReceiver對象,該對象可以接收來自InputChannel的輸入事件
InputHandler是SampleWindow實現的一個繼承自InputEventReceiver的類


事件的接收
InputPublisher將事件以InputMessage的形式寫入InputChannel之後,Looper會被喚醒,執行InputEventReceiver的handle-Event(),該方法直
接調用了consumeEvent()。
consumeEvent(){
1、通過consume()函數從InputChannel中讀取一條InputMessage,解析爲InputEvent,作爲參數傳出

2、根據事件的類型分別創建KeyEvent與MotionEvent的Java對象

3、通過JNI回調Java層的InputEventReceiver的dispatchInputEvent()函數
}


InputEventReceiver.dispatchInputEvent(){
//保存來自InputDispatcher的序列號

//調用onInputEvent(event)函數
}


事件的反饋與發送循環
事件的反饋由InputEventReceiver.finishInputEvent()發起
InputEventReceiver.finishInputEvent(){
//從字典中將事件對應的序列號取出
IndexOfKey();
//由nativeFinishInputEvent完成反饋動作
nativeFinishInputEvent(mReceiverPtr,seq,handled)
}


發送過程由NativeInputEventReceiver完成
NativeInputEventReceiver::finishInputEvent(){
//由mInputConsumer將handle兩個信息以InputMessage的形式寫入InputChannel中
mInputConsumer.sendFinishedSignal(seq,handled)
}


當InputChannel被寫入數據時,會觸發服務端的InputChannel可讀性事件,InputDispatcher的被喚醒,執行handleReceiverCallback()
handleReceiverCallback(){
//1、獲取對應的Connection對象

//2、循環讀取竟可能多的反饋信息

//3、調用finishDispatchCycleLocked()函數完成對反饋的處理
}




finishDispatchCycleLocked()函數將向InputDispatcher發送一個命令,處理反饋的函數是doDispatcherCycleFinishLockedInterruptible()
doDispatcherCycleFinishLockedInterruptible(){

}




焦點窗口:即當前操作的窗口,尋找焦點窗口的基本原則是沿着ZOrder的順序從上到下遍歷窗口







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章