ANR分析


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)


 


 

你可能感兴趣的:(android)