ANR InputDispatching TimeOut超時判斷
InputDispatching超時判斷
android-9.0.0_r8
InputReader\InputDispatchers初始化,及其線程啓動
JNI涉及java層和C/C++層,ANR超時判斷在C/C++層
InputDispatching
Input事件超時主要是事件分發超時,從標題就有提示。
InputDispatcherThread是InputDispatcher的notifyMotion函數喚醒,執行InputDispatcherThread的threadLoop函數
dispatchOnceInnerLocked開始計時,handleTargetsNotReadyLocked裏進行判斷超時。
InputDispatcher::dispatchOnceInnerLocked()
在派發事件時,dispatchKeyLocked()和dispatchMotionLocked(), 需要找到當前的焦點窗口,焦點窗口才是最終接收事件的地方,找窗口的過程就會判斷是否已經發生了ANR。
1、當前時間,ANR計時的起點
2、當分發被凍結,則不再處理超時和分發事件的工作
3、如果isAppSwitchDue爲true,說明沒有及時響應HOME鍵等操作,則搶佔分發,丟棄其他所有即將要處理的事件。
4、mInboundQueue不爲空,則取出頭部的事件,放入mPendingEvent變量;並重置ANR時間
5、根據EventEntry的type類型分別處理,比如按鍵調用dispatchKeyLocked分發事件
6、執行完成(done)的處理。根據dropReason(默認DROP_REASON_NOT_DROPPED不處理)來決定是否丟失事件;releasePendingEventLocked 釋放當前正在處理的事件(即mPendingEvent); 強制立刻執行輪詢LONG_LONG_MIN
InputDispatcher::checkWindowReadyForMoreInputLocked()
ANR輸出相關原因
InputDispatching超時判斷
int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,
const EventEntry* entry,
const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
nsecs_t* nextWakeupTime, const char* reason) {
if (applicationHandle == NULL && windowHandle == NULL) {
if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) {
#if DEBUG_FOCUS
ALOGD("Waiting for system to become ready for input. Reason: %s", reason);
#endif
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY;
mInputTargetWaitStartTime = currentTime;
mInputTargetWaitTimeoutTime = LONG_LONG_MAX;
mInputTargetWaitTimeoutExpired = false;
mInputTargetWaitApplicationHandle.clear();
}
} else {
if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
#if DEBUG_FOCUS
ALOGD("Waiting for application to become ready for input: %s. Reason: %s",
getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str(),
reason);
#endif
nsecs_t timeout;
if (windowHandle != NULL) {
timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
} else if (applicationHandle != NULL) {
timeout = applicationHandle->getDispatchingTimeout(
DEFAULT_INPUT_DISPATCHING_TIMEOUT);
} else {
timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT;
}
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
mInputTargetWaitStartTime = currentTime;
mInputTargetWaitTimeoutTime = currentTime + timeout;
mInputTargetWaitTimeoutExpired = false;
mInputTargetWaitApplicationHandle.clear();
if (windowHandle != NULL) {
mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle;
}
if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) {
mInputTargetWaitApplicationHandle = applicationHandle;
}
}
}
if (mInputTargetWaitTimeoutExpired) {
return INPUT_EVENT_INJECTION_TIMED_OUT;
}
if (currentTime >= mInputTargetWaitTimeoutTime) {
onANRLocked(currentTime, applicationHandle, windowHandle,
entry->eventTime, mInputTargetWaitStartTime, reason);
// Force poll loop to wake up immediately on next iteration once we get the
// ANR response back from the policy.
*nextWakeupTime = LONG_LONG_MIN;
return INPUT_EVENT_INJECTION_PENDING;
} else {
// Force poll loop to wake up when timeout is due.
if (mInputTargetWaitTimeoutTime < *nextWakeupTime) {
*nextWakeupTime = mInputTargetWaitTimeoutTime;
}
return INPUT_EVENT_INJECTION_PENDING;
}
}
currentTime >= mInputTargetWaitTimeoutTime超時判斷,執行onANRLocked
1、currentTime是指執行dispatchOnceInnerLocked方法體的起點
2、mInputTargetWaitTimeoutTime = currentTime + timeout默認超時時間是五秒DEFAULT_INPUT_DISPATCHING_TIMEOUT
3、mInputTargetWaitCause等於INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY(應用沒有準備就緒),而前面resetANRTimeoutsLocked()過程是唯一用於重置等待理由的地方。可見,ANR時間區間是從dispatchOnceInnerLocked方法體的起點,直到下次執行handleTargetsNotReadyLocked()方法的這段應用未準備就緒的時間段,該時間段是否超過5s來決定是否觸發ANR。
ANR log輸出
JNI層
java層
和ANR service TimeOut 超時判斷、ANR Broadcast TimeOut 超時判斷一樣使用AppErrors.appNotResponding最終輸出Log
感謝
ANR機制以及問題分析
Input系統—ANR原理分析
Input系統—InputDispatcher線程
Android輸入系統(三)InputReader的加工類型和InputDispatcher的分發過程