当前位置:   article > 正文

ANR系列之一:ANR显示和日志生成原理讲解_wrote stack traces to tombstoned

wrote stack traces to tombstoned

前言:   

ANR系列介绍

ANR系列一共打算分为7篇文章,主要分为三块来讲:

 第一块,讲解ANR发生后,是如何显示的,以及对应的日志文件如何生成的:

ANR系列之一:ANR显示和日志生成原理讲解_失落夏天的博客-CSDN博客

第二块,讲四种类型的ANR是如何产生的:

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

ANR系列之三:broadcast类型ANR产生原理讲解

ANR系列之四:ContentProvider类型ANR产生原理讲解

ANR系列之五:Service类型ANR原理讲解

第三块,讲如何ANR问题如何进行分析,以及如何建立有效的机制来检测上报ANR类型问题。(未完成)

ANR系列之六:ANR文件和日志如何分析

ANR系列之七:如何建立有效的机制来监控分析ANR问题

本篇主要内容

本篇是该系列的第一篇,主要讲解以下几点内容:

1.ANR的一些基本概念;

2.ANR弹框是如何显示出来的;

3.ANR的logcat日志以及ANR文件是如何产生的;

4.发生ANR时,会有哪些日志,以及如何解读;

5.一些扩展性的知识点。

一.ANR基本概念

ANR,指的是安卓中一种长时间应用无响应的一种场景。发生ANR时,会弹出下面这样的提示框,用户点击按钮可以强行杀死应用。

简单来说,ANR就是应用的主线程长时间处于阻塞状态,导致其任务无法正常执行完成的一种场景。所以,主线程阻塞就一定会造成ANR吗?当然不会,因为还有另外一个必要条件:待执行的任务。

二.ANR流程概览

本章主要讲解ANR发生后的完整流程,当然更具体的内容,比如ANR弹框是怎么显示的,以及日志是如何记录的,我们放到了后面章节来讲。

ANR流程概览

首先,我们通过一张流程图来了解整个ANR的流程:

无论是哪种类型的ANR,哪怕是native层的ANR,最终也会通知到AnrHelper类的appNotResponding方法。所以,我们从这个方法开始了解整个ANR的流程。我们用来区分ANR的四种不同类型,其实也就是appNotResponding这个方法中的annotation不同而已,而ANR本身是不去分类型的。

1.appNotResponding方法中,主要是生成AnrRecord对象,加入到mAnrRecords集合中。然后调用startAnrConsumerIfNeeded方法。

2.startAnrConsumerIfNeeded方法主要是通过cas进行判断,避免两个ANR线程同时执行。如果没有冲突的话,则开启AnrConsumerThread线程,对mAnrRecords中的对象进行消费。

3.AnrConsumerThread的run方法中,就是从mAnrRecords中取出对象,这些对象第一条中添加的。通过AnrRecord自身的appNotResponding方法进行消费。

4.appNotResponding方法就是整个ANR流程的核心执行逻辑了。总结一下,其实主要分为两大块:

第一,生成ANR的相关log以及日志并打印或保存。这个我们第四章来讲

第二,弹出应用无响应的框。这个我们第三章来讲。

三.ANR的logcat日志以及ANR文件是如何产生的

两种ANR信息介绍

logcat的日志和ANR文件的生成的核心逻辑仍然在appNotResponding方法中。

发生ANR的时候,会有3种形式的记录,分别记录不同的信息。

1.logcat中记录的日志。这里主要起到的是打印的作用,打印一些ANR的信息,以及会把一些CPU状态打印出来

2.data/anr/目录下生成对应的ANR日志文件。这里面主要记录的是dump进程的信息。

3.dropbox中记录的信息。

3.1 收集进程信息

ANR发生的原因,有时候并不是APP自身导致的,和其他进程也有关系。比如其他进程耗尽CPU资源,导致发生ANR的APP的任务无法正常执行。所以,发生ANR后,收集原因时,并不能单纯的只收集发生ANR的那个APP进程。

appNotResponding方法中,有两个集合,分别是firstPids和lastPids,分别收集

  1. ArrayList<Integer> firstPids = new ArrayList<>(5);
  2. SparseArray<Boolean> lastPids = new SparseArray<>(20);

firstPids中会加入以下类型的进程ID:

1.发生ANR的进程PID;

2.发生ANR的进程的父进程PID;

3.系统进程的PID;

4.最近使用到并且还存活的进程PID;

5.存在被处理过的Activity的进程PID,这个说实在的,我没太理解,不过不影响主流程,就先忽略。

3.2 logcat中打印ANR信息

发生ANR的时候,会有两种形式的记录:

接下来,appNotResponding方法中会收集一些必要的ANR信息,打印显示在logcat中,主要代码如下:

  1. // Log the ANR to the main log.
  2. StringBuilder info = new StringBuilder();
  3. info.setLength(0);
  4. info.append("ANR in ").append(mApp.processName);//打印发生ANR的进程名
  5. if (activityShortComponentName != null) {
  6. info.append(" (").append(activityShortComponentName).append(")");
  7. }
  8. info.append("\n");
  9. info.append("PID: ").append(pid).append("\n");//打印发生ANR的进程PID
  10. if (annotation != null) {
  11. info.append("Reason: ").append(annotation).append("\n");//打印ANR类型和原因
  12. }
  13. if (parentShortComponentName != null
  14. && parentShortComponentName.equals(activityShortComponentName)) {
  15. info.append("Parent: ").append(parentShortComponentName).append("\n");
  16. }
  17. if (errorId != null) {
  18. info.append("ErrorId: ").append(errorId.toString()).append("\n");
  19. }
  20. info.append("Frozen: ").append(mApp.mOptRecord.isFrozen()).append("\n");
  21. ...
  22. Slog.e(TAG, info.toString());

具体记录的内容和如何分析,我们下面再讲,这里只要知道,logcat中的信息是这里记录的就好。这些必要的信息都存储在info中,最终会通过logcat打印出来。

3.3 记录ANR文件流程

dumpStackTraces入参讲解

这个主要是通过appNotResponding中的ActivityManagerService.dumpStackTraces方法来实现的,我们先看下这个方法的参数:

  1. static File dumpStackTraces(ArrayList<Integer> firstPids,
  2. ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids,
  3. ArrayList<Integer> nativePids, StringWriter logExceptionCreatingFile,
  4. long[] firstPidOffsets, String subject) {
 tracesFile = createAnrDumpFile(tracesDir);

1.firstPids:第一等级要收集的进程PID,firstPids集合3.1有介绍。

2.processCpuTracker:CPU分析记录对象,这个方法中会用到

3.lastPids:第二等级要收集的进程PID集合。

4.nativePids:要收集的native进程的PID集合。

5.tracesFileException:传递进去一个输出流对象,供方法内写入,最终这些信息会写入到dropbox中

6.offsets:用来记录采集的第一个非系统进程的日志文件的偏移量。两个参数,分别记录写入之前和写入之后的文件大小。

7.annotation:ANR类型和原因

三个要dump进程的集合

dumpStackTraces方法中,首先初始化processCpuTracker,然后休眠200毫秒,这200毫秒主要是让CPU去采集和分析CPU状态。然后遍历lastPids,获取其中CPU占用率最高的5个进程加入到extraPids集合中,等于说对lastPids集合进行了一遍处理。所以,我们现在有三个PID集合了:firstPids,nativePids和extraPids,这三个集合就是我们要dump进程的。

生成trace文件

生成trace文件,并且把ARN原因写入

  1. File tracesFile;
  2. try {
  3. tracesFile = createAnrDumpFile(tracesDir);
  4. } catch (IOException e) {
  5. Slog.w(TAG, "Exception creating ANR dump file:", e);
  6. if (logExceptionCreatingFile != null) {
  7. logExceptionCreatingFile.append("----- Exception creating ANR dump file -----\n");
  8. e.printStackTrace(new PrintWriter(logExceptionCreatingFile));
  9. }
  10. return null;
  11. }
  12. if (subject != null) {
  13. try (FileOutputStream fos = new FileOutputStream(tracesFile, true)) {
  14. String header = "Subject: " + subject + "\n";
  15. fos.write(header.getBytes(StandardCharsets.UTF_8));
  16. } catch (IOException e) {
  17. Slog.w(TAG, "Exception writing subject to ANR dump file:", e);
  18. }
  19. }

采集进程堆栈信息

最后通过重写的dumpStackTraces方法,分别回去采集firstPids,nativePids,extraPids集合中对应进程的堆栈状态。

这里系统会设置上限20秒的时间来允许对集合中的进程PID进程捕获,如果超过20秒,则认为捕获失败。

我们先看遍历firstPids集合的操作,简化的代码如下:

  1. for (int i = 0; i < num; i++) {
  2. final int pid = firstPids.get(i);
  3. ...
  4. Slog.i(TAG, "Collecting stacks for pid " + pid);
  5. final long timeTaken = dumpJavaTracesTombstoned(pid, tracesFile,
  6. remainingTime);
  7. remainingTime -= timeTaken;
  8. if (remainingTime <= 0) {
  9. Slog.e(TAG, "Aborting stack trace dump (current firstPid=" + pid
  10. + "); deadline exceeded.");
  11. return firstPidStart >= 0 ? new Pair<>(firstPidStart, firstPidEnd) : null;
  12. }
  13. if (firstPid) {
  14. firstPidEnd = tf.length();
  15. }
  16. if (DEBUG_ANR) {
  17. Slog.d(TAG, "Done with pid " + firstPids.get(i) + " in " + timeTaken + "ms");
  18. }
  19. }

dumpJavaTracesTombstoned中,会调用Debug类,最终会通知native层去获取对应PID的进程堆栈。现在常用的使用信号量监听ANR也是在此时发送的。

遍历nativePids集合的操作其实和第一步操作类似,只不过最终调用的就是dumpNativeBacktraceToFileTimeout方法了。

而最后遍历extraPids集合,操作和第一步是一样的了。

具体日志和代码的对应,我们第五章再讲。

四.ANR弹框是如何显示出来的

这一章其实是很早之前写的,比较简单,就直接复用之前的内容,不再改了。对于新手排查系统问题,是一个很好的参考。

4.1找到弹框对应类

想知道弹框是如何显示的,最简单的方式就是先造一个程序无响应的场景,然后打开uiautomatorviewer工具查看布局,这样我们就可以找到对应的XMl然后在源码中搜索,就能找到我们的目标类了。

首先我们看到的是下面这样一个场景,先基于android-29的源码全局文字:没有响应,关闭应用,等待,没有搜到,正常,这些文字应该是配置在xml中的。换个思路搜id,关闭应用对应的是aerr_close,全局搜果然搜到了,在AppNotRespondingDialog类中。对应的类名正好也符合:APP无响应。所以说我们的入口找到了。

另外我们看一下AppNotRespondingDialog的包名:com.android.server.am,说明是跑在Serve端的。

4.2.查找AppNotRespondingDialog引用

发现有是AppErrors的handleShowAnrUi方法调用的。我们先看整个调用流程:

1.InputManagerService的notifyANR方法

  1. // Native callback.
  2. private long notifyANR(IBinder token, String reason) {
  3. return mWindowManagerCallbacks.notifyANR(
  4. token, reason);
  5. }

好吧,调用触发点是naive。
2.InputManagerCallback的notifyANR方法

  1. @Override
  2. public long notifyANR(IBinder token, String reason) {
  3. AppWindowToken appWindowToken = null;
  4. WindowState windowState = null;
  5. boolean aboveSystem = false;
  6. synchronized (mService.mGlobalLock) {
  7. ...
  8. //存储日志的
  9. mService.saveANRStateLocked(appWindowToken, windowState, reason);
  10. }
  11. // All the calls below need to happen without the WM lock held since they call into AM.
  12. mService.mAtmInternal.saveANRState(reason);
  13. if (appWindowToken != null && appWindowToken.appToken != null) {
  14. ...
  15. } else if (windowState != null) {
  16. //通知弹出ANR的框
  17. long timeout = mService.mAmInternal.inputDispatchingTimedOut(
  18. windowState.mSession.mPid, aboveSystem, reason);
  19. if (timeout >= 0) {
  20. // The activity manager declined to abort dispatching.
  21. // Wait a bit longer and timeout again later.
  22. return timeout * 1000000L; // nanoseconds
  23. }
  24. }
  25. return 0; // abort dispatching
  26. }

3.ActivityManagerService.LocalService的inputDispatchingTimedOut方法

4.ActivityManagerService的inputDispatchingTimedOut方法

5.ProcessRecord的appNotResponding方法

  1. if (mService.mUiHandler != null) {
  2. // Bring up the infamous App Not Responding dialog
  3. Message msg = Message.obtain();
  4. msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
  5. msg.obj = new AppNotRespondingDialog.Data(this, aInfo, aboveSystem);
  6. mService.mUiHandler.sendMessage(msg);
  7. }

6.ProcessRecord的appNotResponding方法

  1. case SHOW_NOT_RESPONDING_UI_MSG: {
  2. mAppErrors.handleShowAnrUi(msg);
  3. ensureBootCompleted();
  4. } break;

7.ProcessRecord的appNotResponding方法

  1. void handleShowAnrUi(Message msg) {
  2. Dialog dialogToShow = null;
  3. List<VersionedPackage> packageList = null;
  4. synchronized (mService) {
  5. AppNotRespondingDialog.Data data = (AppNotRespondingDialog.Data) msg.obj;
  6. final ProcessRecord proc = data.proc;
  7. if (proc == null) {
  8. Slog.e(TAG, "handleShowAnrUi: proc is null");
  9. return;
  10. }
  11. ...
  12. if (mService.mAtmInternal.canShowErrorDialogs() || showBackground) {
  13. dialogToShow = new AppNotRespondingDialog(mService, mContext, data);
  14. proc.anrDialog = dialogToShow;
  15. } else {
  16. MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
  17. AppNotRespondingDialog.CANT_SHOW);
  18. // Just kill the app if there is no dialog to be shown.
  19. mService.killAppAtUsersRequest(proc, null);
  20. }
  21. }
  22. // If we've created a crash dialog, show it without the lock held
  23. if (dialogToShow != null) {
  24. dialogToShow.show();//显示程序无响应的框
  25. }
  26. ...
  27. }

总结一下,流程图如下:

五.发生ANR时,会有哪些日志,以及如何解读

上面有讲到,ANR发生时,会有三种信息来记录, 分别是logcat以及ANR的日志。其实还有一些logcat中的信息,可以辅助我们判断ANR流程何时开始,合适采集,合适结束等等,所以,我们一一来讲解。

5.1  logcat中日志信息

 首先,我们先梳理一下整个logcat中ANR日志的完整流程:

  1. 2022-10-08 15:03:32.023 24194-24330/? W/InputDispatcher: Window ... is not responding. Waited 5007ms for MotionEvent //InputDispatcher::onAnrLocked中,识别到输入事件响应超时
  2. 2022-10-08 15:03:32.023 24194-24330/? W/InputDispatcher: Canceling events ... it is unresponsive //InputDispatcher::cancelEventsForAnrLocked中,InputDispatcher进行ANR流程分法
  3. 2022-10-08 15:03:32.023 24194-24330/? I/WindowManager: ANR in Window{} //AnrController.java的notifyWindowUnresponsive中,window中超时,准备通知AMS
  4. 2022-10-08 15:03:32.146 24194-31707/? I/ActivityManager: dumpStackTraces pids={7705=true, 7740=true, ...} //ActivityManagerService.java的dumpStackTraces中,准备收集的进程集合
  5. 2022-10-08 15:03:32.471 24194-31707/? I/ActivityManager: Dumping to /data/anr/anr_2022-10-08-15-03-32-471 //ActivityManagerService.java的dumpStackTraces中,准备通知APP收集ANR日志
  6. 2022-10-08 15:03:32.471 24194-31707/? I/ActivityManager: Collecting stacks for pid 31655 //ActivityManagerService.java的dumpStackTraces中,待收集的进程PID
  7. 2022-10-08 15:03:32.472 24194-31707/? I/system_server: libdebuggerd_client: started dumping process 31655 //debuggerd_client.cpp的debuggerd_trigger_dump中,native中准备通知待收集的进程
  8. 2022-10-08 15:03:32.472 31655-31660/com.xt.client I/com.xt.client: Thread[6,tid=31660,...]: reacting to signal 3 //APP进程收到信号,准备开始写入
  9. 2022-10-08 15:03:32.568 31655-31660/com.xt.client I/com.xt.client: Wrote stack traces to tombstoned //APP进程写入完成,通知系统侧
  10. 2022-10-08 15:03:32.568 24194-31707/? I/system_server: libdebuggerd_client: done dumping process 31655 //系统进程收到通知,进行保存
  11. 2022-10-08 15:03:32.589 24194-31707/? I/ActivityManager: Collecting stacks for pid 24194 //ActivityManagerService.java dumpStackTraces中,准备开始收集下一个进程的PID,这个进程为系统进程system_server
  12. 2022-10-08 15:03:32.601 24194-31707/? I/system_server: libdebuggerd_client: started dumping process 24194 //debuggerd_client.cpp的debuggerd_trigger_dump中,native中准备通知待收集的进程
  13. 2022-10-08 15:03:32.603 24194-24202/? I/system_server: Thread[2,...]: reacting to signal 3 //system_server进程收到信号,准备开始写入
  14. 2022-10-08 15:03:32.858 24194-24202/? I/system_server: Wrote stack traces to tombstoned //system_server进程写入完成,通知系统侧
  15. ...继续收集其它java进程的信息
  16. 2022-10-08 15:03:34.972 24194-31707/? I/ActivityManager: Collecting stacks for native pid 660 //准备收集native进程660的信息
  17. 2022-10-08 15:03:34.973 24194-31707/? I/system_server: libdebuggerd_client: started dumping process 660 //debuggerd_client.cpp的debuggerd_trigger_dump中,native中准备通知待收集的进程
  18. 2022-10-08 15:03:34.974 660-660/? I/libc: Requested dump for pid 660 (binder:660_2) //debuggerd_handler.cpp的log_signal_summary中,native中准备通知待收集的进程
  19. ...继续收集其它native进程的信息
  20. 2022-10-08 15:03:36.273 24194-31707/? I/ActivityManager: Done dumping //全部收集完成
  21. 2022-10-08 15:03:36.274 24194-31707/? E/ActivityManager: ANR in com.xt.client (com.xt.client/.MainActivity) //打印发生ANR时收集到的日志
  22. ...

这里我们以输入类型为例,

1.InputDispatcher中识别到发生ANR了,通过回调java方法,通知到InputManagerService。如InputDispatcher开头的两行日志所记录。

2.InputManagerService中,根据WindowState找到对应的归属,先交给ActivityRecord处理,最终转交到AMS中。如WindowManager开头的一行日志所记录。

3.AMS中委托给AnrHelper.java进行处理,最终会通知到ProcessErrorStateRecord.java的appNotResponding方法,该方法中,会进行三个操作:

首先,收集需要dump的进程列表,包含java进程,native进程,其它进程,采集规则是发生ANR的进程+最近活动的进程。

其次,进行采集操作。这个会交给ActivityManagerService.java的dumpStackTraces方法执行。

最后,显示无响应的弹框。

4.采集日志会进入到ActivityManagerService.java的dumpStackTraces方法中,此时先打印ActivityManager开头的两行日志,分别代表着开始采集和生成日志文件。下面这两个日志分别记录将要采集的进程ID以及日志文件路径:

  1. 2022-10-08 15:03:32.146 24194-31707/? I/ActivityManager: dumpStackTraces pids={7705=true, 7740=true, ...} //ActivityManagerService.java的dumpStackTraces中,准备收集的进程集合
  2. 2022-10-08 15:03:32.471 24194-31707/? I/ActivityManager: Dumping to /data/anr/anr_2022-10-08-15-03-32-471 //ActivityManagerService.java的dumpStackTraces中,准备通知APP收集ANR日志

5.因为需要dump多个进程的,所以开始采集以及采集完成的日志会有很多,如下面所示,分别代表开始采集,发送信号通知,收到信号通知,采集完成以及系统收到采集完成的通知。这种日志会经历很多轮。

  1. 2022-10-08 15:03:32.471 24194-31707/? I/ActivityManager: Collecting stacks for pid 31655 //ActivityManagerService.java的dumpStackTraces中,待收集的进程PID
  2. 2022-10-08 15:03:32.472 24194-31707/? I/system_server: libdebuggerd_client: started dumping process 31655 //debuggerd_client.cpp的debuggerd_trigger_dump中,native中准备通知待收集的进程
  3. 2022-10-08 15:03:32.472 31655-31660/com.xt.client I/com.xt.client: Thread[6,tid=31660,...]: reacting to signal 3 //APP进程收到信号,准备开始写入
  4. 2022-10-08 15:03:32.568 31655-31660/com.xt.client I/com.xt.client: Wrote stack traces to tombstoned //APP进程写入完成,通知系统侧
  5. 2022-10-08 15:03:32.568 24194-31707/? I/system_server: libdebuggerd_client: done dumping process 31655 //系统进程收到通知,进行保存

6.采集native的信息

  1. 2022-10-08 15:03:34.972 24194-31707/? I/ActivityManager: Collecting stacks for native pid 660 //准备收集native进程660的信息
  2. 2022-10-08 15:03:34.973 24194-31707/? I/system_server: libdebuggerd_client: started dumping process 660 //debuggerd_client.cpp的debuggerd_trigger_dump中,native中准备通知待收集的进程
  3. 2022-10-08 15:03:34.974 660-660/? I/libc: Requested dump for pid 660 (binder:660_2) //debuggerd_handler.cpp的log_signal_summary中,native中准备通知待收集的进程

7.所有进程dump完成。

2022-10-08 15:03:36.273 24194-31707/? I/ActivityManager: Done dumping                                                   //全部收集完成

5.2  logcat中信息记录

上面的流程采集完成后,会一次性打印采集到的ANR的信息,如下面所示:

我们这一小节就重点介绍下,这份logcat中的ANR信息,如何解读。

  1. 2022-10-08 15:03:36.274 24194-31707/? E/ActivityManager: ANR in com.xt.client (com.xt.client/.MainActivity)
  2. PID: 31655 //进程ID
  3. Reason: Input dispatching timed out (dff7ad com.xt.client/com.xt.client.MainActivity (server) is not responding. Waited 5007ms for MotionEvent) //原因
  4. Parent: com.xt.client/.MainActivity //触发点
  5. ErrorId: bcef99f2-c232-4bee-bdd8-233b4ff598f0
  6. Frozen: false
  7. Load: 0.54 / 0.15 / 0.12 //ANR发生之前的1分钟,5分钟,15分钟CPU占用率。0.54代表0.54%
  8. ----- Output from /proc/pressure/memory -----
  9. some avg10=0.00 avg60=0.00 avg300=0.00 total=18377466
  10. full avg10=0.00 avg60=0.00 avg300=0.00 total=10458714
  11. ----- End output from /proc/pressure/memory -----
  12. //ANR发生之前的129秒内CPU占用率
  13. CPU usage from 129271ms to 0ms ago (2022-10-08 15:01:22.846 to 2022-10-08 15:03:32.116):
  14. //user代表用户态占用,kernel代表内核态占用
  15. 1.7% 24194/system_server: 1.2% user + 0.5% kernel / faults: 3611 minor
  16. 1.5% 689/surfaceflinger: 1.1% user + 0.4% kernel / faults: 441 minor
  17. 1.4% 24426/com.android.systemui: 1% user + 0.3% kernel / faults: 2682 minor
  18. 1% 28207/kworker/u16:6: 0% user + 1% kernel / faults: 18 minor
  19. 0.8% 31505/kworker/u16:3: 0% user + 0.8% kernel
  20. 0.7% 27789/kworker/u16:1: 0% user + 0.7% kernel / faults: 2 minor
  21. 0.6% 29978/com.tencent.mm: 0.1% user + 0.4% kernel / faults: 66 minor
  22. 0.6% 1122/vendor.google.wifi_ext@1.0-service-vendor: 0.3% user + 0.2% kernel / faults: 1190 minor
  23. 0.3% 24523/com.breel.wallpapers20a: 0.2% user + 0% kernel / faults: 1291 minor
  24. 0.4% 24828/com.google.android.apps.nexuslauncher: 0.3% user + 0% kernel / faults: 1984 minor
  25. 0.1% 691/android.hardware.graphics.composer@2.4-service-sm8150: 0% user + 0% kernel / faults: 133 minor
  26. 0.3% 18902/com.google.android.gms.persistent: 0.2% user + 0.1% kernel / faults: 2221 minor
  27. 0.3% 30388/com.tencent.mm:tools: 0.2% user + 0% kernel / faults: 93 minor
  28. ...

具体解释如下:

行数内容解释
1
ANR in com.test.sceneengineservice
发生ANR应用的包名
2
PID: 2468
发生ANR的进程ID,请注意, 此日志是system_server进程打印的
3
Reason: executing service com.test.sceneengineservice/.SceneEngineService 
发生ANR的的原因
4
Load: 0.0 / 0.0 / 0.0 
发生ANR之前CPU的负载,分别代表发生前的1分钟/5分钟/15分钟
5
CPU usage from 14781ms to 0ms ago (2022-09-21 07:32:34.092 to 2022-09-21 07:32:48.873):
这期间的CPU占用。从发生之前的14秒到发生时
6
E ActivityManager:   5.6% 1000/system_server: 1.8% user + 3.7% kernel / faults: 3555 minor
这段时间内具体的CPU占用率。user代表应用侧的占用,kernel代表内核侧的占用。

5.3  ANR文件中记录的信息

文件内容信息如下:

  1. Subject: Input dispatching timed out (4dff4f9 com.xt.client/com.xt.client.MainActivity (server) is not responding. Waited 5001ms for MotionEvent)
  2. --- CriticalEventLog ---
  3. capacity: 20
  4. events <
  5. timestamp_ms: 1665198570560
  6. anr <
  7. pid: 20001
  8. process: "com.xt.client"
  9. process_class: 1
  10. subject: "Input dispatching timed out (b9701e com.xt.client/com.xt.client.MainActivity (server) is not responding. Waited 5007ms for MotionEvent)"
  11. uid: 10244
  12. >
  13. >
  14. events <
  15. timestamp_ms: 1665198580245
  16. java_crash <
  17. exception_class: "java.lang.SecurityException"
  18. pid: 20001
  19. process: "com.xt.client"
  20. process_class: 1
  21. uid: 10244
  22. >
  23. >
  24. timestamp_ms: 1665198615793
  25. window_ms: 300000
  26. ----- pid 20223 at 2022-10-08 11:10:16.144897760+0800 -----
  27. Cmd line: com.xt.client
  28. Build fingerprint: 'google/sunfish/sunfish:13/TP1A.220905.004/8927612:user/release-keys'
  29. ABI: 'arm64'
  30. Build type: optimized
  31. /** 类加载信息-开始 class_linker.cc中写入,记录类加载信息 */
  32. Zygote loaded classes=21523 post zygote classes=573
  33. Dumping registered class loaders
  34. #0 dalvik.system.PathClassLoader: [], parent #1
  35. #1 java.lang.BootClassLoader: [], no parent
  36. #2 dalvik.system.PathClassLoader: [/data/app/~~9kDnfQhhAsXX5wlTVjeRlA==/com.xt.client-DT6oy9kys_nok1ibzgGmFQ==/base.apk!classes12.dex:/data/data/com.xt.client/code_cache/.overlay/base.apk/classes14.dex:/data/app/~~9kDnfQhhAsXX5wlTVjeRlA==/com.xt.client-DT6oy9kys_nok1ibzgGmFQ==/base.apk:/data/app/~~9kDnfQhhAsXX5wlTVjeRlA==/com.xt.client-DT6oy9kys_nok1ibzgGmFQ==/base.apk!classes11.dex:/data/app/~~9kDnfQhhAsXX5wlTVjeRlA==/com.xt.client-DT6oy9kys_nok1ibzgGmFQ==/base.apk!classes3.dex:/data/app/~~9kDnfQhhAsXX5wlTVjeRlA==/com.xt.client-DT6oy9kys_nok1ibzgGmFQ==/base.apk!classes8.dex:/data/data/com.xt.client/code_cache/.overlay/base.apk/classes9.dex:/data/app/~~9kDnfQhhAsXX5wlTVjeRlA==/com.xt.client-DT6oy9kys_nok1ibzgGmFQ==/base.apk!classes5.dex:/data/app/~~9kDnfQhhAsXX5wlTVjeRlA==/com.xt.client-DT6oy9kys_nok1ibzgGmFQ==/base.apk!classes6.dex], parent #1
  37. Done dumping class loaders
  38. Classes initialized: 0 in 0
  39. /** 类加载信息-结束 */
  40. /** 引用表-开始 intern_table.cc中写入,记录强弱引用数量 */
  41. Intern table: 30098 strong; 1210 weak
  42. /** 引用表-结束 */
  43. /** JNI加载信息-开始 java_vm_ext.cc中写入,记录加载的so */
  44. JNI: CheckJNI is on; globals=400 (plus 68 weak)
  45. Libraries: libandroid.so libaudioeffect_jni.so libcompiler_rt.so libframework-connectivity-jni.so libframework-connectivity-tiramisu-jni.so libicu_jni.so libjavacore.so libjavacrypto.so libjnigraphics.so libmedia_jni.so libopenjdk.so librs_jni.so librtp_jni.so libsoundpool.so libstats_jni.so libwebviewchromium_loader.so (16)
  46. /** JNI加载信息-结束 */
  47. /** java虚拟机堆状态-开始 heap.cc中写入,记录当前的内存状态 */
  48. Heap: 74% free, 4180KB/16MB; 183984 objects
  49. Dumping cumulative Gc timings
  50. Average major GC reclaim bytes ratio inf over 0 GC cycles
  51. Average major GC copied live bytes ratio 0.732525 over 4 major GCs
  52. Cumulative bytes moved 29923016
  53. Cumulative objects moved 547043
  54. Peak regions allocated 60 (15MB) / 1024 (256MB)
  55. Total madvise time 7.031ms
  56. Average minor GC reclaim bytes ratio nan over 0 GC cycles
  57. Average minor GC copied live bytes ratio nan over 0 minor GCs
  58. Cumulative bytes moved 0
  59. Cumulative objects moved 0
  60. Peak regions allocated 60 (15MB) / 1024 (256MB)
  61. Total number of allocations 183984
  62. Total bytes allocated 4180KB
  63. Total bytes freed 0B
  64. Free memory 11MB
  65. Free memory until GC 11MB
  66. Free memory until OOME 251MB
  67. Total memory 16MB
  68. Max memory 256MB
  69. Zygote space size 7760KB
  70. Total mutator paused time: 0
  71. Total time waiting for GC to complete: 2.448us
  72. Total GC count: 0
  73. Total GC time: 0
  74. Total blocking GC count: 0
  75. Total blocking GC time: 0
  76. Total pre-OOME GC count: 0
  77. Native bytes total: 14386550 registered: 2142838
  78. Total native bytes at last GC: 4357592
  79. /** java虚拟机堆状态-结束 */
  80. /** OTA文件记录-开始 oat_file_manager.cc中写入,记录当前使用到的OTA文件 */
  81. /data/app/~~9kDnfQhhAsXX5wlTVjeRlA==/com.xt.client-DT6oy9kys_nok1ibzgGmFQ==/oat/arm64/base.vdex: verify
  82. /system/framework/oat/arm64/android.hidl.manager-V1.0-java.odex: verify
  83. /system/framework/oat/arm64/android.test.base.odex: verify
  84. /system/framework/oat/arm64/android.hidl.base-V1.0-java.odex: verify
  85. /** OTA文件记录-结束 */
  86. /** JIT信息记录-开始 jit.cc中写入,记录JIT的信息 */
  87. Current JIT code cache size (used / resident): 40KB / 60KB
  88. Current JIT data cache size (used / resident): 28KB / 60KB
  89. Zygote JIT code cache size (at point of fork): 22KB / 32KB
  90. Zygote JIT data cache size (at point of fork): 16KB / 32KB
  91. Current JIT mini-debug-info size: 19KB
  92. Current JIT capacity: 128KB
  93. Current number of JIT JNI stub entries: 0
  94. Current number of JIT code cache entries: 46
  95. Total number of JIT baseline compilations: 34
  96. Total number of JIT optimized compilations: 4
  97. Total number of JIT compilations for on stack replacement: 1
  98. Total number of JIT code cache collections: 1
  99. Memory used for stack maps: Avg: 377B Max: 11KB Min: 32B
  100. Memory used for compiled code: Avg: 1156B Max: 26KB Min: 164B
  101. Memory used for profiling info: Avg: 187B Max: 4416B Min: 24B
  102. Start Dumping Averages for 56 iterations for JIT timings
  103. Compiling optimized: Sum: 49.228ms Avg: 879.071us
  104. Compiling baseline: Sum: 27.108ms Avg: 484.071us
  105. TrimMaps: Sum: 2.699ms Avg: 48.196us
  106. Code cache collection: Sum: 380us Avg: 6.785us
  107. Compiling OSR: Sum: 240us Avg: 4.285us
  108. Done Dumping Averages
  109. Memory used for compilation: Avg: 154KB Max: 4050KB Min: 16KB
  110. ProfileSaver total_bytes_written=0
  111. ProfileSaver total_number_of_writes=0
  112. ProfileSaver total_number_of_code_cache_queries=0
  113. ProfileSaver total_number_of_skipped_writes=0
  114. ProfileSaver total_number_of_failed_writes=0
  115. ProfileSaver total_ms_of_sleep=5000
  116. ProfileSaver total_ms_of_work=0
  117. ProfileSaver total_number_of_hot_spikes=0
  118. ProfileSaver total_number_of_wake_ups=0
  119. /** JIT信息记录-结束 */
  120. /** ART信息指标-开始 metrics_common.cc中写入,记录ART虚拟机的一些关键指标 */
  121. *** ART internal metrics ***
  122. Metadata:
  123. timestamp_since_start_ms: 19952
  124. Metrics:
  125. ClassLoadingTotalTime: count = 17358
  126. ClassVerificationTotalTime: count = 15303
  127. ClassVerificationCount: count = 28
  128. WorldStopTimeDuringGCAvg: count = 0
  129. YoungGcCount: count = 0
  130. FullGcCount: count = 0
  131. TotalBytesAllocated: count = 2349168
  132. TotalGcCollectionTime: count = 0
  133. YoungGcThroughputAvg: count = 0
  134. FullGcThroughputAvg: count = 0
  135. YoungGcTracingThroughputAvg: count = 0
  136. FullGcTracingThroughputAvg: count = 0
  137. JitMethodCompileTotalTime: count = 28492
  138. JitMethodCompileCount: count = 39
  139. YoungGcCollectionTime: range = 0...60000, buckets: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  140. FullGcCollectionTime: range = 0...60000, buckets: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  141. YoungGcThroughput: range = 0...10000, buckets: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  142. FullGcThroughput: range = 0...10000, buckets: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  143. YoungGcTracingThroughput: range = 0...10000, buckets: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  144. FullGcTracingThroughput: range = 0...10000, buckets: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  145. *** Done dumping ART internal metrics ***
  146. /** ART信息指标-结束 */
  147. /** 线程信息-开始 thread_list.cc中写入,记录当前进程的线程信息 */
  148. suspend all histogram: Sum: 112us 99% C.I. 0.083us-54us Avg: 4.666us Max: 54us
  149. DALVIK THREADS (19):
  150. "Signal Catcher" daemon prio=10 tid=6 Runnable
  151. | group="system" sCount=0 ucsCount=0 flags=0 obj=0x12c801a0 self=0xb400007193e16a60
  152. | sysTid=20229 nice=-20 cgrp=system sched=0/0 handle=0x7004dfbcb0
  153. | state=R schedstat=( 17930731 0 5 ) utm=0 stm=0 core=7 HZ=100
  154. | stack=0x7004d04000-0x7004d06000 stackSize=991KB
  155. | held mutexes= "mutator lock"(shared held)
  156. native: #00 pc 00000000005374cc /apex/com.android.art/lib64/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, int, BacktraceMap*, char const*, art::ArtMethod*, void*, bool)+128) (BuildId: 97fdb979efb7d2b596fa4fceabaad95b)
  157. native: #01 pc 00000000006f0d94 /apex/com.android.art/lib64/libart.so (art::Thread::DumpStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, bool, BacktraceMap*, bool) const+236) (BuildId: 97fdb979efb7d2b596fa4fceabaad95b)
  158. native: #02 pc 00000000006fe620 /apex/com.android.art/lib64/libart.so (art::DumpCheckpoint::Run(art::Thread*)+208) (BuildId: 97fdb979efb7d2b596fa4fceabaad95b)
  159. native: #03 pc 00000000003641d4 /apex/com.android.art/lib64/libart.so (art::ThreadList::RunCheckpoint(art::Closure*, art::Closure*)+440) (BuildId: 97fdb979efb7d2b596fa4fceabaad95b)
  160. native: #04 pc 00000000006fcdc0 /apex/com.android.art/lib64/libart.so (art::ThreadList::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, bool)+280) (BuildId: 97fdb979efb7d2b596fa4fceabaad95b)
  161. native: #05 pc 00000000006fc7b4 /apex/com.android.art/lib64/libart.so (art::ThreadList::DumpForSigQuit(std::__1::basic_ostream<char, std::__1::char_traits<char> >&)+292) (BuildId: 97fdb979efb7d2b596fa4fceabaad95b)
  162. native: #06 pc 00000000006d57e4 /apex/com.android.art/lib64/libart.so (art::Runtime::DumpForSigQuit(std::__1::basic_ostream<char, std::__1::char_traits<char> >&)+184) (BuildId: 97fdb979efb7d2b596fa4fceabaad95b)
  163. native: #07 pc 00000000006e1928 /apex/com.android.art/lib64/libart.so (art::SignalCatcher::HandleSigQuit()+468) (BuildId: 97fdb979efb7d2b596fa4fceabaad95b)
  164. native: #08 pc 0000000000573c40 /apex/com.android.art/lib64/libart.so (art::SignalCatcher::Run(void*)+264) (BuildId: 97fdb979efb7d2b596fa4fceabaad95b)
  165. native: #09 pc 00000000000b62b8 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+208) (BuildId: 058e3ec96fa600fb840a6a6956c6b64e)
  166. native: #10 pc 0000000000052fb8 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 058e3ec96fa600fb840a6a6956c6b64e)
  167. (no managed stack frames)
  168. "main" prio=5 tid=1 Sleeping
  169. | group="main" sCount=1 ucsCount=0 flags=1 obj=0x72424e88 self=0xb400007193e0a7b0
  170. | sysTid=20223 nice=-10 cgrp=system sched=0/0 handle=0x72dd5244f8
  171. | state=S schedstat=( 331627619 74690560 345 ) utm=30 stm=2 core=7 HZ=100
  172. | stack=0x7fcfb32000-0x7fcfb34000 stackSize=8188KB
  173. | held mutexes=
  174. at java.lang.Thread.sleep(Native method)
  175. - sleeping on <0x0e92c80b> (a java.lang.Object)
  176. at java.lang.Thread.sleep(Thread.java:450)
  177. - locked <0x0e92c80b> (a java.lang.Object)
  178. at java.lang.Thread.sleep(Thread.java:355)
  179. at com.xt.client.MainActivity.doActionWithoutClass(MainActivity.java:201)
  180. at com.xt.client.MainActivity.access$000(MainActivity.java:85)
  181. at com.xt.client.MainActivity$2.onItemClick(MainActivity.java:177)
  182. at com.xt.client.inter.RecyclerItemClickListener.onInterceptTouchEvent(RecyclerItemClickListener.java:34)
  183. at androidx.recyclerview.widget.RecyclerView.findInterceptingOnItemTouchListener(RecyclerView.java:3286)
  184. at androidx.recyclerview.widget.RecyclerView.dispatchToOnItemTouchListeners(RecyclerView.java:3257)
  185. at androidx.recyclerview.widget.RecyclerView.onTouchEvent(RecyclerView.java:3421)
  186. at android.view.View.dispatchTouchEvent(View.java:15004)
  187. at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3115)
  188. at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2788)
  189. at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3121)
  190. at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2802)
  191. at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3121)
  192. at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2802)
  193. at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3121)
  194. at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2802)
  195. at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3121)
  196. at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2802)
  197. at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:498)
  198. at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1899)
  199. at android.app.Activity.dispatchTouchEvent(Activity.java:4262)
  200. at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:456)
  201. at android.view.View.dispatchPointerEvent(View.java:15263)
  202. at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:6548)
  203. at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:6348)
  204. at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5804)
  205. at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5861)
  206. at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5827)
  207. at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5992)
  208. at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5835)
  209. at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:6049)
  210. at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5808)
  211. at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5861)
  212. at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5827)
  213. at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5835)
  214. at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5808)
  215. at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:8857)
  216. at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:8808)
  217. at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:8777)
  218. at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:8980)
  219. at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:267)
  220. at android.os.MessageQueue.nativePollOnce(Native method)
  221. at android.os.MessageQueue.next(MessageQueue.java:335)
  222. at android.os.Looper.loopOnce(Looper.java:161)
  223. at android.os.Looper.loop(Looper.java:288)
  224. at android.app.ActivityThread.main(ActivityThread.java:7898)
  225. at java.lang.reflect.Method.invoke(Native method)
  226. at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
  227. at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
  228. ...
  229. /** 线程信息-结束/
  230. ----- end 20223 -----
  231. ...

具体解释如下:

所在行内容解释
1”main“线程名
1prio=5线程优先级
1tid=1线程标识符
1Native线程状态,native是native中的线程状态,对应java中runnable
2group="main"线程所属的线程组
2sCount=1程被正常挂起的次数
2dsCount=0线程因调试而挂起次数
2flags=1
2obj=0x75c4db98线程的Java对象的地址
2self=0x7b08e14c00线程本身的地址
3sysTid=2468Linux下的内核线程id
3nice=0线程的调度优先级
3cgrp=default调度属组
3sched=0/0线程的调度策略和优先级
3handle=0x7b8e933548线程的处理函数地址
4state=S调度状态
4schedstat=( 562066147 3061697256 542 )

执行时间记录:

三个值分别表示线程在cpu上执行的时间、线程的等待时间和线程执行的时间片长度

4utm=31用户态CPU占用次数,由于频率是100,则占用31次就等于31*10ms=310ms
4stm=24内核态CPU占用次数
4core=2最后执行这个线程的CPU核序号
4HZ=100运行频率,一秒100次
5stack=0x7fe841d000-0x7fe841f000虚拟机栈地址
5stackSize=8MB虚拟机栈大小
6at android.os.BinderProxy.transactNative(Native method) at android.os.BinderProxy.transact(Binder.java:1127)此时采集到的APP对应线程的对应状态

5.4 DropBox中的ANR信息

dropBox中的日志文件更像是一个综合体,包括了logcat日志中的部分以及ANR文件中的部分。

ProcessErrorStateRecord的appNotResponding方法中,会通过以下的方法,把report信息和traceFile中的信息进行记录。report信息基本上就是上面logcat中的部分。

  1. mService.addErrorToDropBox("anr", mApp, mApp.processName, activityShortComponentName,
  2. parentShortComponentName, parentPr, null, report.toString(), tracesFile,
  3. null, new Float(loadingProgress), incrementalMetrics, errorId);

文件位置是:/data/system/dropbox/data_app_anr@1670396615724.txt.gz

是一个压缩文件,解析后就是我们想要的内容了,大体的格式如下。

  1. Process: com.beantechs.apm
  2. PID: 10589
  3. Flags: 0x20e8bf46
  4. Package: com.xxx.apm v1 (1.0)
  5. Foreground: Yes
  6. Activity: com.xxx.apm/.TestActivity
  7. Subject: Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago. Wait queue length: 4. Wait queue head age: 5571.8ms.)
  8. Build: qti/gwm/gwm:9/PQ1A.190105.004/bean08231515:userdebug/test-keys
  9. CPU usage from 141069ms to 0ms ago (2022-12-07 15:01:10.951 to 2022-12-07 15:03:32.020):
  10. 20% 6354/adbd: 1.7% user + 18% kernel / faults: 4493599 minor
  11. 5.8% 322/logd: 1.7% user + 4% kernel / faults: 26 minor
  12. 4.3% 514/android.hardware.sensors@1.0-service: 0.6% user + 3.7% kernel
  13. 3.9% 385/vendor.ts.systemlog@1.0-service: 1.7% user + 2.1% kernel / faults: 281 minor
  14. 3.4% 497/android.hardware.audio@2.0-service.rbgwm: 0.9% user + 2.4% kernel
  15. 3.2% 1020/system_server: 1.3% user + 1.9% kernel / faults: 21547 minor 1 major
  16. 3.2% 543/audioserver: 1.2% user + 1.9% kernel / faults: 4052 minor
  17. 3.2% 26582/kworker/u16:1: 0% user + 3.2% kernel
  18. 2.2% 4415/com.beantechs.datapipeline: 1.5% user + 0.7% kernel / faults: 41778 minor
  19. 2.1% 4442/com.lx.usbaudiohid: 1% user + 1% kernel / faults: 2 minor
  20. 2% 3376/com.beantechs.intelligentvehiclecontrol: 1.3% user + 0.7% kernel / faults: 5915 minor
  21. 1.8% 9937/kworker/u17:1: 0% user + 1.8% kernel
  22. ...
  23. 10% TOTAL: 3.2% user + 6.4% kernel + 0% iowait + 0.7% irq + 0.1% softirq
  24. ----- pid 10589 at 2022-12-07 15:03:32 -----
  25. Cmd line: com.xxxx.apm

六.扩展问题:

问题1:ANR发生后会立马弹出ANR框吗?

答:不会,2.3中讲到,触发了ANR并且采集完相关线程日志后,会延时5S在弹出ANR的框。

问题2:主线程卡顿一定会导致ANR吗?

答:不会。首先,卡顿一定要达到某个阈值才会触发。其次,一定要满足某个场景才可以。比如ActivityA跳转ActivityB之后,延时1S后主线程休眠20S,就不会ANR,因为输入事件已经得到响应,并不满足任何触发ANR的场景。

问题3:为什么ANR的日志traces.txt中,有时候会打印nativePollOnce的堆栈?

答:理论上,系统侧在发现达到超市事件后,会立马出发ANR检查。如果检查发生真的超时,会走ANR流程,捕获APP的堆栈状态并保存。但是实际执行中,创建文件,dump指定进程堆栈信息都需要时间,并且ANR流程的开始还会sleep200毫秒。

我们看3.1中日志,从15:03:32.023开始识别到ANR,到15:03:32.568结束dump完成APP侧信息。

  1. 2022-10-08 15:03:32.023 24194-24330/? W/InputDispatcher: Window ... is not responding. Waited 5007ms for MotionEvent //InputDispatcher::onAnrLocked中,识别到输入事件响应超时
  2. 2022-10-08 15:03:32.568 31655-31660/com.xt.client I/com.xt.client: Wrote stack traces to tombstoned //APP进程写入完成,通知系统侧

整个流程大约要500多毫秒,其中包括:

1.InputDispatcher中识别到ANR,传递到AMS准备开始采集要100多毫秒

2.识别到ANR的时候,系统进程会休眠200毫秒采集CPU信息。

3.系统进程采集一些必要信息,会耗费一些时间,大约100毫秒左右。

4.客户端收到信号去采集ANR的时候,也需要时间,大约要100毫秒左右。

所以,漂移的是有上限时间的,正常漂移上限一般为500ms左右,即使极端的场景,应该也不会很长。

七.声明:

参考文章:

​​​​​​android input anr分析 - 知乎

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/619503
推荐阅读
相关标签
  

闽ICP备14008679号