ANR问题分析指南

引言
每天收到无数的兄弟团队的同事向系统转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:8769,

进程名: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 ( A c t i v i t y T h r e a d . j a v a : 150 ) a t a n d r o i d . a p p . A c t i v i t y T h r e a d 1900(ActivityThread.java:150) at android.app.ActivityThread 1900(ActivityThread.java:150)atandroid.app.ActivityThreadH.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 ( A c t i v i t y T h r e a d . j a v a : 154 ) 88665 a t a n d r o i d . a p p . A c t i v i t y T h r e a d 1600(ActivityThread.java:154) 88665 at android.app.ActivityThread 1600(ActivityThread.java:154)88665atandroid.app.ActivityThreadH.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.ZygoteInitKaTeX parse error: Expected '}', got 'EOF' at end of input: ….ActivityThreadH
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 S t u b Stub StubProxy.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 . h a n d l e M e s s a g e ( A c t i v i t y T h r e a d . j a v a : 1619 ) 12 − 1702 : 08 : 44.58758875887 W M I U I − B L O C K − M O N I T O R : a t a n d r o i d . o s . H a n d l e r . d i s p a t c h M e s s a g e ( H a n d l e r . j a v a : 102 ) 12 − 1702 : 08 : 44.58758875887 W M I U I − B L O C K − M O N I T O R : a t a n d r o i d . o s . L o o p e r . l o o p ( L o o p e r . j a v a : 163 ) 12 − 1702 : 08 : 44.58758875887 W M I U I − B L O C K − M O N I T O R : a t a n d r o i d . a p p . A c t i v i t y T h r e a d . m a i n ( A c t i v i t y T h r e a d . j a v a : 6379 ) 12 − 1702 : 08 : 44.58758875887 W M I U I − B L O C K − M O N I T O R : a t j a v a . l a n g . r e f l e c t . M e t h o d . i n v o k e ( N a t i v e M e t h o d ) 12 − 1702 : 08 : 44.58758875887 W M I U I − B L O C K − M O N I T O R : a t c o m . a n d r o i d . i n t e r n a l . o s . Z y g o t e I n i t 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 H.handleMessage(ActivityThread.java:1619)121702:08:44.58758875887WMIUIBLOCKMONITOR:atandroid.os.Handler.dispatchMessage(Handler.java:102)121702:08:44.58758875887WMIUIBLOCKMONITOR:atandroid.os.Looper.loop(Looper.java:163)121702:08:44.58758875887WMIUIBLOCKMONITOR:atandroid.app.ActivityThread.main(ActivityThread.java:6379)121702:08:44.58758875887WMIUIBLOCKMONITOR:atjava.lang.reflect.Method.invoke(NativeMethod)121702:08:44.58758875887WMIUIBLOCKMONITOR:atcom.android.internal.os.ZygoteInitMethodAndArgsCaller.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比例(没有太大价值)

  1. 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类

  1. 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之间的交互

转载于:https://www.cnblogs.com/genggeng/p/10564260.html

相关资源:如何分析及避免AndroidANR问题.pdf-Android文档类资源

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ANR Trace分析是一种通过分析ANR错误日志(或称为ANR跟踪文件)来确定ANR错误的根本原因的方法。通过分析ANR跟踪文件,您可以了解应用程序中哪些线程阻塞了主线程,并确定导致线程阻塞的原因。 在Android设备上,您可以使用命令行工具 `adb shell dumpsys activity ANR` 来获取ANR错误日志。此命令将打印出最近的ANR错误日志,其中包含了主线程的堆栈跟踪信息、CPU使用情况、线程状态等信息。 下面是一个ANR错误日志的示例: ``` ANR in com.example.myapp PID: 1234 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. Waited for 1.0s.) Load: 98% CPU usage from 10000ms to 0ms ago: 60% com.example.myapp: 50% user + 9.7% kernel / faults: 250 minor 4 major 39% system_server: 14% user + 24% kernel / faults: 324 minor 3 major 0.1% com.android.systemui: 0% user + 0.1% kernel / faults: 17 minor 1 major 0% com.android.phone: 0% user + 0% kernel / faults: 11 minor 0% com.android.launcher: 0% user + 0% kernel / faults: 7 minor 0% kswapd0: 0% user + 0% kernel 0% kworker/u:1: 0% user + 0% kernel ``` 通过分析上面的ANR错误日志,您可以了解以下信息: - 应用程序包名为 com.example.myapp,进程ID为 1234。 - ANR出现的原因是输入事件分发超时,即应用程序在等待某个窗口处理输入事件时超时了。 - 应用程序的CPU负载达到了98%。 - 应用程序占用了60%的CPU时间。 - 系统服务 system_server 占用了39%的CPU时间。 - 其他进程的CPU使用率非常低。 通过分析这些信息,您可以确定ANR错误的原因,并尝试采取相应的措施来解决问题,比如将耗时操作移到后台线程中执行、优化代码、调整系统配置等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值