通过源码搞定ANR Log如何产生(一)

710 阅读3分钟

前言:我们经常分析ANR log,但是它是如何生成到本地的,系统又如何知道发生了ANR并且将相关log收集起来的。那就看接下来吧!

首先通过InputDispatcher超时,触发ANR的时候开始

1,Android系统处理input事件的是inputFlinger,每次处理input 事件的时候,要执行到native的一个方法:

frameworks/native/services/inputflinger/InputDispatcher.cpp 中的findFocusedWindowTargetsLocked(...)方法,每次处理input的事件的时候都会走到这个函数中

     1.1 判断focusedWindowHandle == nullptr and focusedApplicationHandle != nullptr 时,执行handleTargetsNotReadyLocked()方法

int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, 
                      const EventEntry* entry, std::vector& inputTargets, 
                      nsecs_t* nextWakeupTime) {
    // If there is no currently focused window and no focused application
    // then drop the event.
    //当前没有焦点窗口and没有焦点应用,执行handleTargetsNotReadyLocked
    if (focusedWindowHandle == nullptr) {
        if (focusedApplicationHandle != nullptr) {
            injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                    focusedApplicationHandle, nullptr, nextWakeupTime,
                    "Waiting because no window has focus but there is a "
                    "focused application that may eventually add a window "
                    "when it finishes starting up.");
            goto Unresponsive;
        }
    }
}

Waiting because no window has focus but........这句log是不是就很眼熟

      1.2 handleTargetsNotReadyLocked() : 超过5s没有响应,就调用onANRLocked(),开始anr的逻辑

int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,const 
        EventEntry* entry,
        const sp& applicationHandle,
        const sp& windowHandle,
        nsecs_t* nextWakeupTime, const char* reason) {
        //currentTime >= mInputTargetWaitTimeoutTime 大致意思是超过5s没响应,
        //则执行触发anr的逻辑onANRLocked
    if (currentTime >= mInputTargetWaitTimeoutTime) {
        onANRLocked(currentTime, applicationHandle, windowHandle,
                entry->eventTime, mInputTargetWaitStartTime, reason);
    } 
}

      1.3 onANRLocked():这个方法内会收集Application is not responding.....,Window,Reason等的信息,然后通过调用InputDispatcher::doNotifyANRLockedInterruptible,去notify ANR

void InputDispatcher::onANRLocked(nsecs_t currentTime, const sp& applicationHandle,
        const sp& windowHandle,
        nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) {
    ALOGI("Application is not responding: %s.  "
            "It has been %0.1fms since event, %0.1fms since wait started.  Reason: %s",
            getApplicationWindowLabel(applicationHandle, windowHandle).c_str(),
            dispatchLatency, waitDuration, reason);

    mLastANRState += INDENT "ANR:\n";
    mLastANRState += StringPrintf(INDENT2 "Time: %s\n", timestr);
    mLastANRState += StringPrintf(INDENT2 "Window: %s\n",
            getApplicationWindowLabel(applicationHandle, windowHandle).c_str());
    mLastANRState += StringPrintf(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency);
    mLastANRState += StringPrintf(INDENT2 "WaitDuration: %0.1fms\n", waitDuration);
    mLastANRState += StringPrintf(INDENT2 "Reason: %s\n", reason);
    //这个方法会打印类似DispatchEnabled....这类的log,很重要的方法
    dumpDispatchStateLocked(mLastANRState);

    CommandEntry* commandEntry = postCommandLocked(
            & InputDispatcher::doNotifyANRLockedInterruptible);
}

  Application is not responding.....这句log,相信看过ANR log的同学应该很熟悉,继续往下看

      1.4 上面的代码会通过postCommandLocked(........doNotifyANRLockedInterruptible),执行doNotifyANRLockedInterruptible()方法 通过调用 mPolicy->notifyANR,真正的去notify anr

void InputDispatcher::doNotifyANRLockedInterruptible(
        CommandEntry* commandEntry) {
            
    nsecs_t newTimeout = mPolicy->notifyANR(
            commandEntry->inputApplicationHandle,
            commandEntry->inputChannel ? commandEntry->inputChannel->getToken() : nullptr,
            commandEntry->reason)
}

      1.5 notifyANR():通过jni调用java端的方法,即调用了java端的notifyANR()方法

           参数:mServiceObj: 是指InputManagerService.java  参考1.5.1

                    gServiceClassInfo.notifyANR: 是指java方法为notifyANR  参考1.5.2

nsecs_t NativeInputManager::notifyANR(const sp& inputApplicationHandle,
        const sp& token, const std::string& reason) {

    JNIEnv* env = jniEnv();
    jlong newTimeout = env->CallLongMethod(mServiceObj,
                gServiceClassInfo.notifyANR, tokenObj,reasonObj);
}

          1.5.1

1,mServiceObj,是通过传入的serviceObj参数赋值的,继续查看NativeInputManager
NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp& looper) :
        mLooper(looper), mInteractive(true) {

    mServiceObj = env->NewGlobalRef(serviceObj);

}
2,NativeInputManager,是在nativeInit中初始化的,参数也是从nativeInit中传入的,
该方法是在java端调用的
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {

    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());

}
3,通过java端的方法可以看出,serviceObj = this = InputManagerService.java
    public InputManagerService(Context context) {
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
    }

          1.5.2  gServiceClassInfo.notifyANR:jmethodID = notifyANR

static struct {
    jclass clazz;
    jmethodID notifyANR;
} gServiceClassInfo;

接下来,我们就要看看java端的notifyANR()方法了,详情请看下一篇