Android R Input 之ANR的产生与显示流程

Posted pecuyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android R Input 之ANR的产生与显示流程相关的知识,希望对你有一定的参考价值。

文章托管在gitee上 Android Notes , 同步csdn

在InputDispatcher的工作流程中,分析过过ANR相关的部分内容,这一篇来详细分析ANR的产生与显示流程

ANR 的检查

在InputDispatcher的dispatchOnce方法中,会在执行完事件派发与Commands后,通过processAnrsLocked方法处理ANR.

/// @frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::dispatchOnce() 
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
     // acquire lock
        std::scoped_lock _l(mLock);
        mDispatcherIsAlive.notify_all();  // 通知dispatcher线程还活跃, 用于检测死锁

        // Run a dispatch loop if there are no pending commands.
        // The dispatch loop might enqueue commands to run afterwards.
        if (!haveCommandsLocked())  // 如果没有commands 则进行事件分发
            dispatchOnceInnerLocked(&nextWakeupTime);
        

        // Run all pending commands if there are any.
        // If any commands were run then force the next poll to wake up immediately.
        if (runCommandsLockedInterruptible())  // 执行commands
            nextWakeupTime = LONG_LONG_MIN; // 立即进行下一轮的派发
        

        // If we are still waiting for ack on some events,
        // we might have to wake up earlier to check if an app is anr'ing.
        const nsecs_t nextAnrCheck = processAnrsLocked(); // 处理anr
        nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);

        // We are about to enter an infinitely long sleep, because we have no commands or
        // pending or queued events
        if (nextWakeupTime == LONG_LONG_MAX) 
            mDispatcherEnteredIdle.notify_all();  // 通知进入idle
        
     // release lock

    // Wait for callback or timeout or wake.  (make sure we round up, not down)
    nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    mLooper->pollOnce(timeoutMillis); // 等待进行下一轮循环

InputDispatcher::processAnrsLocked

这个方法用来处理ANR,返回值表示下次唤醒的时间,方法逻辑如下:

  • 如果有在等待出现焦点窗口的操作,判断是否有超时,如果出现超时,则会调用 onAnrLocked 通知出现ANR
  • 对所有的connection检查是否有ANR出现,出现则调用onAnrLocked 通知出现ANR

怎么理解Connection ANR? 在InputDispatcher的工作流程分析中可知, 派发了一个事件到目标窗口后,会将事件从Connection 的 outboundQueue -> waitQueue , 并添加到mAnrTracker 进行ANR追踪.AnrTracker存储了以该事件的超时时间为key,以InputChanel的token为value的记录(即<timeout,token>).如果client处理该事件后在timeout时间内发送事件反馈,则会将之前的ANR追踪记录清除(移除waitQueue和AnrTracker中的记录,),反之,那么就说明该事件处理超时,触发ANR.

/**
 * Check if any of the connections' wait queues have events that are too old.
 * If we waited for events to be ack'ed for more than the window timeout, raise an ANR.
 * Return the time at which we should wake up next.
 */
nsecs_t InputDispatcher::processAnrsLocked() 
    const nsecs_t currentTime = now();
    nsecs_t nextAnrCheck = LONG_LONG_MAX;
    // Check if we are waiting for a focused window to appear. Raise ANR if waited too long
    if (mNoFocusedWindowTimeoutTime.has_value() && mAwaitedFocusedApplication != nullptr) // 等待焦点应用的focused 窗口出现
        if (currentTime >= *mNoFocusedWindowTimeoutTime)  // 等待超时
            onAnrLocked(mAwaitedFocusedApplication);  // 通知ANR , 注意此处的参数是inputApplicationHandle
            mAwaitedFocusedApplication.clear(); // 清除等待焦点应用信息
            return LONG_LONG_MIN; // 立即进行下一轮循环
         else 
            // Keep waiting  继续等待焦点窗口出现, 计算到超时事件还有多久
            const nsecs_t millisRemaining = ns2ms(*mNoFocusedWindowTimeoutTime - currentTime);
            ALOGW("Still no focused window. Will drop the event in %" PRId64 "ms", millisRemaining);
            nextAnrCheck = *mNoFocusedWindowTimeoutTime;
        
    

    // Check if any connection ANRs are due 检查是否有connection中的ANR触发时间到了
    nextAnrCheck = std::min(nextAnrCheck, mAnrTracker.firstTimeout()); // 取出mAnrTracker最近的超时时间
    if (currentTime < nextAnrCheck)  // most likely scenario  还没到最近的超时时间,即还没发生ANR
        return nextAnrCheck;          // everything is normal. Let's check again at nextAnrCheck
    

    // If we reached here, we have an unresponsive connection.
    sp<Connection> connection = getConnectionLocked(mAnrTracker.firstToken());
    if (connection == nullptr)  // 检查对于的connection是否存在
        ALOGE("Could not find connection for entry %" PRId64, mAnrTracker.firstTimeout());
        return nextAnrCheck;
    
    connection->responsive = false; // 修改为未响应
    // Stop waking up for this unresponsive connection
    mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken()); // 移除此token对应的记录
    onAnrLocked(connection); // 通知ANR发生, 注意此处的参数是 Connection
    return LONG_LONG_MIN; // 立即进行下一轮循环

InputDispatcher::onAnrLocked

以参数为Connection的为例

void InputDispatcher::onAnrLocked(const sp<Connection>& connection) 
    // Since we are allowing the policy to extend the timeout, maybe the waitQueue
    // is already healthy again. Don't raise ANR in this situation
    if (connection->waitQueue.empty())  // 如果此时waitQueue为空,没有等待反馈的事件,不触发ANR.此种情况说明Connection恢复正常
        ALOGI("Not raising ANR because the connection %s has recovered",
              connection->inputChannel->getName().c_str());
        return;
    
    /**
     * The "oldestEntry" is the entry that was first sent to the application. That entry, however,
     * may not be the one that caused the timeout to occur. One possibility is that window timeout
     * has changed. This could cause newer entries to time out before the already dispatched
     * entries. In that situation, the newest entries caused ANR. But in all likelihood, the app
     * processes the events linearly. So providing information about the oldest entry seems to be
     * most useful.
     */
    DispatchEntry* oldestEntry = *connection->waitQueue.begin(); // 第一个超时没有收到反馈的事件
    const nsecs_t currentWait = now() - oldestEntry->deliveryTime; // 等待事件,与派发时的时间差
    std::string reason =
            android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s",
                                        connection->inputChannel->getName().c_str(),
                                        ns2ms(currentWait),
                                        oldestEntry->eventEntry->getDescription().c_str()); // 未响应原因
    // 记录ANR信息                                    
    updateLastAnrStateLocked(getWindowHandleLocked(connection->inputChannel->getConnectionToken()),
                             reason);
    // 将ANR处理的操作封装为command投递到队列. 处理command会调用 doNotifyAnrLockedInterruptible函数                        
    std::unique_ptr<CommandEntry> commandEntry =
            std::make_unique<CommandEntry>(&InputDispatcher::doNotifyAnrLockedInterruptible);
    commandEntry->inputApplicationHandle = nullptr;
    commandEntry->inputChannel = connection->inputChannel; // 指定inputChannel
    commandEntry->reason = std::move(reason);
    postCommandLocked(std::move(commandEntry));

InputDispatcher::doNotifyAnrLockedInterruptible

在onAnrLocked方法中post command到mCommandQueue, 在InputDispatcher的下一轮循环首先执行Command,会回调doNotifyAnrLockedInterruptible方法

void InputDispatcher::doNotifyAnrLockedInterruptible(CommandEntry* commandEntry) 
    sp<IBinder> token =
            commandEntry->inputChannel ? commandEntry->inputChannel->getConnectionToken() : nullptr;
    mLock.unlock();

    const nsecs_t timeoutExtension =  // 通过策略派发ANR, 返回值表示是否需要延长ANR超时时间
            mPolicy->notifyAnr(commandEntry->inputApplicationHandle, token, commandEntry->reason); // mPolicy 即 NativeInputManager

    mLock.lock();

    if (timeoutExtension > 0)  // 延长ANR超时时间
        extendAnrTimeoutsLocked(commandEntry->inputApplicationHandle, token, timeoutExtension);
     else 
        // stop waking up for events in this connection, it is already not responding
        sp<Connection> connection = getConnectionLocked(token);
        if (connection == nullptr) 
            return;
        
        cancelEventsForAnrLocked(connection); // 对Connection 发送取消事件
    

NativeInputManager::notifyAnr

注意 此方法是在InputDispatcher线程中被调用

/// @frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
nsecs_t NativeInputManager::notifyAnr(const sp<InputApplicationHandle>& inputApplicationHandle,
                                      const sp<IBinder>& token, const std::string& reason) 
#if DEBUG_INPUT_DISPATCHER_POLICY
    ALOGD("notifyANR");
#endif
    ATRACE_CALL();

    JNIEnv* env = jniEnv();
    ScopedLocalFrame localFrame(env);

    jobject inputApplicationHandleObj =
            getInputApplicationHandleObjLocalRef(env, inputApplicationHandle);

    jobject tokenObj = javaObjectForIBinder(env, token);  // InputChanel token
    jstring reasonObj = env->NewStringUTF(reason.c_str());

    jlong newTimeout = env->CallLongMethod(mServiceObj,   // 回调 IMS的 notifyANR
            gServiceClassInfo.notifyANR, inputApplicationHandleObj, tokenObj,
                 reasonObj);
    if (checkAndClearExceptionFromCallback(env, "notifyANR")) 
        newTimeout = 0; // abort dispatch
     else 
        assert(newTimeout >= 0);
    
    return newTimeout;

InputManagerService#notifyANR

/// @frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
// Native callback.
private long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
        String reason) 
    return mWindowManagerCallbacks.notifyANR(inputApplicationHandle,   // 此处的mWindowManagerCallbacks实际上是WMS的成员mInputManagerCallback
            token, reason);

InputManagerCallback#notifyANR

此方法是在InputDispatcher线程中被调用,不能做耗时操作.

/// @frameworks/base/services/core/java/com/android/server/wm/InputManagerCallback.java
/**
 * Notifies the window manager about an application that is not responding.
 * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
 *
 * Called by the InputManager.
 */
@Override
public long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
        String reason) 
    final long startTime = SystemClock.uptimeMillis();
    try 
        return notifyANRInner(inputApplicationHandle, token, reason); // 调用 notifyANRInner
     finally 
        // Log the time because the method is called from InputDispatcher thread. It shouldn't
        // take too long that may affect input response time.
        Slog.d(TAG_WM, "notifyANR took " + (SystemClock.uptimeMillis() - startTime) + "ms");
    

InputManagerCallback#notifyANRInner

private long notifyANRInner(InputApplicationHandle inputApplicationHandle, IBinder token,
        String reason) 
    ActivityRecord activity = null;
    WindowState windowState = null;
    boolean aboveSystem = false;
    int windowPid = INVALID_PID;

    preDumpIfLockTooSlow();

    //TODO(b/141764879) Limit scope of wm lock when input calls notifyANR
    synchronized (mService.mGlobalLock) 
        // 首先根据Window类型,计算ANR对话框需要的层级值
        // Check if we can blame a window
        if (token != null) 
            windowState = mService.mInputToWindowMap.get(token);
            if (windowState != null) 
                activity = windowState.mActivityRecord;
                windowPid = windowState.mSession.mPid;
                // Figure out whether this window is layered above system windows.
                // We need to do this here to help the activity manager know how to
                // layer its ANR dialog.
                aboveSystem = isWindowAboveSystem(windowState);
            
        

        // Check if we can blame an embedded window
        if (token != null && windowState == null) 
            EmbeddedWindow embeddedWindow = mService.mEmbeddedWindowController.get(token);
            if (embeddedWindow != null) 
                windowPid = embeddedWindow.mOwnerPid;
                WindowState hostWindowState = embeddedWindow.mHostWindowState;
                if (hostWindowState == null) 
                    // The embedded window has no host window and we cannot easily determine
                    // its z order. Try to place the anr dialog as high as possible.
                    aboveSystem = true;
                 else 
                    aboveSystem = isWindowAboveSystem(hostWindowState);
                
            
        

        // Check if we can blame an activity. If we don't have an activity to blame, pull out
        // the token passed in via input application handle. This can happen if there are no
        // focused windows but input dispatcher knows the focused app.
        if (activity == null && inputApplicationHandle != null) 
            activity = ActivityRecord.forTokenLocked(inputApplicationHandle.token);
        

        if (windowState != null) 
            Slog.i(TAG_WM, "Input event dispatching timed out "
                    + "sending to " + windowState.mAttrs.getTitle()
                    + ".  Reason: " + reason);
         else if (activity != null) 
            Slog.i(TAG_WM, "Input event dispatching timed out "
                    + "sending to application " + activity.stringName
                    + ".  Reason: " + reason);
         else 
            Slog.i(TAG_WM, "Input event dispatching timed out "
                    + ".  Reason: " + reason);
        

        mService.saveANRStateLocked(activity, windowState, reason); // WMS保持ANR状态
    

    // All the calls below need to happen without the WM lock held since they call into AM.
    mService.mAtmInternal.saveANRState(reason); //atms dump ANR信息 Dump of the activity state at the time of the last ANR

    if (activity != null && activity.appToken != null)  // 是一个Activity
        // Notify the activity manager about the timeout and let it decide whether
        // to abort dispatching or keep waiting.
        final boolean abort = activity.keyDispatchingTimedOut(reason, windowPid);// 最终也调用AMS的inputDispatchingTimedOut
        if (!abort) 
            // The activity manager declined to abort dispatching.
            // Wait a bit longer and timeout again later.
            return activity.mInputDispatchingTimeoutNanos;
        
     else if (windowState != null || windowPid != INVALID_PID)  // 是一个窗口
        // Notify the activity manager about the timeout and let it decide whether
        // to abort dispatching or keep waiting.
        long timeout = mService.mAmInternal.inputDispatchingTimedOut(windowPid, aboveSystem,
                reason);  // 调用AMS的inputDispatchingTimedOut
        if (timeout >= 0) 
            // The activity manager declined to abort dispatching.
            // Wait a bit longer and timeout again later.
            return timeout * 1000000L; // nanoseconds
        
    
    return 0; // abort dispatching

ActivityRecord#keyDispatchingTimedOut

/**
 * Called when the key dispatching to a window associated with the app window container
 * timed-out.
 *
 * @param reason The reason for the key dispatching time out.
 * @param windowPid The pid of the window key dispatching timed out on.
 * @return True if input dispatching should be aborted.
 */
public boolean keyDispatchingTimedOut(String reason, int windowPid) 
    ActivityRecord anrActivity;
    WindowProcessController anrApp;
    boolean windowFromSameProcessAsActivity;
    synchronized (mAtmService.mGlobalLock) 
        anrActivity = getWaitingHistoryRecordLocked();
        anrApp = app;
        windowFromSameProcessAsActivity =
                !hasProcess() || app.getPid() == windowPid || windowPid == INVALID_PID;
    

    if (windowFromSameProcessAsActivity)  // 同一进程
        return mAtmService.mAmInternal.inputDispatchingTimedOut(anrApp.mOwner,
                anrActivity.shortComponentName, anrActivity.info.applicationInfo,
                shortComponentName, app, false, reason); // 调用AMS的inputDispatchingTimedOut
     else 
        // In this case another process added windows using this activity token. So, we call the
        // generic service input dispatch timed out method so that the right process is blamed.
        return mAtmService.mAmInternal.inputDispatchingTimedOut(
                windowPid, false /* aboveSystem */, reason) < 0;
    

ActivityManagerService$LocalService#inputDispatchingTimedOut

// ActivityManagerInternal
@Override
public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason) 
    return ActivityManagerService.this.inputDispatchingTimedOut(pid, aboveSystem, reason);

ActivityManagerService#inputDispatchingTimedOut(int pid,…)

long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) 
    if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) 
        throw new SecurityException("Requires permission " + FILTER_EVENTS);
    
    ProcessRecord proc;
    long timeout;
    synchronized (this) 
        synchronized (mPidsSelfLocked) 
            proc = mPidsSelfLocked.get(pid);
        
        timeout = proc != null ? proc.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS;
    
    // 调用同名方法
    if (inputDispatchingTimedOut(proc, null, null, null, null, aboveSystem, reason)) 
        return -1;
    

    return timeout;

ActivityManagerService#inputDispatchingTimedOut(ProcessRecord proc,…)

/**
 * Handle input dispatching timeouts.
 * @return whether input dispatching should be aborted or not.
 */
boolean inputDispatchingTimedOut(ProcessRecord proc, String activityShortComponentName,
        ApplicationInfo aInfo, String parentShortComponentName,
        WindowProcessController parentProcess, boolean aboveSystem, String reason) 
    if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) 
        throw new SecurityException("Requires permission " + FILTER_EVENTS);
    

    final String annotation;
    if (reason == null) 
        annotation = "Input dispatching timed out";
     else 
        annotation = "Input dispatching timed out (" + reason + ")";
    

    if (proc != null) 
        synchronized (this) 
            if (proc.isDebugging())  // debug将延长ANR超时
                return false;
            

            if (proc.getActiveInstrumentation() != null) // 处理ActiveInstrumentation
                Bundle info = new Bundle();
                info.putString("shortMsg", "keyDispatchingTimedOut");
                info.putString("longMsg", annotation);
                finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);
                return true;
            
        
        // 通过AnrHelper调用appNotResponding
        mAnrHelper.appNotResponding(proc, activityShortComponentName, aInfo,
                parentShortComponentName, parentProcess, aboveSystem, annotation);
    

    return true;

AnrHelper#appNotResponding

/// @frameworks/base/services/core/java/com/android/server/am/AnrHelper.java
void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName,
        ApplicationInfo aInfo, String parentShortComponentName,
        WindowProcessController parentProcess, boolean aboveSystem, String annotation) 
    synchronized (mAnrRecords) 
      // 添加ANR记录
        mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,
                parentShortComponentName, parentProcess, aboveSystem, annotation));
    
    startAnrConsumerIfNeeded();

AnrHelper#startAnrConsumerIfNeeded

private void startAnrConsumerIfNeeded() 
    if (mRunning.compareAndSet(false, true)) 
        new AnrConsumerThread().start(); // 处理ANR线程
    

AnrConsumerThread#start

启动线程执行run方法

/**
 * The thread to execute @link ProcessRecord#appNotResponding. It will terminate if all
 * records are handled.
 */
private class AnrConsumerThread extends Thread 
    AnrConsumerThread() 
        super("AnrConsumer");
    

    private AnrRecord next() 
        synchronized (mAnrRecords) 
            return mAnrRecords.isEmpty() ? null : mAnrRecords.remove(0);
        
    

    @Override
    public void run() 
        AnrRecord r;
        while ((r = next()) != null)   // 循环处理所有的AnrRecord
            final long startTime = SystemClock.uptimeMillis();
            // If there are many ANR at the same time, the latency may be larger. If the latency
            // is too large, the stack trace might not be meaningful.
            final long reportLatency = startTime - r.mTimestamp;
            final boolean onlyDumpSelf = reportLatency > EXPIRED_REPORT_TIME_MS;
            r.appNotResponding(onlyDumpSelf);  // 调用AnrRecord的appNotResponding
            final long endTime = SystemClock.uptimeMillis();
            Slog.d(TAG, "Completed ANR of " + r.mApp.processName + " in "
                    + (endTime - startTime) + "ms, latency " + reportLatency
                    + (onlyDumpSelf ? "ms (expired, only dump ANR app)" : "ms"));
        

        mRunning.set(false);
        synchronized (mAnrRecords) 
            // The race should be unlikely to happen. Just to make sure we don't miss.
            if (!mAnrRecords.isEmpty())  // 如果还有记录, 则执行下一次处理
                startAnrConsumerIfNeeded();
            
        
    

AnrRecord#appNotResponding直接调用了 ProcessRecord#appNotResponding

ProcessRecord#appNotResponding

具体记录ANR信息

void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
        String parentShortComponentName, WindowProcessController parentProcess,
        boolean aboveSystem, String annotation, boolean onlyDumpSelf) 
    ArrayList<Integer> firstPids = new ArrayList<>(5);
    SparseArray<Boolean> lastPids = new SparseArray<>(20);

    mWindowProcessController.appEarlyNotResponding(annotation, () -> kill("anr",
              ApplicationExitInfo.REASON_ANR, true));

    long anrTime = SystemClock.uptimeMillis();
    if (isMonitorCpuUsage()) 
        mService.updateCpuStatsNow();
    

    final boolean isSilentAnr;
    synchronized (mService)  // 一些特殊情况,直接返回
        // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
        if (mService.mAtmInternal.isShuttingDown()) 
            Slog.i(TAG, "During shutdown skipping ANR: " + this + " " + annotation);
            return;
         else if (isNotResponding()) 
            Slog.i(TAG, "Skipping duplicate ANR: " + this + " " + annotation);
            return;
         else if (isCrashing()) 
            Slog.i(TAG, "Crashing app skipping ANR: " + this + " " + annotation);
            return;
         else if (killedByAm) 
            Slog.i(TAG, "App already killed by AM skipping ANR: " + this + " " + annotation);
            return;
         else if (killed) 
            Slog.i(TAG, "Skipping died app ANR: " + this + " " + annotation);
            return;
        

        // In case we come through here for the same app before completing
        // this one, mark as anring now so we will bail out.
        setNotResponding(true);

        // Log the ANR to the event log.  将ANR写入Event log
        EventLog.writeEvent(EventLogTags.AM_ANR, userId, pid, processName, info.flags,
                annotation);

        // Dump thread traces as quickly as we can, starting with "interesting" processes.
        firstPids.add(pid);

        // Don't dump other PIDs if it's a background ANR or is requested to only dump self.
        isSilentAnr = isSilentAnr();
        if (!isSilentAnr && !onlyDumpSelf) 
            int parentPid = pid;
            if (parentProcess != null && parentProcess.getPid() > 0) 
                parentPid = parentProcess.getPid();
            
            if (parentPid != pid) firstPids.add(parentPid);

            if (MY_PID != pid && MY_PID != parentPid) firstPids.add(MY_PID);

            for (int i = getLruProcessList().size() - 1; i >= 0; i--) 
                ProcessRecord r = getLruProcessList().get(i);
                if (r != null && r.thread != null) 
                    int myPid = r.pid;
                    if (myPid > 0 && myPid != pid && myPid != parentPid && myPid != MY_PID) 
                        if (r.isPersistent()) 
                            firstPids.add(myPid);
                            if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);
                         else if (r.treatLikeActivity) 
                            firstPids.add(myPid);
                            if (DEBUG_ANR) Slog.i(TAG, "Adding likely IME: " + r);
                         else 
                            lastPids.put(myPid, Boolean.TRUE);
                            if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r);
                        
                    
                
            
        
    

    // Log the ANR to the main log.
    StringBuilder info = new StringBuilder();
    info.setLength(0);
    info.append("ANR in ").append(processName);
    if (activityShortComponentName != null) 
        info.append(" (").append(activityShortComponentName).append(")");
    
    info.append("\\n");
    info.append("PID: ").append(pid).append("\\n");
    if (annotation != null) 
        info.append("Reason: ").append(annotation).append("\\n");
    
    if (parentShortComponentName != null
            && parentShortComponentName.equals(activityShortComponentName)) 
        info.append("Parent: ").append(parentShortComponentName).append("\\n");
    

    StringBuilder report = new StringBuilder();
    report.append(MemoryPressureUtil.currentPsiState());
    ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
    ArrayList<Integer> nativePids = null;

    // don't dump native PIDs for background ANRs unless it is the process of interest
    String[] nativeProc = null;
    if (isSilentAnr || onlyDumpSelf) 
        for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) 
            if (NATIVE_STACKS_OF_INTEREST[i].equals(processName)) 
                nativeProc = new String[]  processName ;
                break;
            
        
        int[] pid = nativeProc == null ? null : Process.getPidsForCommands(nativeProc);
        if(pid != null)
            nativePids = new ArrayList<>(pid.length);
            for (int i : pid) 
                nativePids.add(i);
            
        
     else 
        nativePids = Watchdog.getInstance().getInterestingNativePids();
    

    // For background ANRs, don't pass the ProcessCpuTracker to
    // avoid spending 1/2 second collecting stats to rank lastPids.
    StringWriter tracesFileException = new StringWriter();
    // To hold the start and end offset to the ANR trace file respectively.
    final long[] offsets = new long[2];
    File tracesFile = ActivityManagerService.dumpStackTraces(firstPids,
            isSilentAnr ? null : processCpuTracker, isSilentAnr ? null : lastPids,
            nativePids, tracesFileException, offsets);

    if (isMonitorCpuUsage()) 
        mService.updateCpuStatsNow();
        synchronized (mService.mProcessCpuTracker) 
            report.append(mService.mProcessCpuTracker.printCurrentState(anrTime));
        
        info.append(processCpuTracker.printCurrentLoad());
        info.append(report);
    
    report.append(tracesFileException.getBuffer());

    info.append(processCpuTracker.printCurrentState(anrTime));

    Slog.e(TAG, info.toString());
    if (tracesFile == null) 
        // There is no trace file, so dump (only) the alleged culprit's threads to the log
        Process.sendSignal(pid, Process.SIGNAL_QUIT);
     else if (offsets[1] > 0) 
        // We've dumped into the trace file successfully
        mService.mProcessList.mAppExitInfoTracker.scheduleLogAnrTrace(
                pid, uid, getPackageList(), tracesFile, offsets[0], offsets[1]);
    

    FrameworkStatsLog.write(FrameworkStatsLog.ANR_OCCURRED, uid, processName,
            activityShortComponentName == null ? "unknown": activityShortComponentName,
            annotation,
            (this.info != null) ? (this.info.isInstantApp()
                    ? FrameworkStatsLog.ANROCCURRED__IS_INSTANT_APP__TRUE
                    : FrameworkStatsLog.ANROCCURRED__IS_INSTANT_APP__FALSE)
                    : FrameworkStatsLog.ANROCCURRED__IS_INSTANT_APP__UNAVAILABLE,
            isInterestingToUserLocked()
                    ? FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND
                    : FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND,
            getProcessClassEnum(),
            (this.info != null) ? this.info.packageName : "");
    final ProcessRecord parentPr = parentProcess != null
            ? (ProcessRecord) parentProcess.mOwner : null;
    mService.addErrorToDropBox("anr", this, processName, activityShortComponentName,
            parentShortComponentName, parentPr, annotation, report.toString(), tracesFile,
            null);

    if (mWindowProcessController.appNotResponding(info.toString(), () -> kill("anr",
            ApplicationExitInfo.REASON_ANR, true),
            () -> 
                synchronized (mService) 
                    mService.mServices.scheduleServiceTimeoutLocked(this);
                
            )) 
        return;
    

    synchronized (mService) 
        // mBatteryStatsService can be null if the AMS is constructed with injector only. This
        // will only happen in tests.
        if (mService.mBatteryStatsService != null) 
            mService.mBatteryStatsService.noteProcessAnr(processName, uid);
        

        if (isSilentAnr() && !isDebugging()) 
            kill("bg anr", ApplicationExitInfo.REASON_ANR, true);
            return;
        

        // Set the app's notResponding state, and look up the errorReportReceiver
        makeAppNotRespondingLocked(activityShortComponentName,
                annotation != null ? "ANR " + annotation : "ANR", info.toString());

        // mUiHandler can be null if the AMS is constructed with injector only. This will only
        // happen in tests.
        if (mService.mUiHandler != null)   // 显示ANR 对话框
            // Bring up the infamous App Not Responding dialog
            Message msg = Message.obtain();
            msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
            msg.obj = new AppNotRespondingDialog.Data(this, aInfo, aboveSystem);

            mService.mUiHandler.sendMessage(msg);
        
    

AMS处理SHOW_NOT_RESPONDING_UI_MSG

final class UiHandler extends Handler 
    public UiHandler() 
        super(com.android.server.UiThread.get().getLooper(), null, true);
    

    @Override
    public void handleMessage(Message msg) 
        switch (msg.what) 
            case SHOW_ERROR_UI_MSG: 
                mAppErrors.handleShowAppErrorUi(msg);
                ensureBootCompleted();
             break;
            case SHOW_NOT_RESPONDING_UI_MSG:   // 处理ANR
                mAppErrors.handleShowAnrUi(msg);
                ensureBootCompleted();
             break;
      ...

AppErrors#handleShowAnrUi

显示ANR 对话框

/// @frameworks/base/services/core/java/com/android/server/am/AppErrors.java
void handleShowAnrUi(Message msg) 
    List<VersionedPackage> packageList = null;
    synchronized (mService) 
        AppNotRespondingDialog.Data data = (AppNotRespondingDialog.Data) msg.obj;
        final ProcessRecord proc = data.proc;
        if (proc == null) 
            Slog.e(TAG, "handleShowAnrUi: proc is null");
            return;
        
        if (!proc.isPersistent()) 
            packageList = proc.getPackageListWithVersionCode();
        
        if (proc.getDialogController().hasAnrDialogs()) 
            Slog.e(TAG, "App already has anr dialog: " + proc);
            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
                    AppNotRespondingDialog.ALREADY_SHOWING);
            return;
        

        boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
                Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
        if (mService.mAtmInternal.canShowErrorDialogs() || showBackground) 
            proc.getDialogController().showAnrDialogs(data);
         else 
            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
                    AppNotRespondingDialog.CANT_SHOW);
            // Just kill the app if there is no dialog to be shown.
            mService.killAppAtUsersRequest(proc);
        
    
    // Notify PackageWatchdog without the lock held
    if (packageList != null) 
        mPackageWatchdog.onPackageFailure(packageList,
                PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
    

ProcessRecord$ErrorDialogController#showAnrDialogs

void showAnrDialogs(AppNotRespondingDialog.Data data) 
    List<Context> contexts = getDisplayContexts(isSilentAnr() /* lastUsedOnly */);
    mAnrDialogs = new ArrayList<>();
    for (int i = contexts.size() - 1; i >= 0; i--) 
        final Context c = contexts.get(i);
        mAnrDialogs.add(new AppNotRespondingDialog(mService, c, data));
    
    mService.mUiHandler.post(() -> 
        List<AppNotRespondingDialog> dialogs;
        synchronized (mService) 
            dialogs = mAnrDialogs;
        
        if (dialogs != null) 
            forAllDialogs(dialogs, Dialog::show);  // 显示dialog
        
    );

以上是关于Android R Input 之ANR的产生与显示流程的主要内容,如果未能解决你的问题,请参考以下文章

ANR系列之二:Input类型ANR产生原理讲解

Android R input 之 InputManagerService 的建立

Android R input 之 InputManagerService 的建立

源码剖析Android ANR产生机制

Android ANR的产生与分析

Android探究之ANR