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的分發過程

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