ANR(Application Not Responding):应用程序无响应,是Android中AMS与WMS监测应用响应超时的表现;
我们应用开发中常见的ANR主要有如下几类:
  • 按键触摸事件派发超时ANR,一般阈值为5s(设置中开启ANR弹窗,默认有事件派发才会触发弹框ANR);
  • 广播阻塞ANR,一般阈值为10s(设置中开启ANR弹窗,默认不弹框,只有log提示);
  • 服务超时ANR,一般阈值为20s(设置中开启ANR弹窗,默认不弹框,只有log提示);

ANR的定位与分析

ANR。我的经验是,先看看主线程的堆栈,是否是因为锁等待导致。接着看看 ANR 日志中 iowait、CPU、GC、system server 等信息,进一步确定是 I/O 问题,或是 CPU 竞争问题,还是由于大量 GC 导致卡死。
有的ANR问题表现在应用层,但是未必就是应用所导致的,有的ANR问题是很难分析,所以复现问题路劲也很重要。

当ANR发生时除过logcat可以看见的log以外我们还可以在系统指定目录下找到traces文件进行分析,发生ANR后我们可以通过如下命令得到ANR trace文件:
1.抓取anr logcat : adb shell logcat -v time >D:ybf\Desktop\logcat.txt
1.```adb pull /data/anr/traces.txt ./

//显示进程id、ANR发生时间点、ANR发生进程包名
----- pid 19073 at 2015-10-08 17:24:38 -----
Cmd line: com.example.yanbo.myapplication
//一些GC等object信息,通常可以忽略
......
//ANR方法堆栈打印信息!重点!
DALVIK THREADS (18):
"main" prio=5 tid=1 Sleeping
  | group="main" sCount=1 dsCount=0 obj=0x7497dfb8 self=0x7f9d09a000
  | sysTid=19073 nice=0 cgrp=default sched=0/0 handle=0x7fa106c0a8
  | state=S schedstat=( 125271779 68162762 280 ) utm=11 stm=1 core=0 HZ=100
  | stack=0x7fe90d3000-0x7fe90d5000 stackSize=8MB
  | held mutexes=
  at java.lang.Thread.sleep!(Native method)
  - sleeping on <0x0a2ae345> (a java.lang.Object)
  at java.lang.Thread.sleep(Thread.java:1031)
  - locked <0x0a2ae345> (a java.lang.Object)
//真正导致ANR的问题点,可以发现是onClick中有sleep导致。我们平时可以类比分析即可,这里不详细说明。
  at java.lang.Thread.sleep(Thread.java:985)
  at com.example.yanbo.myapplication.MainActivity$1.onClick(MainActivity.java:21)
  at android.view.View.performClick(View.java:4908)
  at android.view.View$PerformClick.run(View.java:20389)
  at android.os.Handler.handleCallback(Handler.java:815)
  at android.os.Handler.dispatchMessage(Handler.java:104)
  at android.os.Looper.loop(Looper.java:194)
  at android.app.ActivityThread.main(ActivityThread.java:5743)
  at java.lang.reflect.Method.invoke!(Native method)
  at java.lang.reflect.Method.invoke(Method.java:372)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:988)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783)
......
//省略一些不常关注堆栈打印
......
``

例子分析:

anr 分析:表现提示是Launcher anr log原因是Input dispatching timed out
真正原因: Bluetooth 发生anr ,导致在launcher上点击分发超时而引起的anr

Line 224019: 02-27 17:20:57.246 I/am_anr  ( 1129): [0,1562,com.android.Bluetooth,948485701,Broadcast of Intent { act=android.bluetooth.adapter.action.STATE_CHANGED flg=0x14000010 cmp=com.android.Bluetooth/.BootReceiver (has extras) }]
	Line 224033: 02-27 17:20:57.410 I/art     ( 1562): Wrote stack traces to '/data/anr/traces.txt'
	Line 224034: 02-27 17:20:57.413 E/ActivityManager( 1129): ANR in com.android.Bluetooth
	Line 224103: 02-27 17:20:57.414 I/ActivityManager( 1129): Killing 1562:com.android.Bluetooth/1000 (adj 0): bg anr
	Line 224104: 02-27 17:20:57.414 I/am_kill ( 1129): [0,1562,com.android.Bluetooth,0,bg anr]
	Line 224719: 02-27 17:21:02.733 I/am_anr  ( 1129): [0,1440,com.android.launcher,948485701,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: 10.  Wait queue head age: 5708.6ms.)]
	Line 224728: 02-27 17:21:02.808 I/art     ( 1440): Wrote stack traces to '/data/anr/traces.txt'
	Line 224827: 02-27 17:21:03.272 I/art     ( 1129): Wrote stack traces to '/data/anr/traces.txt'
	Line 224838: 02-27 17:21:03.329 I/art     ( 1470): Wrote stack traces to '/data/anr/traces.txt'
	Line 224840: 02-27 17:21:03.381 I/art     ( 1993): Wrote stack traces to '/data/anr/traces.txt'
	Line 224843: 02-27 17:21:03.420 I/art     ( 1982): Wrote stack traces to '/data/anr/traces.txt'
	Line 224848: 02-27 17:21:03.485 I/art     ( 1965): Wrote stack traces to '/data/anr/traces.txt'
	Line 224854: 02-27 17:21:03.521 I/art     ( 1953): Wrote stack traces to '/data/anr/traces.txt'
	Line 224873: 02-27 17:21:03.566 I/art     ( 1937): Wrote stack traces to '/data/anr/traces.txt'
	Line 224902: 02-27 17:21:03.826 I/art     (24434): Wrote stack traces to '/data/anr/traces.txt'
	Line 224965: 02-27 17:21:03.943 I/art     ( 1419): Wrote stack traces to '/data/anr/traces.txt'
	Line 224971: 02-27 17:21:03.984 I/art     ( 1337): Wrote stack traces to '/data/anr/traces.txt'
	Line 224973: 02-27 17:21:04.052 I/art     ( 1321): Wrote stack traces to '/data/anr/traces.txt'
	Line 224978: 02-27 17:21:04.194 I/art     (24528): Wrote stack traces to '/data/anr/traces.txt'
	Line 225191: 02-27 17:21:06.265 E/ActivityManager( 1129): ANR in com.android.launcher (com.android.launcher/com.android.launcher.ActivityMain)
	
	
	traces.log 
	查看主线程,Bluetoothservice 中有耗时操作
	"main" prio=5 tid=1 Blocked
  | group="main" sCount=1 dsCount=0 obj=0x743d3518 self=0xf1204400
  | sysTid=29718 nice=0 cgrp=default sched=0/0 handle=0xf3ef6534
  | state=S schedstat=( 190057444 184697495 310 ) utm=16 stm=3 core=2 HZ=100
  | stack=0xff283000-0xff285000 stackSize=8MB
  | held mutexes=
  at com.android.bluetooth.Bluetoothservice.AdapterProperties.sendConnectionStateChange(AdapterProperties.java:336)
  - waiting to lock <0x0d1ebc9a> (a java.lang.Object) held by thread 10
  at com.android.bluetooth.Bluetoothservice.AdapterService.sendConnectionStateChange(AdapterService.java:2513)
  at com.android.bluetooth.Bluetoothservice.AdapterService$AdapterServiceBinder.sendConnectionStateChange(AdapterService.java:1486)
  at com.android.bluetooth.Bluetoothservice.AdapterService.processProfileStateChanged(AdapterService.java:371)
  at com.android.bluetooth.Bluetoothservice.AdapterService.-wrap10(AdapterService.java:-1)
  at com.android.bluetooth.Bluetoothservice.AdapterService$1.handleMessage(AdapterService.java:845)
  at android.os.Handler.dispatchMessage(Handler.java:102)
  at android.os.Looper.loop(Looper.java:154)
  at android.app.ActivityThread.main(ActivityThread.java:6121)
  at java.lang.reflect.Method.invoke!(Native method)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
OK,ANR分析结束。

1,输出ANR Reason信息到Events log中,关键字是am_anr,一般都是用这个信息来确定Anr的发生时间
2、ANR有两种,前台ANR和后台ANR,我在调试中发现,后台ANR非常容易发生,系统直接kill掉这个应用进程,但是用户没有感知。
3、am_anr关键字比ANR in要先打印,所以更接近ANR的实际发生时间

避免ANR最核心的一点就是在主线程减少耗时操作。通常需要从那个以下几个方案下手:
a)使用子线程处理耗时IO操作
b)降低子线程优先级,使用Thread或者HandlerThread时,调用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,否则仍然会降低程序响应,因为默认Thread的优先级和主线程相同
c)使用Handler处理子线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程
d)Activity的onCreate和onResume回调中尽量避免耗时的代码
e)BroadcastReceiver中onReceiver代码也要尽量减少耗时操作,建议使用intentService处理。intentService是一个异步的,会自动停止的服务,很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题