引言

每天收到无数的兄弟团队的同事向系统转ANR JIRA,有些一旦遇到App ANR就直接转到系统组,有些简单看一下就转到系统组帮忙看一下。如此浩瀚的JIRA,我们什么事不做也处理不过来,请每个App owner责任各自ANR.

  • APP Team要先有较深入分析,真正确定是系统问题,再转JIRA
  • 请勿看到binder或者message耗时就直接转到系统,几乎系统所有的通信都离不开这两个基本功能,存在这个不能直接说明问题,要能从逻辑上说得通是系统的问题
  • 如果看完本文,分析完一遍之后,还是无法深入分析,可能是信息不足,可考虑降低优先级,等待用户再反馈;如果同时概率非常低,可考虑先关闭

如有不懂,系统组可以提供相关帮助,原则上自家的APP自家负责,谢谢大家的理解。下面就讲一讲分析ANR的常见套路:

一. ANR类型及常见原因

1.1 ANR定义

Application Not Responding:即应用无响应

如果应用程序主线程在超时时间内对输入事件没有处理完毕,或者对特定操作没有执行完毕,就会出现ANR

(主线程在特定的时间内没有做完特定的事情)

1.2.ANR类型

1)KeyDispatchTimeout-主要类型按键或触摸事件,input事件在5S内没有处理完成发生ANR

发生KeyDispatchTimeout类型的ANR日志中出现的关键字:Reason: Input dispatching timed out xxxx

2)ServiceTimeout-bind,create,start,unbind等在主线程处理耗时,前台Service在20s内,后台Service在200s内没有处理完成发生ANR

发生ServiceTimeout类型的ANR日志中出现的关键字:Timeout executing service:/executing service XXX

3)BroadcastTimeout- BroadcastReceiver onReceiver处理事务时前台广播在10S内,后台广播在60s内没有处理完成发生ANR

发生BroadcastTimeout类型的ANR日志中出现的关键字:Timeout of broadcast XXX/Receiver during timeout:XXX/Broadcast of XXX

4)ProcessContentProviderPublishTimedOutLocked-ContentProvider publish在10s内没有处理完成发生ANR

发生ProcessContentProviderPublishTimedOutLocked类型的ANR日志中出现的关键字:timeout publishing content providers

1.3.常见的原因

A.主线程耗时操作,如复杂的layout,庞大的for循环,IO等。
B.主线程被子线程同步锁block

C.主线程被Binder 对端block
D.Binder被占满导致主线程无法和SystemServer通信
E.得不到系统资源(CPU/RAM/IO)

二.ANR分析

ANR问题发生时,对于用户的直观感受是弹框,给用户取消和等待的选择,但是对于分析ANR的开发者来说,发生ANR的过程中,系统会自动的获取并打印日志信息,从这些log中我们可以获取ANR的类型,CPU的情况(CPU使用率过高有可能是CPU饥饿导致了ANR;CPU使用率过低说明主线程被block了),每种ANR类型在规定时间内执行的具体操作等等。log输出以外,你会发现各个应用进程和系统进程的函数堆栈信息都输出到了一个/data/anr/traces.txt的文件中,这个文件是分析ANR原因的关键文件.要获取到该文件可使用adb指令进行赋权后拉出查看调用stack。除此之外,为了更加准确方便的分析ANR问题,我们在系统中还添加了一些额外的信息。以下将通过log、trace.txt,附加的额外信息以及结合代码分析ANR的前因后果。

分析ANR大致分为以下几个步骤:

1.确定ANR发生时间,关键字:am_anr,ANR in

2.查看ANR发生时打印的trace,文件目录:/data/anr/traces.txt,MIUI系统还会有附加信息关键字:MIUI-BLOCK-MONITOR

这里可以在traces.txt文件中查看导致ANR的错误栈,搜索关键字["main" prio=5 tid=1]  其中prio和tid后的值,可以根据文中的情况修改(调用栈一般在文件最后,可以先搜索"main"来确定后面的prio和tid),这样可以找到ANR时main线程的调用栈情况

3.查看系统耗时关键字:binder_sample,dvm_lock_sample,am_lifecycle_sample,binder thread

4.结合源码和以上的信息进行分析

以下将对这几个步骤做进一步的分析.

2.1. 确定发生ANR的时间具体时间点

2.1.1. ANR发生的日志中,为了定位ANR发生的时间点,可以搜索Events log中的关键字:am_anr

eg:  

12-17 06:02:14.463 1566 1583 I am_anr : [0,8769,com.android.updater,952680005,Broadcast of Intent { act=android.intent.action.BOOT_COMPLETED flg=0x9000010 cmp=com.android.updater/.BootCompletedReceiver (has extras) }]

根据这行log我们确定的信息

发生anr的时间点:12-17 06:02:14.463,

进程pid:,

进程名:com.android.updater,

发生ANR的类型是:BroadcastTimeout,

发生的具体类或者原因:{ act=android.intent.action.BOOT_COMPLETED flg=0x9000010 cmp=com.android.updater/.BootCompletedReceiver (has extras) }

2.1.2. 与之相对应的system log,也就是ANR类型中出现的关键字:

eg:  

12-17 06:02:00.370 1566 1583 W BroadcastQueue: Timeout of broadcast BroadcastRecord{21ef8c2 u0 android.intent.action.BOOT_COMPLETED} - receiver=android.os.BinderProxy@2a6c365, started 60006ms ago

                12-17 06:02:00.370  1566  1583 W BroadcastQueue: Receiver during timeout: ResolveInfo{5a8283a com.android.updater/.BootCompletedReceiver m=0x108000}

这行日志中很多信息是和Events log是重合的,但是我们我们可以通过" started 60006ms ago"可以知道这信息是在1分多钟之前执行的,现在还没有执行结束,已经达到了发生ANR规定的时间,可以确定这是个后台广播,所以我们可以把信息锁定在时间点:12-17 06:02:00.370往前推算的一分钟内,观察在这段时间内具体执行了哪些操作,导致后台广播没有执行完成.

2.1.3. 关键字:ANR in

大家在分析ANR的时候,也往往会检查这个关键字包含的相关内容,这里面包含了CPU的负载,CPU的统计时间段,使用率等信息

eg:  

12-17 06:02:19.286 1566 1583 E ActivityManager: ANR in com.android.updater(进程名)

12-17 06:02:19.286 1566 1583 E ActivityManager: PID: 8769(进程pid)
 12-17 06:02:19.286 1566 1583 E ActivityManager: Reason: Broadcast of Intent { act=android.intent.action.BOOT_COMPLETED flg=0x9000010 cmp=com.android.updater/.BootCompletedReceiver (has extras) }(原因)
 12-17 06:02:19.286 1566 1583 E ActivityManager: Load: 0.0 / 0.0 / 0.0(Load表明是1分钟,5分钟,15分钟CPU的负载)
 12-17 06:02:19.286 1566 1583 E ActivityManager: CPU usage from 0ms to 18846ms later (2017-12-17 06:02:00.379 to 2017-12-17 06:02:19.224):
 12-17 06:02:19.286 1566 1583 E ActivityManager: 95%(CPU的使用率)6142/com.immomo.momo: 95% (用户态的使用率)user + 0% (内核态的使用率)kernel
 12-17 06:02:19.286 1566 1583 E ActivityManager: 2.3% 8170/com.tencent.mm: 2.3% user + 0% kernel / faults: 448 minor
 12-17 06:02:19.286 1566 1583 E ActivityManager: 0.7% 1566/system_server: 0.4% user + 0.3% kernel / faults: 150 minor (高速缓存的缺页次数)1 major(内存的缺页次数)
 12-17 06:02:19.286 1566 1583 E ActivityManager: 0.4% 90/kworker/u16:3: 0% user + 0.4% kernel
 12-17 06:02:19.286 1566 1583 E ActivityManager: 0.3% 4704/com.tencent.mm:push: 0.1% user + 0.2% kernel / faults: 116 minor
 12-17 06:02:19.286 1566 1583 E ActivityManager: 0.3% 8769/com.android.updater: 0.2% user + 0.1% kernel / faults: 1600 minor 2 major
 12-17 06:02:19.286 1566 1583 E ActivityManager: 0.2% 4790/com.tencent.mm:patch: 0.2% user + 0% kernel / faults: 748 minor
 12-17 06:02:19.286 1566 1583 E ActivityManager: 0.2% 329/mmc-cmdqd/0: 0% user + 0.2% kernel
 12-17 06:02:19.286 1566 1583 E ActivityManager: 0.2% 5429/com.tencent.mm:push: 0% user + 0.1% kernel / faults: 17 minor
 12-17 06:02:19.286 1566 1583 E ActivityManager: 0.2% 5435/com.tencent.mm:patch: 0.2% user + 0% kernel / faults: 82 minor
 12-17 06:02:19.286 1566 1583 E ActivityManager: 0.2% 8712/com.tencent.mm:exdevice: 0.1% user + 0% kernel

注意:1.ANR in对应的ANR的时间点往往是比am_anr的时间点是靠后的,一般不使用这个时间确定ANR发生的具体时间点

2.cpu占用95%有时候并不算高,在多核中每个核最大占用率都是100%(八核占用率是800%)

2.2. ANR发生时打印的堆栈和系统附加信息

2.2.1. trace信息

发生ANR时,各个应用进程和系统进程的函数堆栈信息都输出到了一个/data/anr/traces.txt的文件.我们往往比较关注的是发生ANR的应用进程主线程具体执行堆栈,我们可以知道在发生ANR这个时间点主线程具体在做什么,为什么卡住了,是等锁,binder call调用还是主线程存在耗时的操作等等.

eg:

main(线程名)、prio(线程优先级,默认是5)、tid(线程唯一标识ID)、Sleeping(线程当前状态)

"main" prio=5 tid=1 Sleeping
| group="main" sCount=1 dsCount=0 obj=0x73132d10 self=0x5598a5f5e0
//sysTid是线程号(主线程的线程号和进程号相同)
| sysTid=17027 nice=0 cgrp=default sched=0/0 handle=0x7fb6db6fe8
| state=S schedstat=( 420582038 5862546 143 ) utm=24 stm=18 core=6 HZ=100
| stack=0x7fefba3000-0x7fefba5000 stackSize=8MB
| held mutexes=
// java 堆栈调用信息(这里可查看导致ANR的代码调用流程)(分析ANR最重要的信息)
at java.lang.Thread.sleep!(Native method)
- sleeping on <0x0c60f3c7> (a java.lang.Object)
at java.lang.Thread.sleep(Thread.java:1031)
- locked <0x0c60f3c7> (a java.lang.Object) // 锁住对象0x0c60f3c7
at java.lang.Thread.sleep(Thread.java:985)
at android.os.SystemClock.sleep(SystemClock.java:120)
at org.code.ipc.MessengerService.onCreate(MessengerService.java:63) //导致ANR的代码
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2877)
at android.app.ActivityThread.access$1900(ActivityThread.java:150)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1427)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke!(Native method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

2.2.2. 附加信息

在前面也说过为更准确更方便分析anr问题,我们在系统中添加了一些额外的信息供分析

如何提升ANR问题分析效率---这篇文章有具体分析,大家可以具体阅读这篇文章,这里就不再详细的讲述

我们在获取ANR日志后需要关注的关键字:MIUI-BLOCK-MONITOR

1.我们对每一个Message都额外记录了它各个状态的时间点,方便我们进行分析
planTime:消息计划被执行的时间点
dispatchTime:消息真正被执行的时间点
finishTime:消息完成时的时间点

2.当主线程某一个消息处理时间大于2s(开发版及稳定版是3秒)时,打印出一个警告日志
MIUI系统可在日志中搜索"MIUI-BLOCK-MONITOR: The msg"关键字

3.当主线程的某一个binder call耗时超过3s时,打印出一个警告日志,并打印出对应的调用栈
MIUI系统可在日志中搜索"MIUI-BLOCK-MONITOR: The binder call"关键字

4.当主线程的某个input事件处理时间大于2s时,打印出一个警告日志
MIUI系统可在日志中搜索"MIUI-BLOCK-MONITOR: The input关键字

5.在发生anr时,会在/data/anr/目录下生成anr_info_processName_time.txt文件,它会记录一些anr发生时的信息
5.1 anr发生前app主线程的耗时消息记录(超过200ms的消息会被记录)
可搜索"History of long time messages"关键字。
需要注意:记录最多保留50条,按完成时间降序排列,如果短时间内处理消息过多,真正耗时的消息可能会被覆盖,这时可在日志中搜索耗时纪录。
5.2 anr发生时正在处理的消息,如果有的话
可搜索"Running message"关键字
5.3 主线程未执行的剩余消息
可搜索"MessageQueue on Looper"关键字

下面是如何提升ANR问题分析效率文章中的一个例子:

eg:

ANR in com.sankuai.meituan (com.sankuai.meituan/.activity.Welcome)
PID: 25544
Reason: Input dispatching timed out (Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.)
Dump time : 2016-11-30 22:07:03.756+0800
Running message is { when=-5s363ms what=110 obj=AppBindData{appInfo=ApplicationInfo{e612c25 com.sankuai.meituan}} target=android.app.ActivityThread$H planTime=1480514818393 dispatchTime=1480514818409 finishTime=0 }
先解释一下"Running message"各个重要参数的意义:
when是这个消息需要被执行的时间点,是基于当前dump的时间算出来的一个时间差
注意:history中的消息,when值没有参考意义,它只是消息完成时的一个快照,
还有一点需要特别注意通过Handler.sendMessageAtFrontOfQueue方法设置的消息,它的uptimeMillis设置的是0,
这时候的when值是(SystemClock.uptimeMillis() - 0),对于这种消息不能简单看when值,需要通过以下三个值才能做出判断。
planTime是消息计划被执行的时间点
dispatchTime是消息真正被执行的时间点
finishTime是消息完成时的时间点
上面的例子,消息A应该在22:06:58.393(22:07:03.756-5s363ms)这个时间点被执行,
消息等待执行的时间:dispatchTime-planTime=16ms
这个消息当前已经执行的时间:5s363ms-16ms=5s347ms,
也就是anr发生时what=110这个消息己经执行了5s347ms,这是有问题的
在这种情况下,抓取的trace是准确的,可以根据trace栈,进行分析了。
查看对应主线程的trace栈,刚好是what=110(ActivityThread.BIND_APPLICATION)这个消息,都匹配上了:

88651 at java.lang.Runtime.nativeLoad(Native method)
88652 at java.lang.Runtime.doLoad(Runtime.java:435)
88653 - locked <0x0f7e5bd6> (a java.lang.Runtime)
88654 at java.lang.Runtime.loadLibrary(Runtime.java:370)
88655 at java.lang.System.loadLibrary(System.java:1076)
88656 at com.meituan.android.common.performance.statistics.crash.ExceptionHandler.initNative(ExceptionHandler.java:43)
88657 at com.meituan.android.common.performance.statistics.crash.ExceptionHandler.registerExceptionHandler(ExceptionHandler.java:59)
88658 at com.meituan.android.common.performance.statistics.crash.CrashStatistics.start(CrashStatistics.java:49)
88659 at com.meituan.android.common.performance.statistics.crash.CrashStatisticsManager.start(CrashStatisticsManager.java:44)
88660 at com.meituan.android.common.performance.PerformanceManager.start(PerformanceManager.java:228)
88661 at com.sankuai.meituan.MeituanApplication.onCreate(MeituanApplication.java:2232)
88662 at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1014)
88663 at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4737)
88664 at android.app.ActivityThread.access$1600(ActivityThread.java:154)
88665 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1423)
88666 at android.os.Handler.dispatchMessage(Handler.java:102)
88667 at android.os.Looper.loop(Looper.java:164)
88668 at android.app.ActivityThread.main(ActivityThread.java:5452)
88669 at java.lang.reflect.Method.invoke!(Native method)
88670 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738)
88671 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)
最终耗时,可以从日志中查看,这个消息最终在07:05的时候才执行完,消息的整个处理耗时7075ms,其中dispatch之后耗时7059ms。
23145 11-30 22:07:05.469 25544 25544 W MIUI-BLOCK-MONITOR: The msg { when=-7s75ms what=110 obj=AppBindData{appInfo=ApplicationInfo{e612c25 com.sankuai.meituan}} target=android.app.ActivityThread$H
planTime=1480514818393 dispatchTime=1480514818409 finishTime=1480514825468 } took 7075ms and took 7059ms after dispatch

注意:1.在查看堆栈的过程中,我们需要和第1)步中的ANR的时间,pid等点结合起来,有时候trace的时间点是和真正发生ANR的时间是对不上,说明抓取的trace已经错过了现场

2.有时候"Running message"和打印的trace信息也未必对的上,这个在如何提升ANR问题分析效率有更加详细的介绍,具体问题还需具体分析

2.3.关于binder call ,关于系统耗时

在日志分析中我们根据上面系统附加的信息,我们往往可以看到以下binder call的信息,

eg:

12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: The binder call took 68921ms.
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: java.lang.Throwable
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at android.os.AnrMonitor.checkBinderCallTime(AnrMonitor.java:591)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at android.os.BinderProxy.transact(Binder.java:623)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at android.content.pm.IPackageManager$Stub$Proxy.getApplicationInfo(IPackageManager.java:2658)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at android.app.ApplicationPackageManager.getApplicationInfoAsUser(ApplicationPackageManager.java:340)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at android.app.ApplicationPackageManager.getApplicationInfo(ApplicationPackageManager.java:333)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at miui.core.ManifestParser.create(SourceFile:64)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at miui.core.SdkManager.start(SourceFile:186)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at java.lang.reflect.Method.invoke(Native Method)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at miui.external.Application.c(SourceFile:101)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at miui.external.Application.attachBaseContext(SourceFile:165)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at com.mipay.wallet.App.attachBaseContext(SourceFile:13)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at android.app.Application.attach(Application.java:193)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at android.app.Instrumentation.newApplication(Instrumentation.java:1009)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at android.app.Instrumentation.newApplication(Instrumentation.java:993)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at android.app.LoadedApk.makeApplication(LoadedApk.java:800)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5516)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at android.app.ActivityThread.-wrap2(ActivityThread.java)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1619)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at android.os.Handler.dispatchMessage(Handler.java:102)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at android.os.Looper.loop(Looper.java:163)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at android.app.ActivityThread.main(ActivityThread.java:6379)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at java.lang.reflect.Method.invoke(Native Method)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
12-17 02:08:44.587 5887 5887 W MIUI-BLOCK-MONITOR: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)

看到这些日志打印的时候,有时候给人的第一感觉是系统出了问题,跟binder有关,其实我们可以进一步确定问题

首先我们可以确定系统是否有耗时信息,参考文章---系统耗时分析方案

1.binder_sample

1.功能说明: 监控每个进程的主线程的binder transaction的耗时情况, 当超过阈值时,则输出相应的目标调用信息.

2.云控参数: persist.sys.binder.transact_ms (默认值为 1000ms). 当该值小于0则关闭该功能.

3.log格式: 52004 binder_sample (descriptor|3),(method_num|1|5),(time|1|3),(blocking_package|3),(sample_percent|1|6)

4.log实例: 2754 2754 I binder_sample: [android.app.IActivityManager,35,2900,android.process.media,5]

5.log解析: 
1.主线程2754;
2.执行android.app.IActivityManager接口
3. 所对应方法code =35(即STOP_SERVICE_TRANSACTION),
4. 所花费时间为2900ms. 
5. 该block所在package为 android.process.media
最后一个参数是sample比例(没有太大价值)

2. dvm_lock_sample

1.功能说明: 当某个线程等待lock的时间blocked超过阈值,则输出当前的持锁状态 ;

2.云控参数: persist.vm.lockprof.threshold (默认值为 500ms)

3.log格式: 20003 dvm_lock_sample (process|3),(main|1|5),(thread|3),(time|1|3),(file|3),(line|1|5),(ownerfile|3),(ownerline|1|5),(sample_percent|1|6)

4.log实例:  dvm_lock_sample: [system_server,1,Binder_9,1500,ActivityManagerService.java,6403,-,1448,0]
5.log解析: system_server: Binder_9,执行到ActivityManagerService.java的6403行代码,一直在等待AMS锁, "-"代表持锁的是同一个文件,
即该锁被同一文件的1448行代码所持有, 从而导致Binder_9线程被阻塞1500ms.

3.am_lifecycle_sample

1.功能说明:  当app在主线程的生命周期回调方法执行时间超过阈值,则输出相应信息;

2.云控参数:  persist.sys.handler.threshold (默认值为3000ms)

3.log格式: am_lifecycle_sample (User|1|5),(Process Name|3),(MessageCode|1|5),(time|1|3)

4.log实例: 02-23 11:02:35.876 8203 8203 I am_lifecycle_sample: [0,com.android.systemui,114,3837]
5.log解析: pid=8203, processName=com.android.systemui, MessageCode=114(CREATE_SERVICE), 耗时3.827s

注意: MessageCode=200 (并行广播onReceive耗时), 其他Code见 ActivityThread.H类

4. binder thread

1.功能说明:  当system_server等进程的线程池使用完, 无空闲线程时, 则binder通信都处于饥饿状态, 则饥饿状态超过一定阈值则输出信息;

2.云控参数: persist.sys.binder.starvation  (默认值16ms)

3.log实例:  1232 1232 "binder thread pool (16 threads) starved for 100 ms"

4.log解析:  system_server进程的 线程池已满的持续长达100ms

eg:

以上的binder call 信息,我们查找日志中的持锁信息

12-17 02:08:44.559 1999 4899 I dvm_lock_sample: [system_server,1,Binder:1999_16,68916,PackageManagerService.java,3537,UserManagerService.java,3380,0]

12-17 02:08:44.696 1999 4131 I dvm_lock_sample: [system_server,1,Binder:1999_14,61042,PackageManagerService.java,3537,UserManagerService.java,3380,0]

PackageManagerService.java第3537需要的锁被UserManagerService.java中的3380行持有,我们再结合源码查看UserManagerService.java中的3380行是因为什么原因导致持锁耗时

注意:binder call出现耗时,有binder在通信过程中因为繁忙造成,也有可能因为对端持锁或者执行一些耗时的操作耗时,日志中打印binder call信息表明binder call与远程端通信已经结束,出现binder call信息也不不代表framework出现问题,需要根据日志分析准确定位.

2.4. 案例

http://jira.n.xiaomi.com/browse/MIUI-1021360

http://jira.n.xiaomi.com/browse/MIUI-1017959

 

2.5. ANR分析流程

三.ANR分析工具

3.1. 工具使用介绍

为了减少ANR分析的时间,提高分析效率,开发了一套ANR分析工具LogAnalyse:LogAnalyser使用说明书,这里面有详细的配置和使用说明

LogAnalyse中可以把log进行拆分,对于ANR日志能提取其中一些主要的信息放在不同的文件中

1.日志拆分 LogAnalyser <file_path>
例如:LogAnalyser /home/XXXX/local_log/bugreport-2017-09-18-141601.zip
拆分结果在/home/XXXX/local_log/bugreport-2017-09-18-141601目录下,current_log, last_log, traces, dumpsys, system_info应有尽有.
版本信息和properties信息都在build_info中.
另外,还有惊喜:system log和event log中添加了进程名;kernal log中添加了时间戳对齐;dumpsys service也有拆分,都在dumpsys下.

2.分析ANR LogAnalyser <file_path> <process_name> -anr
例如:LogAnalyser /home/XXXX/local_log/bugreport-2017-09-18-141601.zip com.sohu.inputmethod.sogou.xiaomi -anr
可是我不确定是哪个进程?没关系,LogAnalyser <file_path> -anr也可以,会把日志中所有的anr进程都解析了.
解析结果在/home/XXXX/local_log/bugreport-2017-09-18-141601/analysis下面:
  analysis_anr_进程.txt为anr进程的trace解析结果;
  analysis_进程.txt为anr进程的system_log, event_log和main_log解析结果
另外,还可以批量解析,LogAnalyser 文件夹即可!
最终在文件夹下会生成一个summary.txt汇总文件,其内容是根据trace将log分类,方便查看

3.trace分析 LogAnalyser -t <trace_file_path> <process_name>
例如:LogAnalyser -t /home/XXXX/local_log/tracefile.txt com.android.setting
解析结果在/home/XXXX/local_log/out/result_trace_进程名.想知道进程的主线程调用情况,block在什么地方,打开文件就知道了.

4.进程启动和被杀 LogAnalyser <file_path> <process_name> -kill
输出结果在./analysis/extract_key_进程名下.
另外,在"功能2<分析ANR>"的结果文件夹下有个./analysis/analysis_process文件,其中记录所有进程的启动和被杀

3.2. bugreport拆分目录:

  • build_info : 记录版本以及properties信息
  • current_log:
    • current_kernel_log;   (当前Kernel日志)
    • current_system_log;   (当前System日志)
    • current_event_log;   (当前Event日志)
    • current_radio_log;
  • last_log
    • last_kernel_log;  (上一次Kernel日志)
    • last_system_log;  (上一次系统日志)
    • last_radio_log;
  • traces
    • traces_just_now;   (当前的调用栈信息)
    • traces_last_anr;  (最近一次ANR的调用栈信息)
    • tombstones;   (native crash的详细信息)
  • dumpsys                (各种dump信息)

    • dumpsys_activity    (AMS信息)
    • dumpsys_package   (PKMS信息)
    • dumpsys_window   (WMS信息)
    • dumpsys_input  (Input信息)
    • dumpsys_power  (PMS信息)
    • dumpsys_alarm
    • dumpsys_else (其他)
    • dumpsys_checkin
  • system_info   
    • sys_cpu   (CPU)
    • sys_memory   (内存)
    • sys_io   (IO)
    • sys_procs  (进程)
    • sys_binder  (binder)
  • other: 

  • analysis :     
    • analysis_anr  (ANR的分析结果)
    • analysis_process  (杀进程的分析结果)

注意:LogAnalyse能进行初步的确定问题,但是并非适应所有的场景

四.建议

为了避免ANR发生的概率:

1:UI线程尽量只做跟UI相关的工作
2:耗时的工作(比如数据库操作,I/O,连接网络或 者别的有可能阻碍UI线程的操作) 把它放入单独的线程处理
3:尽量用Handler来处理UIthread和别的thread之间的交互

[转]ANR问题分析指南的更多相关文章

  1. android wifi ANR问题分析总结

    android wifi ANR问题分析总结 1 看看main进程阻塞在那里? 2 调用关系的函数阻塞在那里? 3 最终阻塞函数的阻塞前的log以及状态

  2. JavaScript 内存详解 & 分析指南

    前言 JavaScript 诞生于 1995 年,最初被设计用于网页内的表单验证. 这些年来 JavaScript 成长飞速,生态圈日益壮大,成为了最受程序员欢迎的开发语言之一.并且现在的 JavaS ...

  3. 干货:ANR日志分析全面解析

    一.概述 解决ANR一直是Android 开发者需要掌握的重要技巧,一般从三个方面着手. 开发阶段:通过工具检查各个方法的耗时,卡顿情况,发现一处修改一处. 线上阶段:这个阶段主要依靠监控工具发现AN ...

  4. 【Android】[转] ANR的分析和问题处理

    一:什么是ANR ANR:Application Not Responding,即应用无响应 二:ANR的类型 ANR一般有三种类型: 1. KeyDispatchTimeout(5 seconds) ...

  5. android ANR 案例分析

    案例1:关键词:ContentResolver in AsyncTask onPostExecute, high iowait Process:com.android.email Activity:c ...

  6. Android ANR原理分析

    一.概述 ANR(Application Not responding),是指应用程序未响应,Android系统对于一些事件需要在一定的时间范围内完成,如果超过预定时间能未能得到有效响应或者响应时间过 ...

  7. Input系统—ANR原理分析(转)

    一. 概述 当input事件处理得慢就会触发ANR,那ANR内部原理是什么,哪些场景会产生ANR呢. “工欲善其事必先利其器”,为了理解input ANR原理,前面几篇文章疏通了整个input框架的处 ...

  8. ANR问题分析实例

    ANR监测机制包含三种: Service ANR,前台进程中Service生命周期不能超过20秒,后台进程中Service的生命周期不能超过200秒. 在启动Service时,抛出定时消息SERVIC ...

  9. ANR日志分析

    2018年06月27日 16:28:13 Hello__code 阅读数 3427更多 分类专栏: bug记录   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出 ...

随机推荐

  1. jenkins自动化部署vue

    一.nodejs配置 首先加入nodejs插件 在配置里面配置这个插件 这样我们就能在自动构建发布的配置里看到nodejs的编译选项了 二.发布配置 首先新建一个自由风格的项目 然后配置构建保留天数和 ...

  2. SkiaSharp图像处理

    SkiaSharp图像处理 .NET Core使用skiasharp文字头像生成方案(基于docker发布)   一.问题背景 目前.NET Core下面针对于图像处理的库微软并没有集成,在.NET ...

  3. Vue 2.6版本基础知识概要(一)

    挂载组件 //将 App组件挂载到div#app节点里 new Vue({ render: h => h(App), }).$mount('#app') VueComponent.$mount ...

  4. springboot 配置文件

    – Spring Boot使用一个全局的配置文件 • application.properties • application.yml – 配置文件放在src/main/resources目录或者类路 ...

  5. 暂时禁止Cnario Player开机自动启动的办法

    如果暂时不需要播放器开机后启动Cnario Player, 有两种办法 从Windows启动菜单禁用Cnario Player 在Windows的任务管理器中, 找到启动标签栏, 从里面找到Cnari ...

  6. SpringBoot+Swagger整合API

    SpringBoot+Swagger整合API Swagger:整合规范的api,有界面的操作,测试 1.在pom.xml加入swagger依赖 <!--整合Swagger2配置类--> ...

  7. 将root 当成arraylist放入数据sturts2 入门笔记

    刚启动idea 就报出错误 [-- ::,] Artifact -sturts2:war exploded: Error during artifact deployment. See server ...

  8. 【MySQL 读书笔记】全局锁 | 表锁 | 行锁

    全局锁 全局锁是针对数据库实例的直接加锁,MySQL 提供了一个加全局锁的方法, Flush tables with read lock 可以使用锁将整个表的增删改操作都锁上其中包括 ddl 语句,只 ...

  9. Spark2.2 saveAsTable 函数使用 overWrite 设置 Partition 会造成全覆盖的问题

    在使用 CDH 6.0.X 的版本还是自带的是 Spark2.2 的版本,2.2 版本的 Spark 使用 saveAsTable 如果使用overWrite PartitionBy 的功能会有和 h ...

  10. mysql-笔记-datetime

    1 adddate(date,interval expr unit)--同 date_add() select date_add('2019-4-20',interval 31 day); selec ...