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的分发过程

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