Service -- 超时处理机制


# 核心源码

关键类 路径
ActiveServices.java frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
ActivityManagerService.java frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
AppErrors.java frameworks/base/services/core/java/com/android/server/am/AppErrors.java
ProcessRecord.java frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java


一、Application Not Responding

1.1 何为 ANR

官方定义:(https://developer.android.google.cn/topic/performance/vitals/anr?hl=zh_cn)

When the UI thread of an Android app is blocked for too long, an “Application Not Responding” (ANR) error is triggered. If the app is in the foreground, the system displays a dialog to the user, as shown in figure 1. The ANR dialog gives the user the opportunity to force quit the app.

当 Android 应用程序的 UI 线程被阻止太长时,会触发 “应用程序无响应” (ANR)错误。 如果应用程序位于前台,系统会向用户显示一个对话框,ANR 对话框使用户有机会强制退出应用程序,如下图。

ANR Simple Dialog

ANR(Application Not Responding):应用程序无响应,简单一个定义,却涵盖了很多 Android 系统的设计思想。

(1)首先,ANR 属于应用程序的范畴

这不同于 SNR(System Not Respoding),SNR 反映的问题是 “ 系统进程 “(system_server)失去了响应能力,而 ANR 明确将问题圈定在 “ 应用程序 “SNR 由 Watchdog 机制保证,ANR 由消息处理机制保证

Android 在系统层实现了一套精密的机制来发现 ANR,核心原理是 消息调度超时处理

(2)ANR 机制主体实现在 系统层

所有与 ANR 相关的消息,都会经过系统进程(system_server)调度,然后派发到应用进程完成对消息的实际处理,同时,系统进程设计了不同的超时限制来跟踪消息的处理。一旦应用程序处理消息不当,超时限制就起作用了,它收集一些系统状态,例如:CPU/IO 使用情况、进程函数调用栈,并且报告用户有进程 无响应了(ANR 对话框)

(3)ANR 问题本质上是一个 性能问题

ANR 机制实际上对应用程序主线程的限制,要求主线程在限定的时间内处理完一些最常见的操作(启动服务、处理广播、处理输入),如果处理超时,则认为主线程已经失去了响应其他操作的能力。主线程中的 耗时操作,例如:密集 CPU 运算、大量 IO、复杂界面布局等,都会降低应用程序的响应能力。

部分 ANR 问题是很难分析的,有时候由于系统底层的一些影响,导致消息调度失败,出现问题的场景又难以复现。这类 ANR 问题往往需要花费大量的时间去了解系统的一些行为,超出了 ANR 机制本身的范畴。

1.2 ANR 机制

分析一些初级的 ANR 问题,只需要简单理解最终输出的日志即可,但对于一些由系统问题(例如:CPU 负载过高、进程卡死)引发的 ANR,就需要对整个 ANR 机制有所了解,才能定位出问题的原因。所以,我们不仅需要知道怎么去面对并处理一个 ANR 问题,同时也需要了解 ANR 的源码机制,这样才能更好的处理我们平常遇到的稳定性问题。

ANR 机制主要分为两部分:

      ✎  ANR 的监测:Android 对于不同的 ANR 类型(Broadcast,Service,InputEvent)都有一套监测机制。

      ✎  ANR 的报告:在监测到 ANR 以后,需要显示 ANR 对话框并输出日志(查找问题原因)。

1.3 ANR 触发

前面我们说过,出现 ANR 之后一个直观现象就是系统会展示出一个 ANR 对话框。在 Android 系统中,应用都会被 ActivityManagerServiceWindowManagerService 两个系统服务监控着。

系统会在发生如下三种情况时弹出 ANR 提示框:

      ✎  KeyDispatchTimeout ( 5 seconds ) :按键或触摸事件在特定时间内无响应。

      ✎  BroadcastTimeout ( 10 seconds ):BroadcastReceiver 在特定时间内无法处理完成。

      ✎  ServiceTimeout ( 20 seconds ) :Service 在特定的时间内无法处理完成。(本章节需要讨论的内容)


二、Service 超时监测机制

Service 运行在应用程序的主线程,如果 Service 的执行时间超过 20 秒,则会引发 ANR。

当发生 Service ANR 时,一般可以先排查一下在 Service 的生命周期函数中有没有做 耗时的操作,例如复杂的运算、IO 操作等。如果应用程序的代码逻辑查不出问题,就需要深入检查当前系统的状态:CPU 的使用情况、系统服务的状态等,判断当时发生 ANR 进程是否受到 系统运行异常 的影响。

那么,系统是如何检测 Service 超时的呢?Android 系统是通过设置 “定时消息” 来实现对 Service 的超时检测。定时消息是由 AMS 的消息队列处理的,AMS 有 Service 运行的上下文信息,所以在 AMS 中设置一套超时检测机制也是情理之中。

Service ANR 机制相对而言最为简单,主体实现在 ActiveServices 中。我们在 “ Service 的启动流程 “ 一文中分析过,Service 进程 attach 到 system_server 进程后会调用 realStartServiceLocked() 方法。

2.1 ActiveServices.realStartServiceLocked()

// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

public final class ActiveServices {

    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        ... ...

        bumpServiceExecutingLocked(r, execInFg, "create");    // 发送 delay 消息(SERVICE_TIMEOUT_MSG)
        ... ...

        boolean created = false;
        try {
            ... ...

            // 最终会执行 Service 的 onCreate() 方法
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                    app.getReportedProcState());
            ... ...

        } catch (DeadObjectException e) {
            Slog.w(TAG, "Application dead when creating service " + r);
            mAm.appDiedLocked(app);
            throw e;
        } finally {
            if (!created) {
                // Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                // 如果没有发生 ANR,则执行 serviceDoneExecutingLocked() 方法
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);

                // Cleanup.
                if (newService) {
                    app.services.remove(r);
                    r.setProcess(null);
                }

                // Retry.
                if (!inDestroying) {
                    scheduleServiceRestartLocked(r, false);
                }
            }
        }
        ... ...

    }
}

2.2 ActiveServices.serviceDoneExecutingLocked()

前台进程中执行 Service,超时时间是 SERVICE_TIMEOUT(20 秒)
    // How long we wait for a service to finish executing.
    static final int SERVICE_TIMEOUT = 20*1000;
后台进程中执行 Service,超时时间是 SERVICE_BACKGROUND_TIMEOUT(200 秒)
    // How long we wait for a service to finish executing.
    static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;

当 Service 的生命周期结束时(不会 ANR),会调用 serviceDoneExecutingLocked() 方法,之前抛出的 SERVICE_TIMEOUT_MSG 消息在这个方法中会被清除。

// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

public final class ActiveServices {

    private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
              boolean finishing) {    
        ... ...

        if (r.executeNesting <= 0) {
            if (r.app != null) {    
                ... ...

                // 当前服务所在进程中没有正在执行的service,清除 SERVICE_TIMEOUT_MSG 消息
                if (r.app.executingServices.size() == 0) {
                    if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
                               "No more executingServices of " + r.shortInstanceName);
                    mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);        
                } else if (r.executeFg) {
                    ... ...

                }
                ... ...

            }
        }
    }

}

2.3 ActiveServices.bumpServiceExecutingLocked()

// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

public final class ActiveServices {

    private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
        ... ...

        long now = SystemClock.uptimeMillis();
        if (r.executeNesting == 0) {
            r.executeFg = fg;
            ServiceState stracker = r.getTracker();
            if (stracker != null) {
                stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
            }
            if (r.app != null) {
                r.app.executingServices.add(r);
                r.app.execServicesFg |= fg;
                if (timeoutNeeded && r.app.executingServices.size() == 1) {
                    // 超时了,则调用 scheduleServiceTimeoutLocked() 方法
                    scheduleServiceTimeoutLocked(r.app);
                }
            }
        } else if (r.app != null && fg && !r.app.execServicesFg) {
            r.app.execServicesFg = true;
            if (timeoutNeeded) {
                scheduleServiceTimeoutLocked(r.app);
            }
        }
        ... ...
    }

}

2.4 ActiveServices.scheduleServiceTimeoutLocked()

// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

public final class ActiveServices {

    void scheduleServiceTimeoutLocked(ProcessRecord proc) {
        if (proc.executingServices.size() == 0 || proc.thread == null) {
            return;
        }
        Message msg = mAm.mHandler.obtainMessage(
                ActivityManagerService.SERVICE_TIMEOUT_MSG);
        msg.obj = proc;
        // 当超时后仍没有 remove 该 SERVICE_TIMEOUT_MSG 消息,则通过 AMS.MainHandler 抛出一个定时消息
        mAm.mHandler.sendMessageDelayed(msg,
                proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
    }

}

上述方法通过 AMS.MainHandler 抛出一个定时消息 SERVICE_TIMEOUT_MSG

2.5 MainHandler.handleMessage()

system_server 进程中有一个 Handler 线程:ActivityManager。如果在超时时间内,SERVICE_TIMEOUT_MSG 没有被清除,便会向该 Handler 线程发送一条 SERVICE_TIMEOUT_MSG 信息。

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

    final ActiveServices mServices;

    final class MainHandler extends Handler {
        public MainHandler(Looper looper) {
            super(looper, null, true);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                ... ...

                case SERVICE_TIMEOUT_MSG: {
                    mServices.serviceTimeout((ProcessRecord)msg.obj);
                } break;
                ... ...

            }
        }
    }

}

2.6 ActiveServices.serviceTimeout()

// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

public final class ActiveServices {

    void serviceTimeout(ProcessRecord proc) {
        String anrMessage = null;
        synchronized(mAm) {
            ... ...

            long nextTime = 0;

            // 寻找运行超时的 Service
            for (int i = proc.executingServices.size() - 1; i >= 0; i--) {
                ServiceRecord sr = proc.executingServices.valueAt(i);
                if (sr.executingStart < maxTime) {
                    timeout = sr;
                    break;
                }
                if (sr.executingStart > nextTime) {
                    nextTime = sr.executingStart;
                }
            }

            // 判断执行 Service 超时的进程是否在最近运行进程列表,如果不在,则忽略这个 ANR
            if (timeout != null && mAm.mProcessList.mLruProcesses.contains(proc)) {
                Slog.w(TAG, "Timeout executing service: " + timeout);
                StringWriter sw = new StringWriter();
                PrintWriter pw = new FastPrintWriter(sw, false, 1024);
                pw.println(timeout);
                timeout.dump(pw, "    ");
                pw.close();
                mLastAnrDump = sw.toString();
                mAm.mHandler.removeCallbacks(mLastAnrDumpClearer);
                mAm.mHandler.postDelayed(mLastAnrDumpClearer, LAST_ANR_LIFETIME_DURATION_MSECS);
                anrMessage = "executing service " + timeout.shortInstanceName;
            } else { 
                Message msg = mAm.mHandler.obtainMessage(ActivityManagerService.SERVICE_TIMEOUT_MSG);
                msg.obj = proc;
                mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg
                        ? (nextTime+SERVICE_TIMEOUT) : (nextTime + SERVICE_BACKGROUND_TIMEOUT));
            }
        }

        if (anrMessage != null) {
            // 当存在 timeout 的 service,则执行 appNotResponding() 方法
            proc.appNotResponding(null, null, null, null, false, anrMessage);
        }
    }

}

上述方法会找到当前进程已经超时的 Service,经过一些判定后,如果决定要报告 ANR,最终会调用 appNotResponding() 方法。

走到这一步,ANR 机制已经完成了监测报告任务,剩下的任务就是 ANR 结果的输出,我们称之为 ANR 的报告机制。

ANR 的报告机制是通过 ProcessRecord.appNotResponding() 完成的,BroadcastInputEvent 类型的 ANR 最终也都会调用这个方法。


三、ANR 信息收集过程

接下来我们看看 Android ANR 的信息收集过程!

3.1 ProcessRecord.appNotResponding()

// frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java

/**
 * Full information about a particular process that
 * is currently running.
 */
class ProcessRecord implements WindowProcessListener {

    public static final int MY_PID = myPid();

    void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
            String parentShortComponentName, WindowProcessController parentProcess,
            boolean aboveSystem, String annotation) {
        ... ...

        long anrTime = SystemClock.uptimeMillis();
        if (isMonitorCpuUsage()) {
            mService.updateCpuStatsNow();    // 更新 cpu 统计信息
        }

        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);

            // 记录 ANR 到 EventLog
            EventLog.writeEvent(EventLogTags.AM_ANR, userId, pid, processName, info.flags, annotation);

            // 将当前进程添加到 firstPids
            firstPids.add(pid);

            // Don't dump other PIDs if it's a background ANR
            if (!isSilentAnr()) {
                int parentPid = pid;
                if (parentProcess != null && parentProcess.getPid() > 0) {
                    parentPid = parentProcess.getPid();
                }
                if (parentPid != pid) firstPids.add(parentPid);

                // 将 system_server 进程添加到 firstPids
                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()) {
                                // 将 persistent 进程添加到 firstPids
                                firstPids.add(myPid);
                                if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);
                            } else if (r.treatLikeActivity) {
                                firstPids.add(myPid);
                            } else {
                                // 其他进程添加到 lastPids
                                lastPids.put(myPid, Boolean.TRUE);
                                if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r);
                            }
                        }
                    }
                }
            }
        }

        StringBuilder info = new StringBuilder();    // 记录 ANR 输出到 main log
        info.setLength(0);
        info.append("ANR in ").append(app.processName);
        if (activityShortComponentName != null) {
            info.append(" (").append(activityShortComponentName).append(")");
        }
        info.append("\n");
        info.append("PID: ").append(app.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");
        }

        // 创建 CPU tracker 对象 
        ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
        ... ...

        // 输出 traces 文件,见 3.2
        File tracesFile = ActivityManagerService.dumpStackTraces(firstPids,
                (isSilentAnr()) ? null : processCpuTracker, (isSilentAnr()) ? null : lastPids,
                nativePids);

        String cpuInfo = null;
        if (isMonitorCpuUsage()) {
            mService.updateCpuStatsNow();
            synchronized (mService.mProcessCpuTracker) {
                cpuInfo = mService.mProcessCpuTracker.printCurrentState(anrTime);
            }
            info.append(processCpuTracker.printCurrentLoad());    // 记录当前 CPU 负载情况
            info.append(cpuInfo);
        }

        // 记录从 anr 时间开始的 CPU 使用情况
        info.append(processCpuTracker.printCurrentState(anrTime));

        // 输出当前 ANR 的 reason,以及 CPU 使用率、负载信息
        Slog.e(TAG, info.toString());
        if (tracesFile == null) {
            Process.sendSignal(pid, Process.SIGNAL_QUIT);
        }
        ... ...

        // 将 traces 文件和 CPU 使用率信息保存到 dropbox,即 data/system/dropbox 目录
        mService.addErrorToDropBox("anr", this, processName, activityShortComponentName,
                parentShortComponentName, parentPr, annotation, cpuInfo, tracesFile, null);
        ... ...

        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);
            }

            // 后台 ANR 的情况, 直接杀掉
            if (isSilentAnr() && !isDebugging()) {
                kill("bg anr", true);
                return;
            }

            // 设置 app 的 ANR 状态,并查询错误报告 receiver
            makeAppNotRespondingLocked(activityShortComponentName,
                    annotation != null ? "ANR " + annotation : "ANR", info.toString());

            if (mService.mUiHandler != null) {
                // Bring up the infamous App Not Responding dialog,弹出 ANR 对话框
                Message msg = Message.obtain();
                msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
                msg.obj = new AppNotRespondingDialog.Data(this, aInfo, aboveSystem);

                // 向 ui 线程发送,内容为 SHOW_NOT_RESPONDING_MSG 的消息
                mService.mUiHandler.sendMessage(msg);
            }
        }
    }

}

当发生 ANR 时, 会按顺序依次执行:

       ✒ 1、输出 ANR Reason 信息到 EventLog,也就是说 ANR 触发的时间点最接近的就是 EventLog 中输出的 am_anr 信息;

       ✒ 2、收集并输出重要进程列表中的各个线程的 traces 信息,该方法较耗时;

       ✒ 3、输出当前各个进程的 CPU 使用情况 以及 CPU 负载情况

       ✒ 4、将 traces 文件CPU 使用情况信息 保存到 dropbox,即 data/system/dropbox 目录;

       ✒ 5、根据进程类型,来决定直接后台杀掉,还是弹框告知用户

ANR 输出重要进程的 traces 信息,这些进程包含:

       ✒ 1、firstPids 队列:第一个是 ANR 进程,第二个是 system_server,剩余是所有 persistent 进程;

       ✒ 2、Native 队列:是指 /system/bin/ 目录的 mediaserversdcard 以及 surfaceflinger 进程;

       ✒ 3、lastPids 队列: 是指 mLruProcesses 中的 不属于 firstPids 的所有进程。

3.2 ActivityManagerService.dumpStackTraces() - 01

继续看看 dump 出 trace 信息的流程:

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

    public static final String ANR_TRACE_DIR = "/data/anr";

    public static File dumpStackTraces(ArrayList<Integer> firstPids,
           ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids,
           ArrayList<Integer> nativePids) {

        ArrayList<Integer> extraPids = null;
        ... ...

        // 默认为 data/anr/traces.txt
        final File tracesDir = new File(ANR_TRACE_DIR);
        maybePruneOldTraces(tracesDir);

        File tracesFile = createAnrDumpFile(tracesDir);
        if (tracesFile == null) {
            return null;
        }

        // 输出 trace 内容
        dumpStackTraces(tracesFile.getAbsolutePath(), firstPids, nativePids, extraPids);
        return tracesFile;
    }

}

3.3 ActivityManagerService.dumpStackTraces() - 02

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

    public static void dumpStackTraces(String tracesFile, ArrayList<Integer> firstPids,
           ArrayList<Integer> nativePids, ArrayList<Integer> extraPids) {

        Slog.i(TAG, "Dumping to " + tracesFile);

        // We must complete all stack dumps within 20 seconds.
        long remainingTime = 20 * 1000;


        // 首先,获取 firstPids 进程的 stacks
        if (firstPids != null) {
            int num = firstPids.size();
            for (int i = 0; i < num; i++) {
                Slog.i(TAG, "Collecting stacks for pid " + firstPids.get(i));
                final long timeTaken = dumpJavaTracesTombstoned(firstPids.get(i), tracesFile, remainingTime);

                remainingTime -= timeTaken;
                if (remainingTime <= 0) {
                    Slog.e(TAG, "Aborting stack trace dump (current firstPid=" + firstPids.get(i) +
                           "); deadline exceeded.");
                    return;
                }

                if (DEBUG_ANR) {
                    Slog.d(TAG, "Done with pid " + firstPids.get(i) + " in " + timeTaken + "ms");
                }
            }
        }

        // 下一步,获取 native 进程的 stacks
        if (nativePids != null) {
            for (int pid : nativePids) {
                Slog.i(TAG, "Collecting stacks for native pid " + pid);
                final long nativeDumpTimeoutMs = Math.min(NATIVE_DUMP_TIMEOUT_MS, remainingTime);

                final long start = SystemClock.elapsedRealtime();
                Debug.dumpNativeBacktraceToFileTimeout(
                        pid, tracesFile, (int) (nativeDumpTimeoutMs / 1000));
                final long timeTaken = SystemClock.elapsedRealtime() - start;

                remainingTime -= timeTaken;
                if (remainingTime <= 0) {
                    Slog.e(TAG, "Aborting stack trace dump (current native pid=" + pid +
                        "); deadline exceeded.");
                    return;
                }

                if (DEBUG_ANR) {
                    Slog.d(TAG, "Done with native pid " + pid + " in " + timeTaken + "ms");
                }
            }
        }

        // Lastly, dump stacks for all extra PIDs from the CPU tracker.
        if (extraPids != null) {
            for (int pid : extraPids) {
                Slog.i(TAG, "Collecting stacks for extra pid " + pid);

                final long timeTaken = dumpJavaTracesTombstoned(pid, tracesFile, remainingTime);

                remainingTime -= timeTaken;
                if (remainingTime <= 0) {
                    Slog.e(TAG, "Aborting stack trace dump (current extra pid=" + pid +
                            "); deadline exceeded.");
                    return;
                }

                if (DEBUG_ANR) {
                    Slog.d(TAG, "Done with extra pid " + pid + " in " + timeTaken + "ms");
                }
            }
        }
        Slog.i(TAG, "Done dumping");
    }

}

3.4 小结

触发 ANR 时系统会输出关键信息:

       ✒ 1、将 am_anr 信息,输出到 EventLog

       ✒ 2、获取重要进程 trace 信息,保存到 /data/anr/traces.txt

       ✒ 3、ANR reason 以及 CPU 使用情况信息,输出到 main log

       ✒ 4、再将 CPU使用情况 和进程 trace 文件 信息,再保存到 /data/system/dropbox


四、总结

当 Service 出现 ANR 时,最终调用到 AMS.appNotResponding() 方法。

       ✒ 1、对于前台服务,则超时为 SERVICE_TIMEOUT = 20s

       ✒ 2、对于后台服务,则超时为 SERVICE_BACKGROUND_TIMEOUT = 200s

       ✒ 3、Service 超时检测机制:超过一定时间没有执行完相应操作 来触发 延时消息,则会触发 ANR