当前位置:   article > 正文

Android-ANR总结原理_reason: input dispatching timed out (waiting to se

reason: input dispatching timed out (waiting to send non-key event because t

一:什么是ANR

ANR:Application Not Responding,即应用程序无响应

一般在ANR的时候会弹出一个应用无响应对话框,同时会候产生一个日志文件trace.txt,位于/data/anr/文件夹下面,trace文件是Android Davik虚拟机在收到异常终止信号时产生的,最常见的一个触发条件就是Android应用中产生了FC(force close)。由于该文件的产生是在DVM中的,所以只有运行DVM实例的进程才能产生该文件,也就是说只有Java代码才能产生该文件,App应用的Native层(如Android Library、用c/c++编译的库)即使异常也不会产生ANR日志文件。我们可以通过ANR产生的traces日志文件分析应用在哪里产生了ANR,以此来有效解决应用中的ANR。
 

二:ANR的原因和类型

只有当应用程序的UI线程响应超时才会引起ANR。超时时间的计数一般是从按键分发给app开始。超时的原因一般有两种:

(1)当前的事件没有机会得到处理(即UI线程正在处理前一个事件,没有及时的完成或者looper被某种原因阻塞住了)

(2)当前的事件正在处理,但没有及时完成

 

根据ANR产生的原因不同,超时时间也不尽相同,从本质上讲,产生ANR的原因有三种,大致可以对应到Android中四大组件中的三个(Activity、BroadcastReceive、Service)。ANR一般有三种类型:

1. KeyDispatchTimeout(5 seconds) --最常见的一种类型,原因是View事件或者触摸事件在特定时间内(5s)无法得到响应

2. BroadcastTimeout(10 seconds) --BroadcastReceiver的onReceive函数运行在主线程,并在特定的时间内(10s)无法完成处理

3. ServiceTimeout(20 seconds) --小概率类型 Service的各个生命周期函数在特定时间内(20s)无法完成响应

三:典型的ANR场景

1)主线程频繁进行IO操作,比如读写文件或者数据库; 
2)硬件操作如进行调用照相机或者录音等操作; 
3)多线程操作的死锁,导致主线程等待超时; 
4)主线程操作调用join()方法、sleep()方法或者wait()方法; 
5)耗时动画/耗资源行为导致CPU负载过重 
6)system server中发生WatchDog ANR; 
7)service binder的数量达到上限

四:KeyDispatchTimeout

Akey or touch event was not dispatched within the specified time(按键或触摸事件在特定时间内无响应)

具体的超时时间的定义在framework下的ActivityManagerService.java

//How long we wait until we timeout on key dispatching.

staticfinal int KEY_DISPATCHING_TIMEOUT = 5*1000

-------如何避免KeyDispatchTimeout

1. UI线程尽量只做跟UI相关的工作

2. 耗时的工作(比如数据库操作,I/O,连接网络或者别的有可能阻碍UI线程的操作)把它放入单独的线程处理

3. 尽量用Handler来处理UIthread和别的thread之间的交互

-------UI线程

说了那么多的UI线程,那么哪些属于UI线程呢?

UI线程主要包括如下:

1. Activity:onCreate(), onResume(), onDestroy(), onKeyDown(), onClick(),etc

2. AsyncTask: onPreExecute(), onProgressUpdate(), onPostExecute(), onCancel,etc

3. Mainthread handler: handleMessage(), post*(runnable r), etc

4. other

五:ANR的定位和分析

1)Logcat分析

查询关键字(ANR|ActivityManager) 

è¿éåå¾çæè¿°

  1. /system_process E/ActivityManager:
  2. ANR in admanager.lbjfan.com.anrdemo (admanager.lbjfan.com.anrdemo/.MainActivity)
  3.                                                              PID: 12639
  4.                                                              Reason: 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: 6.  Wait queue head age: 5841.3ms.)
  5.                                                              Load: 13.28 / 11.53 / 9.48
  6.                                                              CPU usage from 71228ms to 0ms ago (1970-03-01 00:08:47.864 to 1970-03-01 00:09:59.093):
  7.                                                                15% 920/system_server: 9.2% user + 5.9% kernel / faults: 10139 minor 285 major
  8.                                                                8.2% 13985/com.tencent.mm: 6.5% user + 1.6% kernel / faults: 35481 minor 1879 major
  9.                                                                0.1% 555/fingerprintd: 0% user + 0.1% kernel / faults: 51 minor 22 major
  10.                                                                3.5% 266/mmcqd/0: 0% user + 3.5% kernel
  11.                                                                3.2% 4424/com.tencent.android.qqdownloader:daemon: 1.7% user + 1.5% kernel / faults: 12007 minor 357 major
  12.                                                                3.2% 430/adbd: 0.4% user + 2.7% kernel / faults: 2002 minor
  13.                                                                3.1% 135/kswapd0: 0% user + 3.1% kernel
  14.                                                                1.8% 12271/com.tencent.mobileqq: 1.2% user + 0.5% kernel / faults: 8799 minor 580 major
  15.                                                                1.6% 11695/com.cleanmaster.mguard: 1.5% user + 0.1% kernel / faults: 9171 minor 72 major
  16.                                                                1.3% 13039/com.tencent.mm:push: 0.9% user + 0.3% kernel / faults: 9969 minor 192 major
  17.                                                                1.2% 4954/com.google.android.gms: 0.9% user + 0.2% kernel / faults: 7546 minor 209 major
  18.                                                                1.1% 342/logd: 0.3% user + 0.8% kernel / faults: 628 minor 3 major
  19.                                                                1.1% 1485/kworker/u13:3: 0% user + 1.1% kernel
  20.                                                                1.1% 10/rcu_preempt: 0% user + 1.1% kernel
  21.                                                                1.1% 12166/com.android.vending: 0.8% user + 0.3% kernel / faults: 9897 minor 380 major
  22.                                                                1% 3846/com.tencent.qqmusic:QQPlayerService: 0.6% user + 0.4% kernel / faults: 7354 minor 485 major
  23.                                                                1% 10486/kworker/u13:4: 0% user + 1% kernel
  24.                                                                1% 11251/kworker/u13:1: 0% user + 1% kernel
  25.                                                                1% 9498/com.cleanmaster.security:DefendService: 0.7% user + 0.3% kernel / faults: 11998 minor 287 major
  26.                                                                0.9% 1973/kworker/u13:5: 0% user + 0.9% kernel
  27.                                                                0.9% 14113/com.tencent.mm:exdevice: 0.7% user + 0.1% kernel / faults: 8802 minor 142 major
  28.                                                                0.8% 10814/com.tencent.qqmusic: 0.4% user + 0.4% kernel / faults: 9823 minor 221 major
  29.                                                                0.8% 2062/sogou.mobile.explorer: 0.5% user + 0.3% kernel / faults: 8532 minor 1288 major
  30.                                                                0.8% 528/netd: 0.1% user + 0.7% kernel / faults: 4203 minor 35 major
  31.                                                                0.8% 3925/com.google.android.gms.persistent: 0.4% user + 0.3% kernel / faults: 12578 minor 546 major
  32.                                                                0.7% 556/cnss_diag: 0.6% user + 0% kernel / faults: 121 minor 5 major
  33.                                                                0.6% 4971/com.cleanmaster.mguard:service: 0.4% user + 0.2% kernel / faults: 7468 minor 174 major
  34.                                                                0.5% 9180/com.tencent.android.qqdownloader: 0.2% user + 0.3% kernel / faults: 9571 minor 216 major
  35.                                                                0.5% 15/ksoftirqd/1: 0% user + 0.5% kernel
  36.                                                                0.4% 3280/com.android.phone: 0.2% user + 0.2% kernel / faults: 1857 minor 133 major
  37.                                                                0.4% 8489/kworker/0:1: 0% user + 0.4% kernel
  38.                                                                0.4% 3127/sdcard: 0% user + 0.4% kernel / faults: 92 minor 17 major
  39.                                                                0.4% 397/servicemanager: 0.1% user + 0.2% kernel / faults: 127 minor
  40.                                                                0.4% 11878/swift.space.cleaner.free:service: 0.2% user + 0.1% kernel / faults: 6087 minor 140 major
  41.                                                                0.4% 20/ksoftirqd/2: 0% user + 0.4% kernel
  42.                                                                0.4% 8761/com.netease.cloudmusic:play: 0.3% user + 0% kernel / faults: 4819 minor 977 major
  43.                                                                0.3% 6525/com.tencent.qqlive:services: 0.2% user + 0.1% kernel / faults: 7834 minor 483 major
  44.                                                                0.3% 12250/com.tencent.mobileqq:MSF: 0.2% user + 0.1% kernel / faults: 5368 minor 114 major
  45.                                                                0.3% 9717/com.speed.boost.booster:service: 0.1% user + 0.1% kernel / faults: 5526 minor 77 major
  46.                                                                0.3% 8524/sogou.mobile.explorer:push_service: 0.2% user + 0.1% kernel / faults: 6280 minor 42 major
  47.                                                                0.3% 427/irq/215-fc38800: 0% user + 0.3% kernel
  48.                                                                0.3% 8721/kworker/1:2: 0% user + 0.3% kernel
  49.                                                                0.3% 260/cfinteractive: 0% user + 0.3% kernel
  50.                                                                0.3% 294/msm-core:sampli: 0% user + 0.3% kernel
  51.                                                                0.1% 8756/kworker/u12:3: 0% user + 0.1% kernel
  52.                                                                0.1% 11204/kworker/2:0: 0% user + 0.1% kernel
  53.                                                                0.3% 3150/com.android.systemui: 0.1% user + 0.1% kernel / faults: 3318 minor 129 major
  54.                                                                0.2% 7244/kworker/u12:2: 0% user + 0.2% kernel
  55.                                                                0% 3084/VosMCThread: 0% user + 0% kerne


可以看到,Logcat日志信息中主要包含如下内容:

1)导致ANR的类名及所在包名: 
admanager.lbjfan.com.anrdemo (admanager.lbjfan.com.anrdemo/.MainActivity)

2)导致ANR的进程名及ID:admanager.lbjfan.com.anrdemo,12639

3)ANR产生的原因(类型):Reason: 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: 6. Wait queue head age: 5841.3ms.),明显属于KeyDispatchTimeout类型。

4)系统中CPU使用率的统计信息及某段时间内的变换情况

2).从trace.txt文件分析

ANR Logcat信息可以帮助我们分析引发ANR的具体类的信息以及ANR的类型,但是却无法帮助我们定位到具体引发问题的代码行,这时候就需要借助ANR发生过程中生成的堆栈信息文件data/anr/trace.txt

获取trace文件:adb pull /data/anr/trace.txt

trace.txt文件分析

由于trace文件记录的是整个手机的ANR日志,所以我们需要根据进程名(包名)和ANR发生的时间找到对应日志,具体以pid 进程id开始,以pid进程id结束。由于阻塞始终会发生在主线程,因此我们需要关注 
线程名为main的线程状态。下面摘出一部分关键日志进行分析:

  1. //关键日志的起始标记
  2. ----- pid 20678 at 2018-08-13 21:58:59 -----
  3. //应用程序包名
  4. Cmd line: admanager.lbjfan.com.anrdemo
  5. Build fingerprint: 'Android/aosp_bullhead/bullhead:7.1.2/N2G48C/han-li03221443:userdebug/test-keys'
  6. //手机的CPU架构
  7. ABI: 'arm64'
  8. //堆内存信息
  9. Heap: 33% free, 4MB/6MB; 27144 objects
  10. Dumping cumulative Gc timings
  11. Total time spent in GC: 10.680ms
  12. Mean GC size throughput: 68MB/s
  13. Mean GC object throughput: 1.32996e+06 objects/s
  14. Total number of allocations 41348
  15. Total bytes allocated 5MB
  16. Total bytes freed 753KB
  17. //手机Memory内存信息
  18. Free memory 2MB
  19. Free memory until GC 2MB
  20. Free memory until OOME 187MB
  21. Total memory 6MB
  22. Max memory 192MB
  23. Zygote space size 1128KB
  24. Total mutator paused time: 463us
  25. Total time waiting for GC to complete: 938ns
  26. Total GC count: 1
  27. Total GC time: 10.680ms
  28. Total blocking GC count: 0
  29. Total blocking GC time: 0
  30. //主线程日志分析
  31. //基本信息:main-线程名称,prio-线程优先级,tid-线程id,Sleeping-线程状态
  32. "main" prio=5 tid=1 Sleeping
  33.   //详细信息:group-线程组名称,sCount-线程被挂起的次数,dsCount-线程被调试器刮起的次数,obj-线程的Java对象地址,self-线程本身的Native对象地址
  34.   | group="main" sCount=1 dsCount=0 obj=0x75190ed0 self=0x7f72095a00
  35.   //线程的调度信息:sysTid-linux系统中内核线程id(观察发现主线程的线程号和进程号相同),nice-线程调度的优先级,cgrp-线程调度组,sched-线程调度策略和优先级,handle-线程处理函数地址
  36.   | sysTid=20678 nice=-10 cgrp=default sched=0/0 handle=0x7f75fe0a98
  37.   //上下文信息:state-线程调度状态,schedstat-线程在CPU中的执行时间、线程等待时间、线程执行的时间片长度,utm-线程在用户状态中调度的时间值,core-最后执行这个线程的CPU核序号
  38.   | state=S schedstat=( 274637713 30817705 229 ) utm=20 stm=6 core=1 HZ=100
  39.   //堆栈信息:stack-堆栈地址,stackSize-堆栈大小,余下的为堆栈信息,也是我们分析引发ANR问题的关键
  40.   | stack=0x7fc8318000-0x7fc831a000 stackSize=8MB
  41.   | held mutexes=
  42.   at java.lang.Thread.sleep!(Native method)
  43.   - sleeping on <0x02f69763> (a java.lang.Object)
  44.   at java.lang.Thread.sleep(Thread.java:371)
  45.   - locked <0x02f69763> (a java.lang.Object)
  46.   at java.lang.Thread.sleep(Thread.java:313)
  47.   at admanager.lbjfan.com.anrdemo.MainActivity$1.onClick(MainActivity.java:24)
  48.   at android.view.View.performClick(View.java:5637)
  49.   at android.view.View$PerformClick.run(View.java:22429)
  50.   at android.os.Handler.handleCallback(Handler.java:751)
  51.   at android.os.Handler.dispatchMessage(Handler.java:95)
  52.   at android.os.Looper.loop(Looper.java:154)
  53.   at android.app.ActivityThread.main(ActivityThread.java:6121)
  54.   at java.lang.reflect.Method.invoke!(Native method)
  55.   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
  56.   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
  57. "Jit thread pool worker thread 0" daemon prio=5 tid=2 Native
  58.   | group="main" sCount=1 dsCount=0 obj=0x12c64790 self=0x7f6a635000
  59.   | sysTid=20683 nice=9 cgrp=default sched=0/0 handle=0x7f71701450
  60.   | state=S schedstat=( 696978 5677 2 ) utm=0 stm=0 core=2 HZ=100
  61.   | stack=0x7f71603000-0x7f71605000 stackSize=1021KB
  62.   | held mutexes=
  63.   kernel: __switch_to+0x8c/0x98
  64.   kernel: futex_wait_queue_me+0xd4/0x130
  65.   kernel: futex_wait+0xfc/0x210
  66.   kernel: do_futex+0xe0/0x920
  67.   kernel: SyS_futex+0x11c/0x1b0
  68.   kernel: cpu_switch_to+0x48/0x4c
  69.   native: #00 pc 000000000001bcec  /system/lib64/libc.so (syscall+28)
  70.   native: #01 pc 00000000000e7e4c  /system/lib64/libart.so (_ZN3art17ConditionVariable16WaitHoldingLocksEPNS_6ThreadE+156)
  71.   native: #02 pc 000000000046c910  /system/lib64/libart.so (_ZN3art10ThreadPool7GetTaskEPNS_6ThreadE+248)
  72.   native: #03 pc 000000000046bdac  /system/lib64/libart.so (_ZN3art16ThreadPoolWorker3RunEv+124)
  73.   native: #04 pc 000000000046b6d0  /system/lib64/libart.so (_ZN3art16ThreadPoolWorker8CallbackEPv+132)
  74.   native: #05 pc 0000000000068734  /system/lib64/libc.so (_ZL15__pthread_startPv+208)
  75.   native: #06 pc 000000000001da7c  /system/lib64/libc.so (__start_thread+16)
  76.   (no managed stack frames)
  77. //关键日志的结束标记
  78. ----- end 20678 -----

由于ANR只会发生在主线程,所以我们需要关注主线程的状态,从上 面日志中分析可以知道:发生ANR时主线程的状态为Sleep,且引起该状态的地方在MainActivity$1.onClick(MainActivity.java:24) 

è¿éåå¾çæè¿°


3)使用AndroidStudio分析工具

有时候查看trace文件是及其困难的,很难定位到具体的代码位置,这时候就可以借助AndroidStudio提供的工具:Analyze-AnalyzeStacktrace,然后添加得到的trace,如下:

è¿éåå¾çæè¿°

5.ANR源码分析

下面分析Service内onCreate发生ANR异常时源代码的执行情况

大家都知道Android中的四大组件启动时,都会通过跨进程的方式利用Handler消息机制最终将消息Push到ActivityThread中的内部类去处理,因此我先在ActivityThread中搜索service.onCreate调用,然后依次追溯:

注:下面均以删除无关代码

ActivityThread中调用: 

  1. private void handleCreateService(CreateServiceData data) {
  2.             //调用service的onCreate
  3.             service.onCreate();
  4.     }

该方法由Activity的内部类H(继承与Handler)接收到Servic onCreate消息时调用,该消息由通过scheduleCreateService发出,该方法被ActiveService类调用

  1.         public final void scheduleCreateService(IBinder token,
  2.                 ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
  3.             updateProcessState(processState, false);
  4.             CreateServiceData s = new CreateServiceData();
  5.             s.token = token;
  6.             s.info = info;
  7.             s.compatInfo = compatInfo;
  8.             sendMessage(H.CREATE_SERVICE, s);
  9.         }


ActiveServicde的realStartServiceLocked方法调用上面方法,这个方法比较关键需要认真分析:

  1. private final void realStartServiceLocked(ServiceRecord r,
  2.             ProcessRecord app, boolean execInFg) throws RemoteException {
  3.         r.app = app;
  4.         r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
  5.         final boolean newService = app.services.add(r);
  6.         //发送delay消息(SERVICE_TIMEOUT_MSG)
  7.         bumpServiceExecutingLocked(r, execInFg, "create");
  8.         mAm.updateLruProcessLocked(app, false, null);
  9.         updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
  10.         mAm.updateOomAdjLocked();
  11.         boolean created = false;
  12.         try {
  13.             synchronized (r.stats.getBatteryStats()) {
  14.                 r.stats.startLaunchedLocked();
  15.             }
  16.             mAm.notifyPackageUse(r.serviceInfo.packageName,
  17.                                  PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
  18.             app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
  19.             //最终执行服务的onCreate()方法
  20.             app.thread.scheduleCreateService(r, r.serviceInfo,
  21.                     mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
  22.                     app.repProcState);
  23.             r.postNotification();
  24.             created = true;
  25.         } catch (DeadObjectException e) {
  26.             Slog.w(TAG, "Application dead when creating service " + r);
  27.             mAm.appDiedLocked(app);
  28.             throw e;
  29.         } finally {
  30.             if (!created) {
  31.                 // Keep the executeNesting count accurate.
  32.                 final boolean inDestroying = mDestroyingServices.contains(r);
  33.                 //当service启动完毕,则remove SERVICE_TIMEOUT_MSG消息
  34.                 serviceDoneExecutingLocked(r, inDestroying, inDestroying);
  35.                 // Cleanup.
  36.                 if (newService) {
  37.                     app.services.remove(r);
  38.                     r.app = null;
  39.                 }
  40.                 // Retry.
  41.                 if (!inDestroying) {
  42.                     scheduleServiceRestartLocked(r, false);
  43.                 }
  44.             }
  45.         }
  46.         if (r.whitelistManager) {
  47.             app.whitelistManager = true;
  48.         }
  49.         requestServiceBindingsLocked(r, execInFg);
  50.         updateServiceClientActivitiesLocked(app, null, true);
  51.         // If the service is in the started state, and there are no
  52.         // pending arguments, then fake up one so its onStartCommand() will
  53.         // be called.
  54.         if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
  55.             r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
  56.                     null, null, 0));
  57.         }
  58.         sendServiceArgsLocked(r, execInFg, true);
  59.     }


bumpServiceExecutingLocked方法内又调用了scheduleServiceTimeoutLocked方法:

  1.     void scheduleServiceForegroundTransitionTimeoutLocked(ServiceRecord r) {
  2.         if (r.app.executingServices.size() == 0 || r.app.thread == null) {
  3.             return;
  4.         }
  5.         //指定id为SERVICE_TIMEOUT_MSG的消息
  6.         Message msg = mAm.mHandler.obtainMessage(
  7.                 ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG);
  8.         msg.obj = r;
  9.         r.fgWaiting = true;
  10.         //前台Service和后台Service发送的Delay消息时间不同
  11.         mAm.mHandler.sendMessageDelayed(msg, SERVICE_START_FOREGROUND_TIMEOUT);
  12.     }


serviceDoneExecutingLocked方法

  1.     private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
  2.             boolean finishing) {
  3.         r.executeNesting--;
  4.         if (r.executeNesting <= 0) {
  5.             if (r.app != null) {
  6.                 if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
  7.                         "Nesting at 0 of " + r.shortName);
  8.                 r.app.execServicesFg = false;
  9.                 r.app.executingServices.remove(r);
  10.                 if (r.app.executingServices.size() == 0) {
  11.                     if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
  12.                             "No more executingServices of " + r.shortName);
  13.                    //remove掉id为SERVICE_TIMEOUT_MSG的消息,从上面的分析可知,该方法是onCreate调用之前发出的一个Delay执行的消息
  14.                    mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
  15.                 } else if (r.executeFg) {
  16.                     // Need to re-evaluate whether the app still needs to be in the foreground.
  17.                     for (int i=r.app.executingServices.size()-1; i>=0; i--) {
  18.                         if (r.app.executingServices.valueAt(i).executeFg) {
  19.                             r.app.execServicesFg = true;
  20.                             break;
  21.                         }
  22.                     }
  23.                 }
  24.                 if (inDestroying) {
  25.                     mDestroyingServices.remove(r);
  26.                     r.bindings.clear();
  27.                 }
  28.                 mAm.updateOomAdjLocked(r.app, true);
  29.             }
  30.             r.executeFg = false;
  31.             if (r.tracker != null) {
  32.                 r.tracker.setExecuting(false, mAm.mProcessStats.getMemFactorLocked(),
  33.                         SystemClock.uptimeMillis());
  34.                 if (finishing) {
  35.                     r.tracker.clearCurrentOwner(r, false);
  36.                     r.tracker = null;
  37.                 }
  38.             }
  39.             if (finishing) {
  40.                 if (r.app != null && !r.app.persistent) {
  41.                     r.app.services.remove(r);
  42.                     if (r.whitelistManager) {
  43.                         updateWhitelistManagerLocked(r.app);
  44.                     }
  45.                 }
  46.                 r.app = null;
  47.             }
  48.         }
  49.     }


小结:Service启动调用onCreate方法之前send一个Delay执行的消息,当发生异常或者Service的onCreate方法执行完毕之后,remove掉之前send的消息,如果onCreate方法执行时间超过Delay的时间,那么该消息就会被处理,此时如果Delay的时间是我们设定的ANR时间,则发生ANR,系统作出处理,否则该消息被remove,不会被执行。以一种观察者模式的角度去实现。

id为SERVICE_TIMEOUT_MSG的消息被AMS中MainHandler接收

  1.             case SERVICE_TIMEOUT_MSG: {
  2.                 if (mDidDexOpt) {
  3.                     mDidDexOpt = false;
  4.                     Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
  5.                     nmsg.obj = msg.obj;
  6.                     mHandler.sendMessageDelayed(nmsg, ActiveServices.SERVICE_TIMEOUT);
  7.                     return;
  8.                 }
  9.                 mServices.serviceTimeout((ProcessRecord)msg.obj);
  10.             } break;


ActiveService的serviceTimeout方法中调用AppErrors中的appNotResponding方法,很明显ANR异常处理的方法:

  1.     final void appNotResponding(ProcessRecord app, ActivityRecord activity,
  2.             ActivityRecord parent, boolean aboveSystem, final String annotation) {
  3.         ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
  4.         SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);
  5.         if (mService.mController != null) {
  6.             try {
  7.                 // 0 == continue, -1 = kill process immediately
  8.                 int res = mService.mController.appEarlyNotResponding(
  9.                         app.processName, app.pid, annotation);
  10.                 if (res < 0 && app.pid != MY_PID) {
  11.                     app.kill("anr", true);
  12.                 }
  13.             } catch (RemoteException e) {
  14.                 mService.mController = null;
  15.                 Watchdog.getInstance().setActivityController(null);
  16.             }
  17.         }
  18.         long anrTime = SystemClock.uptimeMillis();
  19.         if (ActivityManagerService.MONITOR_CPU_USAGE) {
  20.             mService.updateCpuStatsNow();
  21.         }
  22.         // Unless configured otherwise, swallow ANRs in background processes & kill the process.
  23.         boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
  24.                 Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
  25.         boolean isSilentANR;
  26.         synchronized (mService) {
  27.             // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
  28.             if (mService.mShuttingDown) {
  29.                 Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation);
  30.                 return;
  31.             } else if (app.notResponding) {
  32.                 Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation);
  33.                 return;
  34.             } else if (app.crashing) {
  35.                 Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);
  36.                 return;
  37.             } else if (app.killedByAm) {
  38.                 Slog.i(TAG, "App already killed by AM skipping ANR: " + app + " " + annotation);
  39.                 return;
  40.             } else if (app.killed) {
  41.                 Slog.i(TAG, "Skipping died app ANR: " + app + " " + annotation);
  42.                 return;
  43.             }
  44.             // In case we come through here for the same app before completing
  45.             // this one, mark as anring now so we will bail out.
  46.             app.notResponding = true;
  47.             // Log the ANR to the event log.
  48.             EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid,
  49.                     app.processName, app.info.flags, annotation);
  50.             // Dump thread traces as quickly as we can, starting with "interesting" processes.
  51.             firstPids.add(app.pid);
  52.             // Don't dump other PIDs if it's a background ANR
  53.             isSilentANR = !showBackground && !isInterestingForBackgroundTraces(app);
  54.             if (!isSilentANR) {
  55.                 int parentPid = app.pid;
  56.                 if (parent != null && parent.app != null && parent.app.pid > 0) {
  57.                     parentPid = parent.app.pid;
  58.                 }
  59.                 if (parentPid != app.pid) firstPids.add(parentPid);
  60.                 if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID);
  61.                 for (int i = mService.mLruProcesses.size() - 1; i >= 0; i--) {
  62.                     ProcessRecord r = mService.mLruProcesses.get(i);
  63.                     if (r != null && r.thread != null) {
  64.                         int pid = r.pid;
  65.                         if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
  66.                             if (r.persistent) {
  67.                                 firstPids.add(pid);
  68.                                 if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);
  69.                             } else if (r.treatLikeActivity) {
  70.                                 firstPids.add(pid);
  71.                                 if (DEBUG_ANR) Slog.i(TAG, "Adding likely IME: " + r);
  72.                             } else {
  73.                                 lastPids.put(pid, Boolean.TRUE);
  74.                                 if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r);
  75.                             }
  76.                         }
  77.                     }
  78.                 }
  79.             }
  80.         }
  81.         //输出ANR异常Log
  82.         // Log the ANR to the main log.
  83.         StringBuilder info = new StringBuilder();
  84.         info.setLength(0);
  85.         //ANR发生时的进程Name
  86.         info.append("ANR in ").append(app.processName);
  87.         if (activity != null && activity.shortComponentName != null) {
  88.             info.append(" (").append(activity.shortComponentName).append(")");
  89.         }
  90.         info.append("\n");
  91.         //进程ID
  92.         info.append("PID: ").append(app.pid).append("\n");
  93.         //ANR发生的原因
  94.         if (annotation != null) {
  95.             info.append("Reason: ").append(annotation).append("\n");
  96.         }
  97.         if (parent != null && parent != activity) {
  98.             info.append("Parent: ").append(parent.shortComponentName).append("\n");
  99.         }
  100.         ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
  101.         // don't dump native PIDs for background ANRs unless it is the process of interest
  102.         String[] nativeProcs = null;
  103.         if (isSilentANR) {
  104.             for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) {
  105.                 if (NATIVE_STACKS_OF_INTEREST[i].equals(app.processName)) {
  106.                     nativeProcs = new String[] { app.processName };
  107.                     break;
  108.                 }
  109.             }
  110.         } else {
  111.             nativeProcs = NATIVE_STACKS_OF_INTEREST;
  112.         }
  113.         int[] pids = nativeProcs == null ? null : Process.getPidsForCommands(nativeProcs);
  114.         ArrayList<Integer> nativePids = null;
  115.         if (pids != null) {
  116.             nativePids = new ArrayList<Integer>(pids.length);
  117.             for (int i : pids) {
  118.                 nativePids.add(i);
  119.             }
  120.         }
  121.         // For background ANRs, don't pass the ProcessCpuTracker to
  122.         // avoid spending 1/2 second collecting stats to rank lastPids.
  123.         //dump栈信息
  124.         File tracesFile = mService.dumpStackTraces(true, firstPids,
  125.                                                    (isSilentANR) ? null : processCpuTracker,
  126.                                                    (isSilentANR) ? null : lastPids,
  127.                                                    nativePids);
  128.         String cpuInfo = null;
  129.         if (ActivityManagerService.MONITOR_CPU_USAGE) {
  130.             mService.updateCpuStatsNow();
  131.             synchronized (mService.mProcessCpuTracker) {
  132.                 //各进程使用CPU情况
  133.                 cpuInfo = mService.mProcessCpuTracker.printCurrentState(anrTime);
  134.             }
  135.             //CPU当前负载
  136.             info.append(processCpuTracker.printCurrentLoad());
  137.             info.append(cpuInfo);
  138.         }
  139.         info.append(processCpuTracker.printCurrentState(anrTime));
  140.         Slog.e(TAG, info.toString());
  141.         if (tracesFile == null) {
  142.             // There is no trace file, so dump (only) the alleged culprit's threads to the log
  143.             Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
  144.         }
  145.         //将anr信息添加到dropbox
  146.         mService.addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,
  147.                 cpuInfo, tracesFile, null);
  148.         if (mService.mController != null) {
  149.             try {
  150.                 // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
  151.                 int res = mService.mController.appNotResponding(
  152.                         app.processName, app.pid, info.toString());
  153.                 if (res != 0) {
  154.                     if (res < 0 && app.pid != MY_PID) {
  155.                         app.kill("anr", true);
  156.                     } else {
  157.                         synchronized (mService) {
  158.                             mService.mServices.scheduleServiceTimeoutLocked(app);
  159.                         }
  160.                     }
  161.                     return;
  162.                 }
  163.             } catch (RemoteException e) {
  164.                 mService.mController = null;
  165.                 Watchdog.getInstance().setActivityController(null);
  166.             }
  167.         }
  168.         synchronized (mService) {
  169.             mService.mBatteryStatsService.noteProcessAnr(app.processName, app.uid);
  170.             if (isSilentANR) {
  171.                 app.kill("bg anr", true);
  172.                 return;
  173.             }
  174.             // Set the app's notResponding state, and look up the errorReportReceiver
  175.             makeAppNotRespondingLocked(app,
  176.                     activity != null ? activity.shortComponentName : null,
  177.                     annotation != null ? "ANR " + annotation : "ANR",
  178.                     info.toString());
  179.             通过Handler消息机制弹出ANR对话框
  180.             // Bring up the infamous App Not Responding dialog
  181.             Message msg = Message.obtain();
  182.             HashMap<String, Object> map = new HashMap<String, Object>();
  183.             msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
  184.             msg.obj = map;
  185.             msg.arg1 = aboveSystem ? 1 : 0;
  186.             map.put("app", app);
  187.             if (activity != null) {
  188.                 map.put("activity", activity);
  189.             }
  190.             mService.mUiHandler.sendMessage(msg);
  191.         }
  192.     }


Android中的ANR监测以Handler消息机制实现,使用观察者模式,当开始监测时注册消息(该消息在规定时间后执行),事件处理完之后移除消息,当该消息执行时说明事件处理超过了规定的时间,即ANR。

6.总结

当ANR发生时,我们可以先通过logcat定位ANR的类型,然后通过trace信息分析产生ANR的原因,需要重点关注主线程(main)的当前状态和CPU的使用情况!当然ANR还是以预防为主,切记不要在主线程做耗时操作,不管是主动发起还是调用系统方法都需要对耗时的地方进行评估!

转载自:

https://blog.csdn.net/fanxudonggreat/article/details/81840791

http://www.cnblogs.com/purediy/p/3225060.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/204115
推荐阅读
相关标签
  

闽ICP备14008679号