Android ANR分析总结
Android ANR分析总结
文章目录
- Android ANR分析总结
-
- 一、前言
-
- 1、什么是 ANR?为什么会发生 ANR?
- 2、系统对ANR的检测机制
- 二、ANR分析思路
- 三、真机模拟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 的四种(四大组件:界面、广播、服务、内容提供者)场景及超时时间:
注意:不同 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
S
D
Z
T
W
X
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 应用解决了这个问题。
估计因为系统目前已经更新了最新的补丁,但是并未更新相关应用,可能会引起一些问题。