ANR時間區別便是指當前這次的事件dispatch過程中執行findFocusedWindowTargetsLocked()方法到下一次執行resetANRTimeoutsLocked()的時間區間. 以下5個時機會reset. 都位於InputDispatcher.cpp文件:
- resetAndDropEverythingLocked
- releasePendingEventLocked
- setFocusedApplication
- dispatchOnceInnerLocked
- setInputDispatchMode
簡單來說, 上面方法主要是對應以下4個場景,會有機會執行resetANRTimeoutsLocked重置timeout時間:
- 解凍屏幕, 系統開/關機的時刻點 (thawInputDispatchingLw, setEventDispatchingLw)
- wms聚焦app的改變 (WMS.setFocusedApp, WMS.removeAppToken)
- 設置input filter的過程 (IMS.setInputFilter)
- 再次分發事件的過程(dispatchOnceInnerLocked)
當InputDispatcher線程 findFocusedWindowTargetsLocked()過程調用到handleTargetsNotReadyLocked,且滿足超時5s的情況則會調用onANRLocked().
通過將InputManagerService加入到Watchdog的monitor隊列,定時監測是否發生死鎖. 整個監測過涉及EventHub, InputReader, InputDispatcher, InputManagerService的死鎖監測. 監測的原理很簡單,通過嘗試獲取鎖並釋放鎖的方式.
可通過adb shell dumpsys input
來查看手機當前的input狀態, 輸出內容分別為EventHub.dump(), InputReader.dump(),InputDispatcher.dump()這3類,另外如果發生過input ANR,那么也會輸出上一個ANR的狀態.
其中mPendingEvent代表的當下正在處理的事件.
ANR分類
由小節[3.5] InputMonitor.notifyANR完成, 當發生ANR時system log中會出現以下信息, 並且TAG=WindowManager:
Input event dispatching timed out xxx. Reason: + reason
, 其中xxx取值:
- 窗口類型: sending to
windowState.mAttrs.getTitle()
- 應用類型: sending to application
appWindowToken.stringName
- 其他類型: 則為空.
至於Reason主要有以下類型:
5.1.1 reason類型
由checkWindowReadyForMoreInputLocked完成, ANR reason主要有以下幾類:
- 無窗口, 有應用:Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.
- 窗口暫停: Waiting because the
[targetType]
window is paused. - 窗口未連接: Waiting because the
[targetType]
window’s input channel is not registered with the input dispatcher. The window may be in the process of being removed. - 窗口連接已死亡:Waiting because the
[targetType]
window’s input connection is[Connection.Status]
. The window may be in the process of being removed. - 窗口連接已滿:Waiting because the
[targetType]
window’s input channel is full. Outbound queue length:[outboundQueue長度]
. Wait queue length:[waitQueue長度]
. - 按鍵事件,輸出隊列或事件等待隊列不為空:Waiting to send key event because the
[targetType]
window has not finished processing all of the input events that were previously delivered to it. Outbound queue length:[outboundQueue長度]
. Wait queue length:[waitQueue長度]
. - 非按鍵事件,事件等待隊列不為空且頭事件分發超時500ms:Waiting to send non-key event because the
[targetType]
window has not finished processing certain input events that were delivered to it over 500ms ago. Wait queue length:[waitQueue長度]
. Wait queue head age:[等待時長]
.
其中
- targetType: 取值為”focused”或者”touched”
- Connection.Status: 取值為”NORMAL”,”BROKEN”,”ZOMBIE”
另外, findFocusedWindowTargetsLocked, findTouchedWindowTargetsLocked這兩個方法中可以通過實現 updateDispatchStatisticsLocked()來分析anr問題.
drop事件分類
由dropInboundEventLocked完成,輸出事件丟棄的原因:
- DROP_REASON_POLICY: “inbound event was dropped because the policy consumed it”;
- DROP_REASON_DISABLED: “inbound event was dropped because input dispatch is disabled”;
- DROP_REASON_APP_SWITCH: “inbound event was dropped because of pending overdue app switch”;
- DROP_REASON_BLOCKED: “inbound event was dropped because the current application is not responding and the user has started interacting with a different application””;
- DROP_REASON_STALE: “inbound event was dropped because it is stale”;
其他:
- doDispatchCycleFinishedLockedInterruptible的過程, 會記錄分發時間超過2s的事件,
- findFocusedWindowTargetsLocked的過程, 可以統計等待時長信息.