查找ANR异常

  1. 导出traces.txt:adb pull data/anr D:/test ,这个命令是把anr整个目录都导出到D盘的test目录中。网上有的文章说如果出现多次ANR会有多个traces.txt,但是在我的设备上,出现多次ANR也只会有一个traces.txt,且traces.txt中保存的是最近出现的那次ANR信息。

  2. 打开traces.txt,在大概200行左右的地方就能看到报出ANR异常的方法是哪个了,如下:

    
       "main" prio=5 tid=1 Native
    
      | group="main" sCount=1 dsCount=0 obj=0x758cca10 self=0x7f7ee95a00
    
      | sysTid=14969 nice=-10 cgrp=default sched=0/0 handle=0x7f82db9a98
    
      | state=S schedstat=( 39182160268 4596760347 54475 ) utm=3593 stm=325 core=4 HZ=100
    
      | stack=0x7fe2848000-0x7fe284a000 stackSize=8MB
    
      | held mutexes=
    
      kernel: __switch_to+0x8c/0x98
    
      kernel: futex_wait_queue_me+0xd8/0x130
    
      kernel: futex_wait+0xec/0x1f8
    
      kernel: do_futex+0xdc/0x878
    
      kernel: SyS_futex+0x110/0x19c
    
      kernel: el0_svc_naked+0x24/0x28
    
      native: #00 pc 000000000001c16c  /system/lib64/libc.so (syscall+28)
    
      native: #01 pc 0000000000069134  /system/lib64/libc.so (_ZL33__pthread_mutex_lock_with_timeoutP24pthread_mutex_internal_tbPK8timespec+744)
    
      native: #02 pc 00000000002a1ad0  /data/app/cn.dazhou.railway.monitor-2/lib/arm64/libtinyWRAP.so (tsk_mutex_lock+28)
    
      at org.doubango.tinyWRAP.tinyWRAPJNI.InviteSession_hangup__SWIG_1(Native method)
    
      at org.doubango.tinyWRAP.InviteSession.hangup(InviteSession.java:55)
    
      at org.doubango.ngn.sip.NgnAVSession.hangUpCall(NgnAVSession.java:847)
    
      at cn.dazhou.railway.monitor.camera.SipVideoPresenterImpl.closeVideo(SipVideoPresenterImpl.kt:189)
    
      at cn.dazhou.railway.monitor.sip.video.VideoService.reCall(VideoService.kt:99)
    
      at cn.dazhou.railway.monitor.sip.video.VideoService$registerBroadcastReceiver$1.onReceive(VideoService.kt:62)
    
      at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:1122)
    
      at android.os.Handler.handleCallback(Handler.java:751)
    
      at android.os.Handler.dispatchMessage(Handler.java:95)
    
      at android.os.Looper.loop(Looper.java:154)
    
      at android.app.ActivityThread.main(ActivityThread.java:6121)
    
      at java.lang.reflect.Method.invoke!(Native method)
    
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
    
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
    
    
    
    

从异常信息中可以看到,这是libc.so中的函数很耗时导致的,而这个libc.so又是由libtinyWRAP.so调用,libtinyWRAP.so又由是InviteSession_hangup__SWIG_1()这个native函数调用的,这个函数又是由hangup()函数调用,嗯,非常棒,很容易就找到了那个耗时的方法了,我们把这个耗时的方法改成在子线程中调用即可。

在我的一个公司设备上是这样的,其他设备上不知道异常信息是不是也大概在这个位置,traces.txt中的内容非常多,大概9千行,我在一台公司设备上出现过两次ANR,每次都是不同方法导致的,但是异常信息大概都在200行的位置。如果在别的设备上不是在这个位置的话,如果找不到,可以直接搜索App的包名,如:cn.dazhou.railway.monitor,这样找起来就很快了,traces.txt中出现应用包名的地方也就几个地方而已。

二、模拟一个ANR异常

==========================================================================

前面讲解了如何解决ANR异常,因为之前项目这出现了两次,有些内容也记不太清,我想搞清楚一点,于是就想到了自己模拟一个ANR异常不就行了吗,然后可以在各种手机上运行测试一下。

  1. 创建一个全新的项目,界面如下:

    在这里插入图片描述

    界面很简单,就一个按钮

  2. 按钮单击事件如下:

    
    fun onClick(view: View) {
    
       Log.i("MainActivity", "准备在UI线程睡20秒钟")
    
       Thread.sleep(20 * 1000)
    
       Log.i("MainActivity", "大哥睡醒了!")
    
    }
    
    
    
    

    代码很简单,就是单击按钮的时候睡20秒钟

  3. 单击“模拟一个ANR”按钮,此时查看控制台日志,如下:

    在这里插入图片描述

    可以看到,睡了20秒,且睡醒了,并没有出现ANR异常,但是可以看到系统日志“Skipped 931 frames! The application may be doing too much work on its main thread.”,翻译成中文意思为“跳过931帧!应用程序可能在其主线程上做了太多的工作。”

  4. 没有出现我们期待的ANR异常。我们再换一种操作:单击“模拟一个ANR”按钮,然后按返回按钮,会发现界面是卡住了,过一会就能看到ANR异常信息了(注:其实也可以连接按多次“模拟一个ANR”按钮也会出现ANR,如果只连按两次也不会出现),如下:

    
    I/MainActivity: 准备在UI线程睡20秒钟
    
    I/ViewRootImpl[MainActivity]: ANR Key Analyze: No Key event currently.
    
    I/ViewRootImpl[MainActivity]: ANR Key Analyze: Previeous Event null,finish at 1970-01-01 08:00:00.000
    
    I/ViewRootImpl[MainActivity]: ANR Motion Analyze: No motion event currently.
    
    I/ViewRootImpl[MainActivity]: ANR Motion Analyze: Previeous Event MotionEvent { action=ACTION_UP, actionButton=0, id[0]=0, x[0]=570.4718, y[0]=1084.4352, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=22612318, downTime=22612281, deviceId=3, source=0x1002 },finish at 2021-03-29 16:23:49.980
    
    I/art: Thread[3,tid=30975,WaitingInMainSignalCatcherLoop,Thread*=0x769708ca00,peer=0x12cb8430,"Signal Catcher"]: reacting to signal 3
    
    I/art: Wrote stack traces to '/data/anr/traces.txt'
    
    I/art: ::: a0ea219 68d8987 59e62c8 d53b473 319369c
    
    I/art: ::: 319369c bf90460 80f30d5 9e191c3 12eb0c5
    
    I/art: ::: 12eb0c5 645e477 d5adee8 5a158d4 a8b78e6
    
     。。。此处省略3百多行art日志
    
    I/art: ::: e1a50ed c1cc94e 39a7e6f fcc1cc4 2bcd093
    
    I/art: ::: 2bcd093 9da4924 647768f ac55f9f 8b1da17
    
    I/art: ::: 8b1da17 0 0 0 0
    
    I/art: ::: 0 0 9e92a074 1c087c29 ff56c79f
    
    I/MainActivity: 大哥睡醒了!
    
    I/Choreographer: Skipped 932 frames!  The application may be doing too much work on its main thread.
    
    
    
    

    从日志中可以看到“I/art: Wrote stack traces to ‘/data/anr/traces.txt’”,这告诉了我们anr异常保存的位置。这里的日志我省略了日志时间,从日志的时间看,从准备睡眠到出现ANR异常,大概是8秒钟时间。日志中间有3百多行的art日志信息,这里我做了省略处理,从日志可以看到,虽然出现了ANR,但是最终大哥还是睡醒了,App并没有崩溃,还是可以继承使用的,点击ANR对话框的“等待”按钮可以继承使用App,ANR异常对话框如下(注:ANR日志会比ANR对话框会早几秒钟出来):

    在这里插入图片描述

    点击“等待”按钮之后,界面停留在了我们的App上,按正常按返回的话,应该是退出当前App界面的,所以,当我们的程序在UI线程做耗时操作的时候,按键事件就被吃掉了。

  5. 我们还可以使用ANRManager进行过滤,但是要去掉“Show only selected application"的限制,如下:

    在这里插入图片描述

    日志内容如下:

    
    D/ANRManager: isANRFlowSkipped() AnrFlow = 0
    
    I/ANRManager: enableTraceLog: false
    
    I/ANRManager: enableBinderLog: false
    
    E/ANRManager: writeStringToFile error: /sys/kernel/debug/binder/transaction_log_enable java.io.FileNotFoundException: /sys/kernel/debug/binder/transaction_log_enable (Permission denied)
    
    I/ANRManager: startAsyncDump: AnrDumpRecord{ Input dispatching timed out (Waiting to send key event because the focused window has not finished processing all of the input events that were previously delivered to it.  Outbound queue length: 0.  Wait queue length: 1.) ProcessRecord{66566af 13102:cn.android666.anrdemo/u0a717} IsCompleted:false IsCancelled:false }
    
    I/ANRManager: dumpAnrDebugInfo begin: AnrDumpRecord{ Input dispatching timed out (Waiting to send key event because the focused window has not finished processing all of the input events that were previously delivered to it.  Outbound queue length: 0.  Wait queue length: 1.) ProcessRecord{66566af 13102:cn.android666.anrdemo/u0a717} IsCompleted:false IsCancelled:false }, isAsyncDump = false
    
    I/ANRManager: setZramTag: 6
    
    I/ANRManager: setZramMonitor: false
    
    I/ANRManager: dumpAnrDebugInfoLocked: AnrDumpRecord{ Input dispatching timed out (Waiting to send key event because the focused window has not finished processing all of the input events that were previously delivered to it.  Outbound queue length: 0.  Wait queue length: 1.) ProcessRecord{66566af 13102:cn.android666.anrdemo/u0a717} IsCompleted:false IsCancelled:false }, isAsyncDump = false
    
    D/ANRManager: file isn't exist
    
    I/ANRManager: START_ANR_DUMP_MSG: AnrDumpRecord{ Input dispatching timed out (Waiting to send key event because the focused window has not finished processing all of the input events that were previously delivered to it.  Outbound queue length: 0.  Wait queue length: 1.) ProcessRecord{66566af 13102:cn.android666.anrdemo/u0a717} IsCompleted:false IsCancelled:false }
    
    I/ANRManager: dumpAnrDebugInfo begin: AnrDumpRecord{ Input dispatching timed out (Waiting to send key event because the focused window has not finished processing all of the input events that were previously delivered to it.  Outbound queue length: 0.  Wait queue length: 1.) ProcessRecord{66566af 13102:cn.android666.anrdemo/u0a717} IsCompleted:false IsCancelled:false }, isAsyncDump = true
    
    
  • 26
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值