> 技术文档 > Android ANR分析总结

Android ANR分析总结


Android ANR分析总结

文章目录

  • Android ANR分析总结
    • 一、前言
      • 1、什么是 ANR?为什么会发生 ANR?
      • 2、系统对ANR的检测机制
    • 二、ANR分析思路
      • 1、看logcat日志
      • 2、查看ANR堆栈日志(需要root权限)
      • 3、查看CPU使用率
    • 三、真机模拟ANR产生并对比看看日志情况
      • 1、Activity主线程 Sleep6秒
        • (1)产生的logcat主要日志:
        • (2)ANR堆栈文件
      • 2、Activity主线程一直for循环
        • (1)ANR相关的logcat日志:
        • (2)ANR堆栈文件:
      • 3、广播Sleep12秒
        • (1)logcat日志:
        • (2)ANR文件日志:
      • 4、广播一直for循环
        • (1)logcat日志:
        • (2)ANR文件日志:
      • 5、服务Sleep12秒
        • (1)logcat相关日志:
        • (2)ANR文件日志:
      • 6、服务一直for循环
        • (1)logcat日志:
        • (2)ANR堆栈日志:
      • 示例演示小结:
        • (1)为啥这里演示的不同场景ANR都是UI无响应的5秒?
        • (2)主线程Sleep 5秒必定会造成ANR吗?
    • 三、其他
      • 1、ANR分析小结
      • 2、检测ANR异常其他手段
      • Android Studio中打开Profiler 功能
      • 3、Google Chome浏览器ANR示例

一、前言

1、什么是 ANR?为什么会发生 ANR?

定义:ANR(Application Not Responding)即应用无响应。

是 Android 系统检测到主线程(UI 线程)长时间阻塞时触发的机制,用户会看到 “等待 / 关闭应用” 对话框或者直接崩溃导致关闭应用。

根本原因:

主线程被耗时操作(如 IO、网络请求、复杂计算)阻塞,或因锁竞争、CPU 资源不足导致无法及时处理输入事件或系统回调。

2、系统对ANR的检测机制

系统检测机制,ANR 的四种(四大组件:界面、广播、服务、内容提供者)场景及超时时间:

场景 超时时间 触发条件 输入事件超时 5 秒 用户交互(如点击、滑动)未在 5 秒内处理完成 前台广播超时 10 秒 BroadcastReceiver.onReceive执行超过 10 秒 后台广播超时 60 秒 后台广播(如Context.startBroadcast)未在 60 秒内完成 前台服务超时 20 秒 Service.onStartCommand/onBind未在 20 秒内返回 后台服务超时 200 秒 后台服务执行超过 200 秒 内容提供者超时 10 秒 ContentProvider的query/insert等方法未在 10 秒内完成

注意:不同 Android 版本可能略有差异,需强调常见标准值。

其实大部分情况都是操作耗时导致ANR,并且最最常见的就是5秒事件超时。

除了上面的常见情况,还有另外的 锁竞争 / 死锁 也会导致ANR,场景和现场:

主线程等待子线程持有的锁(如`synchronized`块),或多个线程形成死锁循环线程状态为`Blocked`,日志中出现`waiting for monitor entry`

这种情况比较特殊,一般可以不用考虑。

本文介绍分析ANR异常的相关日志,并且模拟相关ANR进行简单验证。

有兴趣的可以收藏看看。

二、ANR分析思路

下面主要以Android13的系统代码进行分析。

1、看logcat日志

adb shell# logcat | grep -i \"anr\"

如下可以看到ANR相关的主要日志:

IWB:/data/anr # logcat | grep -i \"anr\"06-27 16:10:06.187 831 996 I WindowManager: ANR in Window{941e1d u0 com.liwenzhi.broadcasttest/com.liwenzhi.broadcasttest.MainActivity}. Reason:941e1d com.liwenzhi.broadcasttest/com.liwenzhi.broadcasttest.MainActivity (server) is not responding. Waited 5001ms for MotionEvent(deviceId=7, eventTime=8503483577000, source=MOUSE, displayId=0, action=HOVER_MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, xCursorPosition=2675.3, yCursorPosition=315.4, pointers=[0: (2675.3, 315.4)]), policyFlags=0x6200000106-27 16:10:06.753 831 7788 I ActivityManager: Dumping to /data/anr/anr_2025-06-27-16-10-06-75206-27 16:10:12.435 831 7788 E ActivityManager: ANR in com.liwenzhi.broadcasttest (com.liwenzhi.broadcasttest/.MainActivity)06-27 16:10:12.435 831 7788 E ActivityManager: 40% 7788/AnrConsumer: 14% user + 26% kernel06-27 16:10:12.438 831 7788 D ActivityManager: Completed ANR of com.liwenzhi.broadcasttest in 6202ms, latency 1ms06-27 16:10:12.478 831 7921 I DropBoxManagerService: add tag=data_app_anr isTagEnabled=true flags=0x6

上面就能看到ANR的具体位置:com.liwenzhi.broadcasttest/.MainActivity

并且说明了会生成堆栈信息文件:Dumping to /data/anr/anr_2025-06-27-16-10-06-752

这里可以看到一次ANR的日志并不会很多,除非是很多次异常会导致日志很多;

所以ANR的日志,及时抓取就好分析一点。

总结一下ANR关键字的logcat日志可以看到如下信息:

(1)\"ANR in\" 之后的信息是ANR的关键信息,(2)\"ANR in\" 之后的 Reason:是大致说明ANR的主要原因,(3)这里的ANR是因为:Waited 5001ms for MotionEvent,就是主线程5秒内无法响操作导致,(4)ActivityManager: Dumping to 是生成ANR堆栈文件的日志,(5)ANR堆栈文件有些情况看到具体哪个类的哪代码错误,(6)生成日志之后的logcat,有大概打印当前cpu的使用情况,可以展开看看,(7)ANR崩溃后大致会有:Force finishing、Completed ANR of 等ANR结束日志。

不同的系统版本生成的ANR堆栈文件可能会不一样,旧版本可能是: traces.txt ,主要是看logcat日志提示为准。

2、查看ANR堆栈日志(需要root权限)

ANR文件比较大,直接cat看不到啥,只能adb pull到本地查看;

比如是用notpad++打开上面日志中提示anr文件:/data/anr/anr_2025-06-27-16-10-06-752

找到第一个主线程堆栈任务,搜索关键字:“main” prio=

\"main\" prio=5 tid=1 Sleeping //(1)当时阻塞的时候是Sleep状态 | group=\"main\" sCount=1 ucsCount=0 flags=1 obj=0x7155d078 self=0xb400006f68651380 | sysTid=7193 nice=-10 cgrp=top-app sched=0/0 handle=0x70a8ce54f8 | state=S schedstat=( 2127060668 395250185 1857 ) utm=184 stm=27 core=4 HZ=100 // (2)state=S S表示休眠 | stack=0x7ff7985000-0x7ff7987000 stackSize=8188KB | held mutexes= at java.lang.Thread.sleep(Native method) - sleeping on  (a java.lang.Object) at java.lang.Thread.sleep(Thread.java:450) - locked  (a java.lang.Object) at java.lang.Thread.sleep(Thread.java:355) at com.liwenzhi.broadcasttest.MainActivity$1.onReceive(MainActivity.java:96) //(3)报错的具体代码类和行数 at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$android-app-LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1790) at android.app.LoadedApk$ReceiverDispatcher$Args$$ExternalSyntheticLambda0.run(unavailable:2) at android.os.Handler.handleCallback(Handler.java:942) ... at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:943)

从上面日志可以看到,报错的具体类和代码行数,进行适配修改就可以了。

上面的demo代码当时是Sleep6秒,所以是显示上面的报错。

这种是比较简单的情况,如果比较复杂的apk并且进行加密的情况,有可能看不到具体的类名称;

但是根据第一个主线程的报错堆栈,还是可以看到那个包名的应用报错的,能大致定位。

ANR堆栈文件内容比较多,很多人可能拿到了也看不出啥,主要思路:

(1)最最关键信息就是看第一个主线程的堆栈信息,搜索\"main\" prio= 就可以看到(2)\"main\" prio=5 tid=1 Sleeping ,可以看到线程当时状态是Sleep模式,也可能是其他的状态(3)state=S schedstat ,确认模式,S 表示Sleep(4)再往下就是堆栈信息了,堆栈信息前面集合和后面几个都是没啥用的,一般看中间的具体的某个应用的类

整个ANR堆栈文件的大部分日志没有太多作用,重点看第一个主线程的信息即可。

网上很多的说在ANR的堆栈文件查看,cpu使用情况,关键字\"CPU usage\" ,或者ANR的原因,关键字\"Reason:\",

这些信息在Android13或者更新版本的ANR文件都是没有的,大部分信息已经放到logcat中显示了。

Android 系统中,线程状态通过 state= 字段标识,常见状态包括:

状态码 完整名称 含义 R Running 线程正在 CPU 上执行,或已准备好执行(处于就绪队列)。 S Sleeping 线程处于睡眠状态,等待某个事件(如 I/O 完成、锁释放)唤醒。 D Disk Sleep 深度睡眠状态(不可中断),通常与磁盘 I/O 相关,无法被信号唤醒。 Z Zombie 僵尸进程,进程已终止但资源未被完全释放。 T Stopped 线程被暂停(如被调试器暂停或通过信号暂停)。 W Waiting 线程正在等待其他线程执行特定操作(如等待锁)。 X Dead 线程已终止。

3、查看CPU使用率

这种情况一般是排除是否系统卡顿,CPU使用过高导致ANR。

比如应用无限循环创建线程、界面、服务等操作,系统使用率会很高,后续打开界面或者点击按钮都可能会卡顿/ANR。

关键字:CPU usage

查看CPU使用是否达到90%以上。

一个demo应用ANR示例logcat日志如下:

logcat | grep \"CPU usage\"06-25 22:22:07.938 1069 19955 E ActivityManager: CPU usage from 172492ms to 0ms ago (2025-06-25 22:19:13.574 to 2025-06-25 22:22:06.066):06-25 22:22:07.938 1069 19955 E ActivityManager: 9.1% 1069/system_server: 5.6% user + 3.5% kernel / faults: 161504 minor 4 major06-25 22:22:07.938 1069 19955 E ActivityManager: 4.7% 1676/com.android.launcher3: 3.9% user + 0.8% kernel / faults: 10930 minor...//10% TOTAL 不影响06-25 22:22:07.938 1069 19955 E ActivityManager: 10% TOTAL: 4.5% user + 4.8% kernel + 0% iowait + 1.1% irq + 0.2% softirq06-25 22:22:07.938 1069 19955 E ActivityManager: CPU usage from 29ms to 323ms later (2025-06-25 22:22:06.095 to 2025-06-25 22:22:06.389):06-25 22:22:07.938 1069 19955 E ActivityManager: 158% 19849/com.liwenzhi.broadcasttest: 126% user + 32% kernel / faults: 3790 minor06-25 22:22:07.938 1069 19955 E ActivityManager: 93% 19849/i.broadcasttest: 74% user + 18% kernel06-25 22:22:07.938 1069 19955 E ActivityManager: 23% 19854/HeapTaskDaemon: 18% user + 4.6% kernel...//68% TOTAL 不影响06-25 22:22:07.938 1069 19955 E ActivityManager: 68% TOTAL: 32% user + 32% kernel + 3.5% irq//ANR 的应用06-25 22:22:07.940 1069 19955 D ActivityManager: Completed ANR of com.liwenzhi.broadcasttest in 1874ms, latency 1ms

这个主要监控系统CPU使用高的主要日志。

上面可以看到CPU TOTAL 的使用率不高,并不是因为系统CPU处理不过来导致ANR;

虽然能看到某个App的使用率超过100%,但是CPU一般是四核或者八核的,

所以某个核的线程使用超过100%,对系统影响不大。

这里主要是看logcat,ANR文件虽然也有些apk的使用率但是有点看不懂;

之前旧版本的系统,网上很多都是说在 traces.txt 能看到 \"CPU usage\"cpu使用率的相关信息,

但是Android13之后的版本上面的ANR文件看了是没有\"CPU usage\" 关键字信息的。

所以ANR异常分析,主要就是看logcat 和ANR文件,进行分析;

网上有的还有说用 Systrace工具或者Studio进行分析,其实都是比较麻烦的,后面会简单说明一下。

上面是分析的大致思路,下面模拟几个情况试试,并看看日志是怎么样的。

三、真机模拟ANR产生并对比看看日志情况

下面主要模拟Activity、Broadcast、Service主线程Sleep和不断执行任务,导致ANR的日志。

不同的系统上报错的实际代码可能有差异,这里仅供参考。

1、Activity主线程 Sleep6秒

验证测试代码:

 public void sendBroadcast(View view) { LogUtil.debug(\"\"); try { Thread.sleep(6000); } catch (InterruptedException e) { throw new RuntimeException(e); } }

Activity添加一个按钮和onClick事件,点击后执行修改6秒。

(1)产生的logcat主要日志:
//执行按钮后的日志:06-28 10:39:50.691 8700 8700 I XXXAppLog: MainActivity.java (51 )::sendBroadcast - 过滤ANR关键字的日志:行 965: 06-28 10:39:55.884 825 1043 I WindowManager: ANR in Window{1c87832 u0 com.liwenzhi.broadcasttest/com.liwenzhi.broadcasttest.MainActivity}. Reason:1c87832 com.liwenzhi.broadcasttest/com.liwenzhi.broadcasttest.MainActivity (server) is not responding. Waited 5004ms for MotionEvent(deviceId=9, eventTime=4948383052000, source=MOUSE, displayId=0, action=HOVER_MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, xCursorPosition=1947.4, yCursorPosition=489.9, pointers=[0: (1947.4, 489.9)]), policyFlags=0x62000001行 1002: 06-28 10:39:56.464 825 9610 I ActivityManager: Dumping to /data/anr/anr_2025-06-28-10-39-56-463行 1002: 06-28 10:39:56.464 825 9610 I ActivityManager: Dumping to /data/anr/anr_2025-06-28-10-39-56-463行 1662: 06-28 10:40:01.762 825 9610 E ActivityManager: ANR in com.liwenzhi.broadcasttest (com.liwenzhi.broadcasttest/.MainActivity)行 1750: 06-28 10:40:01.763 825 9610 E ActivityManager: 33% 9610/AnrConsumer: 12% user + 21% kernel行 1776: 06-28 10:40:01.766 825 9610 D ActivityManager: Completed ANR of com.liwenzhi.broadcasttest in 5800ms, latency 0ms行 1779: 06-28 10:40:01.813 825 9745 I DropBoxManagerService: add tag=data_app_anr isTagEnabled=true flags=0x6

上面这个没啥好说的,就是最经典的5秒左右无响应导致。

可以看到大概过了5秒就出现ANR日志,并且显示原因,和产生的ANR文件。

上面可以看到主要信息:

导致ANR的主要原因:Reason:...MainActivity (server) is not responding. Waited 5004ms for MotionEventANR 报错的类: ActivityManager: ANR in com.liwenzhi.broadcasttest.MainActivity

从logcat日志冲看不出是哪行代码导致ANR阻塞的原因,只能看出ANR堆栈日志查看具体导致ANR的代码行数。

(2)ANR堆栈文件:
\"main\" prio=5 tid=1 Sleeping | group=\"main\" sCount=1 ucsCount=0 flags=1 obj=0x72499078 self=0xb40000709eec97b0 | sysTid=8700 nice=-10 cgrp=top-app sched=0/0 handle=0x71e0dbb4f8 | state=S schedstat=( 2089098233 284649330 1360 ) utm=174 stm=33 core=7 HZ=100 | stack=0x7ffa47d000-0x7ffa47f000 stackSize=8188KB | held mutexes= at java.lang.Thread.sleep(Native method) - sleeping on  (a java.lang.Object) at java.lang.Thread.sleep(Thread.java:450) - locked  (a java.lang.Object) at java.lang.Thread.sleep(Thread.java:355) at com.liwenzhi.broadcasttest.MainActivity.sendBroadcast(MainActivity.java:53) //阻塞位置 at java.lang.reflect.Method.invoke(Native method) at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:468) at android.view.View.performClick(View.java:7507)... at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:943)

这里的ANR堆栈文件可以看出,当时主线程的运行状态是Sleep和主要导致阻塞的具体代码。

2、Activity主线程一直for循环

把Sleep代码替换成大的for循环代码,因为在正常系统for循环中每毫秒只能打印1-2次,

所以只要在主线程循环次数大于10000,就有可能阻塞超过5秒,导致ANR。

不同的系统处理器有差异,如果要必现循环卡死,写个上亿的值进行循环肯定能复现。

其实不一定要很大值的for循环,只要在循环里面每次睡1秒,6秒后也会ANR;

这里for循环只是一直参考,也可以大致区分不同系统的处理能力。

验证测试代码:

 public void sendBroadcast(View view) { LogUtil.debug(\"\"); int index = 0; while (index < 1000000000) { LogUtil.debug(\"自定义广播接收\" + index++); } }

执行for循环后ANR日志如下:

(1)ANR相关的logcat日志:
行 1213: 06-30 20:14:56.520 12502 12502 I XXXAppLog: MainActivity.java (53 )::sendBroadcast - 行 1214: 06-30 20:14:56.521 12502 12502 I XXXAppLog: MainActivity.java (61 )::sendBroadcast - 自定义广播接收0console:/vendor # logcat | grep -i ANR06-30 20:15:02.143 826 1041 I WindowManager: ANR in Window{90cb493 u0 com.liwenzhi.broadcasttest/com.liwenzhi.broadcasttest.MainActivity}. Reason:90cb493 com.liwenzhi.broadcasttest/com.liwenzhi.broadcasttest.MainActivity (server) is not responding. Waited 5001ms for MotionEvent(deviceId=7, eventTime=13514939611000, source=MOUSE, displayId=0, action=HOVER_MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, xCursorPosition=1910.8, yCursorPosition=530.4, pointers=[0: (1910.8, 530.4)]), policyFlags=0x6200000106-30 20:15:02.832 826 13042 I ActivityManager: Dumping to /data/anr/anr_2025-06-30-20-15-02-83106-30 20:15:07.127 826 13042 E ActivityManager: ANR in com.liwenzhi.broadcasttest (com.liwenzhi.broadcasttest/.MainActivity)06-30 20:15:07.127 826 13042 E ActivityManager: 37% 13042/AnrConsumer: 17% user + 20% kernel06-30 20:15:07.132 826 13042 D ActivityManager: Completed ANR of com.liwenzhi.broadcasttest in 4948ms, latency 1ms06-30 20:15:07.169 826 13167 I DropBoxManagerService: add tag=data_app_anr isTagEnabled=true flags=0x6行 93814: 06-30 20:15:07.166 12502 12502 I XXXAppLog: MainActivity.java (61 )::sendBroadcast2 - 自定义广播接收91343...//虽然应用界面崩溃了,但是系统还会打印一段时间,几秒或者十几秒,因为系统没有一下子杀死这个应用!

这里的for循环ANR日志和Sleep日志差不多,也是只能看到ANR无响应和哪个类相关,但是无法看到具体哪行代码;

同时这里也能看到cpu的使用比普通Sleep的情况是高一些,说明不断执行任务,只会增加cpu的使用率的。

(2)ANR堆栈文件:
\"main\" prio=5 tid=1 Runnable | group=\"main\" sCount=0 ucsCount=0 flags=0 obj=0x716e7078 self=0xb400006fb5d1a7b0 | sysTid=12502 nice=-10 cgrp=top-app sched=0/0 handle=0x70f7cad4f8 | state=R schedstat=( 6753134401 864033863 4948 ) utm=451 stm=223 core=1 HZ=100 | stack=0x7fc4a9b000-0x7fc4a9d000 stackSize=8188KB | held mutexes= \"mutator lock\"(shared held) native: #00 pc 0000000000554874 /apex/com.android.art/lib64/libart.so ... at android.util.Log.println_native(Native method) at android.util.Log.i(Log.java:181) at com.liwenzhi.broadcasttest.LogUtil.debug(LogUtil.java:78) at com.liwenzhi.broadcasttest.MainActivity.sendBroadcast(MainActivity.java:61) //ANR日志 at android.view.View.performClick(View.java:7507) at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1213)... at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:943)

这里没有进行Sleep而是现实Run状态,说明主线程一直在高速执行任务,导致主线程无法进行其他操作,后续就会ANR。

这里也能看到ANR阻塞的关键代码位置。

3、广播Sleep12秒

MainActivity代码,在广播接收者中Sleep12秒。

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); LogUtil.debug(\"\"); registerBroadcast(this); } @Override protected void onDestroy() { super.onDestroy(); unRegisterBroadcast(this); } public void sendBroadcast(View view) { LogUtil.debug(\"\"); Intent intent = new Intent(\"TestBroadcast\"); //发送广播 sendBroadcast(intent); } public void registerBroadcast(Context context) { LogUtil.debug(\"\"); filter.addAction(\"TestBroadcast\"); //自定义广播 registerReceiver(mReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED); } private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { //接收广播 final String action = intent.getAction(); LogUtil.debug(\"onReceive: action = \" + action); switch (action) { case \"TestBroadcast\":  LogUtil.debug(\"自定义广播接收\");  try { Thread.sleep(120000);  } catch (InterruptedException e) { throw new RuntimeException(e);  }  break; } } };

下面是点击发送广播后的ANR相关日志。

(1)logcat日志:
06-30 20:38:41.232 10747 10747 I XXXAppLog: MainActivity.java (45 )::sendBroadcast - 06-30 20:38:47.223 835 1001 I WindowManager: ANR in Window{179e744 u0 com.liwenzhi.broadcasttest/com.liwenzhi.broadcasttest.MainActivity}. Reason:179e744 com.liwenzhi.broadcasttest/com.liwenzhi.broadcasttest.MainActivity (server) is not responding. Waited 5002ms for MotionEvent(deviceId=7, eventTime=982458875000, source=MOUSE, displayId=0, action=DOWN, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000001, classification=NONE, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, xCursorPosition=2070.1, yCursorPosition=306.4, pointers=[0: (2070.1, 306.4)]), policyFlags=0x6200000106-30 20:38:47.790 835 10866 I ActivityManager: Dumping to /data/anr/anr_2025-06-30-20-38-47-79006-30 20:38:52.358 835 10866 E ActivityManager: ANR in com.liwenzhi.broadcasttest (com.liwenzhi.broadcasttest/.MainActivity)06-30 20:38:52.358 835 10866 E ActivityManager: 33% 10866/AnrConsumer: 6.1% user + 27% kernel06-30 20:38:52.366 835 10866 D ActivityManager: Completed ANR of com.liwenzhi.broadcasttest in 5084ms, latency 1ms06-30 20:38:52.426 835 10994 I DropBoxManagerService: add tag=data_app_anr isTagEnabled=true flags=0x6

这个的报错和上面Activity ANR事件报错的日志差不多,看不出具体类的哪行代码报错;

只能看看堆栈文件的日志了。

(2)ANR文件日志:
\"main\" prio=5 tid=1 Sleeping | group=\"main\" sCount=1 ucsCount=0 flags=1 obj=0x713cb078 self=0xb400007a716a17b0 | sysTid=10747 nice=-10 cgrp=top-app sched=0/0 handle=0x7bb7f014f8 | state=S schedstat=( 1694521387 208644145 1104 ) utm=142 stm=27 core=5 HZ=100 | stack=0x7fe8c5c000-0x7fe8c5e000 stackSize=8188KB | held mutexes=... at java.lang.Thread.sleep(Thread.java:355) at com.liwenzhi.broadcasttest.MainActivity$1.onReceive(MainActivity.java:110) //阻塞日志 at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$android-app- ... at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:943)

上面可以看到阻塞的原因是休眠Sleep;

日志和UI无响应的类似,只是ANR导致的具体代码行不同而已。

4、广播一直for循环

把上面广播接收后的Sleep操作,替换成for循环底代码:

int index = 0;while (index < 1000000000) {LogUtil.debug(\"自定义广播接收\" + index++);}

报错后的相关日志。

(1)logcat日志:
06-30 20:55:36.055 19434 19434 I XXXAppLog: MainActivity.java (45 )::sendBroadcast - ...行 54714: 06-30 20:55:41.445 835 1001 I WindowManager: ANR in Window{5f3cc3b u0 com.liwenzhi.broadcasttest/com.liwenzhi.broadcasttest.MainActivity}. Reason:5f3cc3b com.liwenzhi.broadcasttest/com.liwenzhi.broadcasttest.MainActivity (server) is not responding. Waited 5003ms for MotionEvent(deviceId=7, eventTime=1996690856000, source=MOUSE, displayId=0, action=HOVER_MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, xCursorPosition=1941.7, yCursorPosition=313.6, pointers=[0: (1941.7, 313.6)]), policyFlags=0x62000001行 61010: 06-30 20:55:42.094 835 19543 I ActivityManager: Dumping to /data/anr/anr_2025-06-30-20-55-42-093行 61010: 06-30 20:55:42.094 835 19543 I ActivityManager: Dumping to /data/anr/anr_2025-06-30-20-55-42-093行 108885: 06-30 20:55:46.355 835 19543 E ActivityManager: ANR in com.liwenzhi.broadcasttest (com.liwenzhi.broadcasttest/.MainActivity)行 109033: 06-30 20:55:46.355 835 19543 E ActivityManager: 32% 19543/AnrConsumer: 8.1% user + 24% kernel行 109077: 06-30 20:55:46.358 835 19543 D ActivityManager: Completed ANR of com.liwenzhi.broadcasttest in 4877ms, latency 1ms行 109278: 06-30 20:55:46.396 835 19662 I DropBoxManagerService: add tag=data_app_anr isTagEnabled=true flags=0x6

这里的for循环ANR日志和Sleep日志差不多,也是只能看到ANR无响应和哪个类相关,但是无法看到具体哪行代码;

(2)ANR文件日志:
\"main\" prio=5 tid=1 Runnable | group=\"main\" sCount=0 ucsCount=0 flags=0 obj=0x713cb078 self=0xb400007a716a17b0 | sysTid=19434 nice=-10 cgrp=top-app sched=0/0 handle=0x7bb7f014f8 | state=R schedstat=( 6769272060 982465976 5922 ) utm=464 stm=212 core=0 HZ=100 | stack=0x7fe8c5c000-0x7fe8c5e000 stackSize=8188KB | held mutexes= \"mutator lock\"(shared held) native: #00 pc 0000000000554874 /apex/com.android.art/lib64/libart.so ... at com.liwenzhi.broadcasttest.LogUtil.debug(LogUtil.java:73) at com.liwenzhi.broadcasttest.MainActivity$1.onReceive(MainActivity.java:107) //阻塞 at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$an... at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:943)

这里也能看到当时是运行状态,并且看到ANR阻塞的关键代码位置。

5、服务Sleep12秒

Activity 拉起Service,并且Service的启动过程Sleep12秒。

//MainActivity.java public void sendBroadcast(View view) { LogUtil.debug(\"\"); startService(new Intent(this, MyService.class)); }//MyService.javapublic class MyService extends Service { @Override public void onCreate() { super.onCreate(); LogUtil.debug(\"onCreate\"); try { Thread.sleep(12000); } catch (InterruptedException e) { throw new RuntimeException(e); } LogUtil.debug(\"onCreate End\"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { LogUtil.debug(\"onStartCommand\"); return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent intent) { LogUtil.debug(\"onBind\"); return null; }}

点击按钮后,应用ANR异常后的相关日志:

(1)logcat相关日志:
07-01 10:46:21.599 827 1045 I WindowManager: ANR in Window{3fbc2a6 u0 com.liwenzhi.broadcasttest/com.liwenzhi.broadcasttest.MainActivity}. Reason:3fbc2a6 com.liwenzhi.broadcasttest/com.liwenzhi.broadcasttest.MainActivity (server) is not responding. Waited 5000ms for MotionEvent(deviceId=9, eventTime=7839635036000, source=MOUSE, displayId=0, action=HOVER_MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, xCursorPosition=2369.9, yCursorPosition=257.2, pointers=[0: (2369.9, 257.2)]), policyFlags=0x6200000107-01 10:46:22.122 827 1656 I ActivityManager: Dumping to /data/anr/anr_2025-07-01-10-46-22-12107-01 10:46:26.684 827 1656 E ActivityManager: ANR in com.liwenzhi.broadcasttest (com.liwenzhi.broadcasttest/.MainActivity)07-01 10:46:26.685 827 1656 E ActivityManager: 34% 1656/AnrConsumer: 15% user + 18% kernel07-01 10:46:26.687 827 1656 D ActivityManager: Completed ANR of com.liwenzhi.broadcasttest in 5053ms, latency 1ms07-01 10:46:26.722 827 1980 I DropBoxManagerService: add tag=data_app_anr isTagEnabled=true flags=0x6

从上面日志可以看出: Reason:…MainActivity (server) is not responding. Waited 5000ms for MotionEvent.

主要原因就是:Service做了耗时操作,Activity 的点击事件5秒没有得到回应导致。

(2)ANR文件日志:
\"main\" prio=5 tid=1 Sleeping | group=\"main\" sCount=1 ucsCount=0 flags=1 obj=0x73076078 self=0xb4000070cc059380 | sysTid=29339 nice=-10 cgrp=top-app sched=0/0 handle=0x720dd904f8 | state=S schedstat=( 1696950825 243033594 1152 ) utm=146 stm=22 core=7 HZ=100 | stack=0x7fc79bb000-0x7fc79bd000 stackSize=8188KB | held mutexes= at java.lang.Thread.sleep(Native method)... at java.lang.Thread.sleep(Thread.java:355) at com.liwenzhi.broadcasttest.MyService.onCreate(MyService.java:19) //卡死的代码位置 at android.app.ActivityThread.handleCreateService(ActivityThread.java:4510)... at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:943)

上面的ANR堆栈日志,可以看到Service中导致阻塞的代码位置。

6、服务一直for循环

把上面服务中Sleep 的代码替换成大的for循环代码就会出现ANR崩溃报错。

(1)logcat日志:
07-01 09:52:49.169 827 1045 I WindowManager: ANR in Window{ab1f480 u0 com.liwenzhi.broadcasttest/com.liwenzhi.broadcasttest.MainActivity}. Reason:ab1f480 com.liwenzhi.broadcasttest/com.liwenzhi.broadcasttest.MainActivity (server) is not responding. Waited 5003ms for MotionEvent(deviceId=9, eventTime=4627203031000, source=MOUSE, displayId=0, action=HOVER_MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, xCursorPosition=2041.1, yCursorPosition=326.7, pointers=[0: (2041.1, 326.7)]), policyFlags=0x6200000107-01 09:52:49.799 827 8488 I ActivityManager: Dumping to /data/anr/anr_2025-07-01-09-52-49-79807-01 09:52:54.048 827 8488 E ActivityManager: ANR in com.liwenzhi.broadcasttest (com.liwenzhi.broadcasttest/.MainActivity)07-01 09:52:54.048 827 8488 E ActivityManager: 32% 8488/AnrConsumer: 8.1% user + 24% kernel07-01 09:52:54.051 827 8488 D ActivityManager: Completed ANR of com.liwenzhi.broadcasttest in 4848ms, latency 0ms07-01 09:52:54.104 827 8608 I DropBoxManagerService: add tag=data_app_anr isTagEnabled=true flags=0x607-01 09:56:35.537 827 10357 I ActivityManager: Dumping to /data/anr/anr_2025-07-01-09-56-35-53607-01 09:56:35.603 827 10357 E ActivityManager: ANR in com.liwenzhi.broadcasttest07-01 09:56:35.605 827 10357 I ActivityManager: Killing 8776:com.liwenzhi.broadcasttest/u0a69 (adj 0): bg anr07-01 09:56:35.606 827 10357 D ActivityManager: Completed ANR of com.liwenzhi.broadcasttest in 104ms, latency 1ms07-01 09:56:35.607 827 10358 I DropBoxManagerService: add tag=data_app_anr isTagEnabled=true flags=0x6

上面也是能看到 ANR in com.liwenzhi.broadcasttest/.MainActivity;

说明ANR 无响应的界面是 MainActivity,具体的阻塞代码位置需要看堆栈日志。

(2)ANR堆栈日志:
\"main\" prio=5 tid=1 Runnable | group=\"main\" sCount=0 ucsCount=0 flags=0 obj=0x73076078 self=0xb4000070cc059380 | sysTid=8776 nice=0 cgrp=background sched=0/0 handle=0x720dd904f8 | state=R schedstat=( 177918821666 14911248363 122763 ) utm=10908 stm=6883 core=2 HZ=100 | stack=0x7fc79bb000-0x7fc79bd000 stackSize=8188KB | held mutexes= \"mutator lock\"(shared held) native: #00 pc 0000000000554874 /apex/com.android.art/lib64/libart.so ... at java.lang.Throwable.getStackTrace(Throwable.java:845) at com.liwenzhi.broadcasttest.LogUtil.debug(LogUtil.java:73) at com.liwenzhi.broadcasttest.MyService.onCreate(MyService.java:25) //阻塞的具体代码行 at android.app.ActivityThread.handleCreateService(ActivityThread.java:4510) ... at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:943)

上面日志可以看到当前阻塞的状态的运行中,可以清楚看到阻塞的具体代码类和行数。

内容提供者provider,都是类似的日志,这里就不做演示了。

这里没复现到Service和广播类型的阻塞情况,有兴趣的可以自己试试。

示例相关日志的logcat和ANR堆栈日志文件:

https://download.csdn.net/download/wenzhi20102321/91238508

示例演示小结:

(1)为啥这里演示的不同场景ANR都是UI无响应的5秒?
1、因为系统会不定时对应用做成能否响应长操作。2、也可能是我的系统原因,只要触摸了就会做成响应。3、UI操作主线程阻塞的ANR时间是最短的,无论是Service阻塞还是Provider阻塞,都是有很大概率导致UI 5秒ANR异常。
(2)主线程Sleep 5秒必定会造成ANR吗?
(1)主线程(UI 线程)Sleep 5 秒不一定绝对会造成 ANR,但极大概率会触发 ANR;(2)如果只是主线程Sleep,并未操作或者触摸或者打印执行一些操作,可能不会ANR;(3)如果是主线程Sleep过程,进行触摸、主线程打印日志、调用方法等,并且Sleep会超过5秒,都会造成ANR异常。

服务和广播的内部ANR有兴趣的可以自己尝试模拟,比如Sleep前发送延时的Handler等手段。

三、其他

1、ANR分析小结

分析ANR异常主要步骤:

(1)分析logcat日志的anr相关信息(2)pull ANR日志文件到本地,查看堆栈信息,看看能否查看到哪行代码导致的ANR(3)如果上面看不出啥,就查看logcat文件,是否是因为cpu使用过高导致ANR

ANR查看的主要信息:

(1)logcat 过滤 \"anr\" 查看ANR的 \"ANR in\",可以看到ANR的大概类和原因Reason(2)logcat 过滤:ActivityManager: Dumping to ,确定ANR堆栈日志的目录和名称(3)ANR堆栈文件有些情况看到具体哪个类的哪代码错误(4)ANR文件找到第一个主线程堆栈任务,搜索关键字:\"main\" prio= 查看堆栈日志和具体应用相关的代码

网上很多文章都是在 traces.txt 中可以查看堆栈信息,cpu使用情况,ANR原因;

其实不实用了,因为在Android13或者更新的版本已经没有 traces.txt 文件了;

并且cpu使用情况,ANR原因等日志已经默认已经打印在logcat日志中;

生成的ANR堆栈文件的名称和位置需要查看logcat中的anr提示信息确认;

在ANR堆栈文件可以看出是哪行代码导致ANR报错。

上面只是一些简单的ANR情况分析总结,

如果是比较复杂的ANR,有可能logcat比较多,ANR的堆栈文件看不出ANR具体信息;

这种情况就要总结复现手段和出现ANR的规律、logcat详细日志,等一些列思考进行分析解决。

2、检测ANR异常其他手段

  • 使用 Android Studio 的 Profiler:可以查看应用的 CPU、内存和网络活动,帮助识别性能瓶颈。

  • 使用 Traceview 或 Systrace:这些工具可以帮助你分析应用的性能问题。

    # 录制包含ANR场景的systraceadb shell systrace -t 10 -o trace.html sched gfx view input am

运行环境的systrace一般不可用了,Android13 试了一下确实不可用了,因为:

从 Android SDK 29 (Android 10) 开始,Google 已逐步弃用独立的 systrace 脚本,转而推荐使用 Android Studio 内置的 Profiler。若使用较新版本的 SDK,可能需要手动配置路径或使用替代工具。

Systrace 命令已经基本废弃了。

  • Android Studio中打开Profiler 功能

    这个操作使用还比较麻烦,不建议过多依赖;

    不同的系统方案和不同版本的Android Studio可能有差异;

    试了一下选项比较多,主要针对可调试运行的app,复杂的情况不一定能监控到。

  • 自定义代码 ANR 监控

    下面是一段监控主线程是否阻塞主要代码:

public class ANRWatchDog extends Thread { private static final long DEFAULT_ANR_TIMEOUT = 5000; // 5秒 private final Handler handler = new Handler(Looper.getMainLooper()); private final long timeout; public ANRWatchDog(long timeout) { this.timeout = timeout; } @Override public void run() { while (!isInterrupted()) { final long startTime = SystemClock.uptimeMillis(); handler.post(() -> { final long endTime = SystemClock.uptimeMillis(); if (endTime - startTime > timeout) {  Log.e(\"ANR\", \"Main thread is blocked for \" + (endTime - startTime) + \"ms\");  // 上报ANR信息 } }); try { Thread.sleep(timeout); } catch (InterruptedException e) { return; } } }}

试了下,其实是不行的!

所以说辅助手段不一定可靠,主要还是分析查看logcat日志+ANR文件。

3、Google Chome浏览器ANR示例

并不是所有ANR都比较容易定位,比如系统服务,系统弹框,

或者系统应用/Google应用的ANR,不一定能看出哪行代码导致ANR。

下面分享一个Android 原生 Chrome 应用ANR崩溃的问题:

这个问题一般情况不出会出现,复现手段是:系统设置wifi代理,打开浏览器的时候,一直点击浏览器,有很低概率会卡死在代理设置弹框的界面。

Chrome ANR相关的logcat日志:

行 258741: 06-25 02:45:38.965 1033 26937 D ActivityManager: created ANR temporary file:/data/anr/temp_anr_5480422974816270127.txt行 258741: 06-25 02:45:38.965 1033 26937 D ActivityManager: created ANR temporary file:/data/anr/temp_anr_5480422974816270127.txt行 258741: 06-25 02:45:38.965 1033 26937 D ActivityManager: created ANR temporary file:/data/anr/temp_anr_5480422974816270127.txt行 258742: 06-25 02:45:38.965 1033 26937 I ActivityManager: Collecting stacks for pid 26769 into temporary file temp_anr_5480422974816270127.txt行 258744: 06-25 02:45:38.968 1033 26938 I ActivityManager: Dumping to /data/anr/anr_2025-06-25-02-45-38-967行 258744: 06-25 02:45:38.968 1033 26938 I ActivityManager: Dumping to /data/anr/anr_2025-06-25-02-45-38-96706-25 02:45:42.467 1033 26938 I ActivityManager: Done dumping06-25 02:45:42.477 1033 26938 E ActivityManager: ANR in com.android.chrome // ANR in06-25 02:45:42.477 1033 26938 E ActivityManager: PID: 2676906-25 02:45:42.477 1033 26938 E ActivityManager: Reason: No response to onStopJob06-25 02:45:42.477 1033 26938 E ActivityManager: ErrorId: 99eb0b25-2ef0-4413-a34c-aafc0a021afc06-25 02:45:42.477 1033 26938 E ActivityManager: Frozen: false行 261055: 06-25 02:45:42.477 1033 26938 E ActivityManager: ANR in com.android.chrome行 261089: 06-25 02:45:42.477 1033 26938 E ActivityManager: 20% 26939/AnrAuxiliaryTas: 4% user + 16% kernel行 261091: 06-25 02:45:42.477 1033 26938 E ActivityManager: 4% 26938/AnrConsumer: 0% user + 4% kernel行 261104: 06-25 02:45:42.478 1033 26938 D ActivityManager: Completed ANR of com.android.chrome in 3513ms, latency 0ms

上面日志看不出啥,能看出Chrome ANR隐藏,能看出 onStopJob 无法做成响应异常导致ANR;只能寄托ANR堆栈文件能看出啥了。

ANR堆栈日志:

\"main\" prio=5 tid=1 Native | group=\"main\" sCount=1 ucsCount=0 flags=1 obj=0x7259c828 self=0xb4000075c1235010 | sysTid=26769 nice=-10 cgrp=default sched=0/0 handle=0x771ea270a0 | state=S schedstat=( 144172880 16691789 353 ) utm=10 stm=3 core=6 HZ=100 | stack=0x7fd3b22000-0x7fd3b24000 stackSize=8188KB | held mutexes= ... at android.os.BinderProxy.transact(BinderProxy.java:586) at vw1.K(chromium-TrichromeChromeGoogle6432.aab-stable-653310333:18) at Kt3.a(chromium-TrichromeChromeGoogle6432.aab-stable-653310333:3) at It3.onResult(chromium-TrichromeChromeGoogle6432.aab-stable-653310333:16) at org.chromium.base.Callback.N(chromium-TrichromeChromeGoogle6432.aab-stable-653310333:1) at ON.run(chromium-TrichromeChromeGoogle6432.aab-stable-653310333:5) at android.os.Handler.handleCallback(Handler.java:991)... at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:871)DumpLatencyMs: 10.7564

ANR堆栈日志只能看出和Chrome有关,但是里面的类都被混淆了,无法确定是哪个类,所以这种情况就比较麻烦了。

另外目前Google的Chrome 应用并未开源,所以无解?

这个问题我看了一天也没有分析出啥原因,以为是系统哪里影响到了Chrome应用。

后续是更新了Chrome 应用解决了这个问题。

估计因为系统目前已经更新了最新的补丁,但是并未更新相关应用,可能会引起一些问题。