1. ANR的来源
系统判定一个APP无响应的几个条件包括:
控制Service/Activity/Provider超时、接收广播超时、响应按键/触屏事件超时等。
从系统设计角度来分析,以上这些事件都是给APP主线程发消息,可见这些超时实际都是消息没有在APP的主线程及时处理导致的。
消息没有处理有三种可能:
a. 消息没有发送到主线程的消息队列中
b. 主线程还在执行前面的或优先级高的消息,来不及处理已经入队的消息
c. 当前系统忙,APP得不到CPU时间来处理消息循环
从应用角度来看,a和c两种情形是无法分辨的,都表现为主线程空闲,但系统报ANR,需要在系统中增加主线程消息队列的dump才能区分这两者。情形b表现为主线程正在工
作,处在某个事件处理的调用堆栈中。只有情形b是真正的ANR,其他的是误报,APP本身是无辜的。
2. 系统对ANR的处理
系统监测到上面的超时条件时,会给APP发一个信号,让其signalCatcher 线程开始打印各个线程的堆栈,并将这些堆栈信息输出到一个trace.txt文件中作为ANR发生时的现场记
录。这个log中还有当前SystemServer等系统进程的线程快照,用于辅助分析。这是我们分析ANR的依据。由于ANR发生到trace文件生成有一个时间间隔,因此抓到的现场并不
总是准确的,尤其是系统繁忙的时候。
3. 分析ANR
首先当然是要拿到trace文件,不然无法开始分析。以下为例:
打开trace.txt,每个进程都是用类似下面的形式开头的
----- pid 12628 at 2016-05-28 07:10:37 -----
Cmd line: com.google.android.gms.persistent
通过Cmd line后面的包名可以确定需要分析的进程
找到main线程,这个是关键,其堆栈为
native: #00 pc 0000000000068460 /system/lib64/libc.so (__ioctl+4)
native: #01 pc 0000000000072488 /system/lib64/libc.so (ioctl+100)
native: #02 pc 000000000002d498 /system/lib64/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+164)
native: #03 pc 000000000002df70 /system/lib64/libbinder.so (android::IPCThreadState::waitForResponse(android::Parcel*, int*)+104)
native: #04 pc 000000000002e1e4 /system/lib64/libbinder.so (android::IPCThreadState::transact(int, unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+176)
native: #05 pc 00000000000255f4 /system/lib64/libbinder.so (android::BpBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+64)
native: #06 pc 00000000000e12a4 /system/lib64/libandroid_runtime.so (???)
native: #07 pc 00000000013781a4 /system/framework/arm64/boot.oat (Java_android_os_BinderProxy_transactNative__ILandroid_os_Parcel_2Landroid_os_Parcel_2I+200)
at android.os.BinderProxy.transactNative(Native method)
at android.os.BinderProxy.transact(Binder.java:503)
at android.net.wifi.IWifiManager$Stub$Proxy.getSupportedFeatures(IWifiManager.java:800)
at android.net.wifi.WifiManager.getSupportedFeatures(WifiManager.java:1025)
at android.net.wifi.WifiManager.isFeatureSupported(WifiManager.java:1032)
at android.net.wifi.WifiManager.isWifiScannerSupported(WifiManager.java:1071)
at com.google.android.location.places.i.k.
(:com.google.android.gms:155)
at com.google.android.location.places.service.aa.(:com.google.android.gms:157)
at com.google.android.location.places.service.PlaceDetectionService.onCreate(:com.google.android.gms:46)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2905)
可以看到主线程在执行PlaceDetectionService.onCreate方法,
其内部通过Binder IPC 调用了IWifiManager.getSupportedFeatures,Binder IPC是同步调用,服务进程没有执行完成并返回,本地调用线程就一直阻塞,这个阻塞的时间超过时
限,系统就报ANR错误。到这里分析并未完成,我们还需要找出为何服务端执行getSupportedFeatures会如此耗时,以致不能在ANR时限内完成。
Android系统的设计惯例是客户端的XxxManager.Yyy方法都有一个服务端的Service的方法也叫Yyy,我们再在其他进程中找这个getSupportedFeatures,看看是否在工作。如果
不在工作则可能是服务端的binder线程繁忙,需要进行其他分析。这个log里正好它在工作
"Binder_7" prio=5 tid=71 Waiting
| group="main" sCount=1 dsCount=0 obj=0x13f490a0 self=0x7f6d586600
| sysTid=24777 nice=0 cgrp=default sched=0/0 handle=0x7f6b5c0440
| state=S schedstat=( 131233911 267857403 640 ) utm=8 stm=5 core=0 HZ=100
| stack=0x7f6b4c4000-0x7f6b4c6000 stackSize=1013KB
| held mutexes=
at java.lang.Object.wait!(Native method)
- waiting on <0x05a8cc8a> (a java.lang.Object)
at com.android.internal.util.AsyncChannel$SyncMessenger.sendMessageSynchronously(AsyncChannel.java:820)
- locked <0x05a8cc8a> (a java.lang.Object)
at com.android.internal.util.AsyncChannel$SyncMessenger.access$100(AsyncChannel.java:740)
at com.android.internal.util.AsyncChannel.sendMessageSynchronously(AsyncChannel.java:654)
at com.android.internal.util.AsyncChannel.sendMessageSynchronously(AsyncChannel.java:667)
at com.android.server.wifi.WifiStateMachine.syncGetSupportedFeatures(WifiStateMachine.java:2373)
at com.android.server.wifi.WifiServiceImpl.getSupportedFeatures(WifiServiceImpl.java:751)
at android.net.wifi.IWifiManager$Stub.onTransact(IWifiManager.java:53)
at android.os.Binder.execTransact(Binder.java:453)
该线程在system_server进程中,它阻塞在WifiStateMachine.syncGetSupportedFeatures这个方法调用中,这个方法内部会通过一个AsyncChannel来给另外一个进程发送同步消
息并等待返回。WifiStateMachine和另外一个进程之间的交互是WIFI模块内部的逻辑,至此我们可以得出结论是WIFI模块出问题了,我们可以继续分析下去或交给WIFI模块的负
责人进行更进一步的分析。以上ANR发生的原因是主线程未能及时处理Service控制消息的情形,而对于情形a或c,主线程是空闲的,只是在等待消息队列中有消息,其堆栈就
是下面的样子:
native: #00 pc 0000000000068374 /system/lib64/libc.so (__epoll_pwait+8)
native: #01 pc 000000000001f3a4 /system/lib64/libc.so (epoll_pwait+32)
ntive: #02 pc 000000000001ad74 /system/lib64/libutils.so (android::Looper::pollInner(int)+144)
native: #03 pc 000000000001b154 /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+80)
native: #04 pc 00000000000d3104 /system/lib64/libandroid_runtime.so (android::NativeMessageQueue::pollOnce(_JNIEnv*, _jobject*, int)+48)
native: #05 pc 000000000000550c /system/framework/arm64/boot.oat (Java_android_os_MessageQueue_nativePollOnce__JI+144)
at android.os.MessageQueue.nativePollOnce(Native method)
at android.os.MessageQueue.next(MessageQueue.java:324)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5519)
所有的HandlerThread空闲时的堆栈都是上面这个样子
下面列出了一般常见的线程空闲的情形,我们可以通过简单的判断快速分析某个线程是否参与某项工作。注意看以下堆栈的栈顶方法。
binder线程空闲堆栈
native: #00 pc 0000000000068460 /system/lib64/libc.so (__ioctl+4)
native: #01 pc 0000000000072488 /system/lib64/libc.so (ioctl+100)
native: #02 pc 000000000002d498 /system/lib64/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+164)
native: #03 pc 000000000002dcf8 /system/lib64/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+24)
native: #04 pc 000000000002de14 /system/lib64/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+76)
AsyncTask线程空闲堆栈
at java.lang.Object.wait!(Native method)
- waiting on <0x00173e03> (a java.lang.Object)
at java.lang.Thread.parkFor$(Thread.java:1220)
- locked <0x00173e03> (a java.lang.Object)
at sun.misc.Unsafe.park(Unsafe.java:299)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2013)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:410
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1036)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1098)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
SocketServer线程空闲堆栈
at libcore.io.Posix.accept(Native method)
at libcore.io.BlockGuardOs.accept(BlockGuardOs.java:63)
at android.system.Os.accept(Os.java:43)