ANR相关问题分析解决方法

第一章 Android ANR

第一节 什么是ANR

最直观的情况,当你使用一款Android APP时,系统弹出一个对话框,显示“xx无响应。要将其关闭吗?”。这就是一个应用ANR的场景,你可以选择强制关闭当前应用,也可以等待应用继续执行。

在Android中,系统通过显示ANR警示框来保护程序的长时间无响应。类似的警示界面在PC的操作系统中也会见到。

第二节 Android UI单线程模型

当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。

主线程通常又被叫做UI线程。在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。

单线程模型有先天的劣势,这意味着你的编码必须非常高效,否则事件或消息的处理可能会导致程序变得很缓慢。而当用户参与到程序运行中后,整个程序对用户的响应会变得非常迟缓。

哪些属于UI线程呢?

UI线程主要包括如下:

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

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

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

other

第三节 什么会触发ANR

超时的终极原因一般有两种:

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

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

 

ANR的诱因:

多数情况下是调用阻塞,也就是一个函数,是通过UI主线程调用下去的,但因为某种原因,该调用一直没有返回,引起超时。当前,其本质原因,可能是某些服务进程异常或者死锁等。对于一些低配手机,如果运行的任务比较多,也可能因为CPU、Mem等资源占用引起一些优先级低的响应慢而超时。

 

在Android里,应用程序的响应性是由Activity Manager和WindowManager系统服务监视的。当它监测到以下情况中的一个时,Android就会针对特定的应用程序显示ANR:

(1)在5秒内没有响应输入的事件(例如,按键按下,屏幕触摸)

(2)BroadcastReceiver在10秒内没有执行完毕

超时时间的计数一般是从按键或事件分发给app开始。

第四节 ANR的类型

ANR一般有三种类型:

1:KeyDispatchTimeout(5 seconds) --主要类型

按键或触摸事件在特定时间内无响应

ActivityManagerService.java中定义:

static final int KEY_DISPATCHING_TIMEOUT = 5*1000;

 

2:BroadcastTimeout(10 seconds)

BroadcastReceiver在特定时间内无法处理完成。

ActivityManagerService.java中定义:

前台用户操作发出的广播:

static final int BROADCAST_FG_TIMEOUT = 10*1000;

后台非用户操作发出的广播:

static final int BROADCAST_BG_TIMEOUT = 60*1000;

 

3:ServiceTimeout(20 seconds) --小概率类型

Service在特定的时间内无法处理完成。

ActiveServices.java中定义,规定了前后台服务的超时时间:

// How long we wait for a service to finish executing.

static final int SERVICE_TIMEOUT = 20*1000;

// How long we wait for a service to finish executing.

static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;

第二章 如何避免ANR

考虑上面的ANR定义,让我们来研究一下为什么它会在Android应用程序里发生和如何最佳构建应用程序来避免ANR。

Android程序通常是执行在默认的UI线程(也可以成为main线程)中的。这意味着在UI线程中执行的任何长时间的操作都可能触发ANR,因为程序没有给自己处理输入事件或者broadcast事件的机会。

通常来说,系统会在程序无法响应用户的输入事件时显示ANR。例如,如果一个程序在UI线程执行I/O操作(通常是网络请求或者是文件读写),这样系统就无法处理用户的输入事件。或者是应用在UI线程花费了太多的时间用来建立一个复杂的在内存中的数据结构,又或者是在一个游戏程序的UI线程中执行了一个复杂耗时的计算移动的操作。确保那些计算操作高效是很重要的,不过即使是最高效的代码也是需要花时间执行的。

通常来说对Android应用,避免ANR需要遵循以下几个原则:

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

对于你的应用中任何可能执行时间长的操作,你都不应该执行在UI线程。你可以创建一个工作线程,把那些操作都执行在工作线程中。这确保了UI线程(这个线程会负责处理UI事件) 能够顺利执行,也预防了系统因代码僵死而崩溃。因为UI线程是和类级别相关联的,你可以把相应性作为一个类级别(class-level)的问题(相比来说,代码性能则属于方法级别(method-level)的问题)。

 

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

任何执行在UI线程的方法都应该尽可能的简短快速。特别是,在activity的生命周期的关键方法 onCreate()与 onResume()方法中应该尽可能的做比较少的事情。类似网络或者DB操作等可能长时间执行的操作,或者是类似调整bitmap大小等需要长时间计算的操作,都应该执行在工作线程中。(在DB操作中,可以通过异步的网络请求)。

 

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

潜在的耗时操作,例如网络或数据库操作,或者高耗时的计算如改变位图尺寸,应该在子线程里(或者以数据库操作为例,通过异步请求的方式)来完成。然而,不是说你的主线程阻塞在那里等待子线程的完成——也不是调用Thread.wait()或是Thread.sleep()。替代的方法是,主线程应该为子线程提供一个Handler,以便完成时能够提交给主线程。以这种方式设计你的应用程序,将能保证你的主线程保持对输入的响应性并能避免由于5秒输入事件的超时引发的ANR对话框。这种做法应该在其它显示UI的线程里效仿,因为它们都受相同的超时影响。

第三章 ANR情景分析

以上所讨论的ANR的介绍和如何避免发生ANR可以说对我们设计和开发应用程序提供了很好的规范。但是我们某些情况下并不能完全遵守,或者由于经验的关系某些代码的实现还是粗暴的。在程序发布前期性能测试时往往容易暴露这些问题。当我们拿到一堆无响应的问题点时,我们需要去分析问题、找到性能瓶颈,并加以优化解决。而分析ANR问题我们也形成了一些方法和经验。

Traces文件

当一个应用程序发生ANR后,系统会生成一个trace文件到/data/anr/目录,traces.txt文件总表示上一个出现的ANR。通过分析这个traces文件以及配合logcat日志,我们可以对ANR问题的成因做出分析。

 

案例一:

主线程ContentResolver 数据库IO操作长时间不返回

  Process:com.android.email
Activity:com.android.email/.activity.MessageView
Subject:keyDispatchingTimedOut
CPU usage from 2550ms to -2814ms ago:
5%187/system_server: 3.5% user + 1.4% kernel / faults: 86 minor 20major
4.4% 1134/com.android.email: 0.7% user + 3.7% kernel /faults: 38 minor 19 major
4% 372/com.android.eventstream: 0.7%user + 3.3% kernel / faults: 6 minor
1.1% 272/com.android.phone:0.9% user + 0.1% kernel / faults: 33 minor
0.9%252/com.android.systemui: 0.9% user + 0% kernel
0%409/com.android.eventstream.telephonyplugin: 0% user + 0% kernel /faults: 2 minor
0.1% 632/com.android.devicemonitor: 0.1% user + 0%kernel
100%TOTAL: 6.9% user + 8.2% kernel +84%iowait


-----pid 1134 at 2010-12-17 17:46:51 -----
Cmd line:com.android.email

DALVIK THREADS:
(mutexes: tll=0 tsl=0tscl=0 ghl=0 hwl=0 hwll=0)
"main" prio=5 tid=1 WAIT
|group="main" sCount=1 dsCount=0 obj=0x2aaca180self=0xcf20
| sysTid=1134 nice=0 sched=0/0 cgrp=[fopen-error:2]handle=1876218976
at java.lang.Object.wait(Native Method)
-waiting on <0x2aaca218> (a java.lang.VMThread)
atjava.lang.Thread.parkFor(Thread.java:1424)
atjava.lang.LangAccessImpl.parkFor(LangAccessImpl.java:48)
atsun.misc.Unsafe.park(Unsafe.java:337)
atjava.util.concurrent.locks.LockSupport.park(LockSupport.java:157)
atjava.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:808)
atjava.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:841)
atjava.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1171)
atjava.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:200)
atjava.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:261)
atandroid.database.sqlite.SQLiteDatabase.lock(SQLiteDatabase.java:378)
atandroid.database.sqlite.SQLiteCursor.<init>(SQLiteCursor.java:222)
atandroid.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:53)
atandroid.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1356)
atandroid.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1235)
atandroid.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1189)
atandroid.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1271)
atcom.android.email.provider.EmailProvider.query(EmailProvider.java:1098)
atandroid.content.ContentProvider$Transport.query(ContentProvider.java:187)
atandroid.content.ContentResolver.query(ContentResolver.java:268)
atcom.android.email.provider.EmailContent$Message.restoreMessageWithId(EmailContent.java:648)
atcom.android.email.Controller.setMessageRead(Controller.java:658)
atcom.android.email.activity.MessageView.onMarkAsRead(MessageView.java:700)
atcom.android.email.activity.MessageView.access$2500(MessageView.java:98)
atcom.android.email.activity.MessageView$LoadBodyTask.onPostExecute(MessageView.java:1290)
atcom.android.email.activity.MessageView$LoadBodyTask.onPostExecute(MessageView.java:1255)
atandroid.os.AsyncTask.finish(AsyncTask.java:417)
atandroid.os.AsyncTask.access$300(AsyncTask.java:127)
atandroid.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
atandroid.os.Handler.dispatchMessage(Handler.java:99)
atandroid.os.Looper.loop(Looper.java:123)
atandroid.app.ActivityThread.main(ActivityThread.java:3652)
atjava.lang.reflect.Method.invokeNative(Native Method)
atjava.lang.reflect.Method.invoke(Method.java:507)
atcom.android.internal.os.ZygoteIn
  原因:IOWait很高,说明当前系统在忙于I/O,因此数据库操作被阻塞
  
  原来:
  finalMessagemessage=Message.restoreMessageWithId(mProviderContext,messageId);
  if(message==null){
     return;
  }
  
  Accountaccount=Account.restoreAccountWithId(mProviderContext,message.mAccountKey);
  
  if(account==null){
     return;//isMessagingController returns false for null, but let's make itclear.
  }
  
  if(isMessagingController(account)){
     new Thread(){
         @Override
         public void run(){
            mLegacyController.processPendingActions(message.mAccountKey);
         }
     }.start();
  }
  
  解决后:
  newThread() {
      finalMessagemessage=Message.restoreMessageWithId(mProviderContext,messageId);
  
      if(message==null){
          return;
      }
  
      Accountaccount=Account.restoreAccountWithId(mProviderContext,message.mAccountKey);
  
      if(account==null){
         return;//isMessagingController returns false for null, but let's make itclear.
      }
  
      if(isMessagingController(account)) {
          mLegacyController.processPendingActions(message.mAccountKey);
      }
  }.start();

案例二:

在UI线程进行网络数据的读写

  ANR in process: com.android.mediascape:PhotoViewer (last incom.android.mediascape:PhotoViewer)
Annotation:keyDispatchingTimedOut
CPU usage:
Load: 6.74 / 6.89 / 6.12
CPUusage from 8254ms to 3224ms ago:
ovider.webmedia: 4% = 4% user +0% kernel / faults: 68 minor
system_server: 2% = 1% user + 0%kernel / faults: 18 minor
re-initialized>: 0% = 0% user + 0%kernel / faults: 50 minor
events/0: 0% = 0% user + 0%kernel
TOTAL:7% = 6% user + 1% kernel

DALVIKTHREADS:
""main"" prio=5 tid=3 NATIVE
|group=""main"" sCount=1 dsCount=0 s=Yobj=0x4001b240 self=0xbda8
| sysTid=2579 nice=0 sched=0/0cgrp=unknown handle=-1343993184
atorg.apache.harmony.luni.platform.OSNetworkSystem.receiveStreamImpl(NativeMethod)
atorg.apache.harmony.luni.platform.OSNetworkSystem.receiveStream(OSNetworkSystem.java:478)
atorg.apache.harmony.luni.net.PlainSocketImpl.read(PlainSocketImpl.java:565)
atorg.apache.harmony.luni.net.SocketInputStream.read(SocketInputStream.java:87)
atorg.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnection$LimitedInputStream.read(HttpURLConnection.java:303)
atjava.io.InputStream.read(InputStream.java:133)
atjava.io.BufferedInputStream.fillbuf(BufferedInputStream.java:157)
atjava.io.BufferedInputStream.read(BufferedInputStream.java:346)
atandroid.graphics.BitmapFactory.nativeDecodeStream(Native Method)
atandroid.graphics.BitmapFactory.decodeStream(BitmapFactory.java:459)
atcom.android.mediascape.activity.PhotoViewerActivity.getPreviewImage(PhotoViewerActivity.java:4465)
atcom.android.mediascape.activity.PhotoViewerActivity.dispPreview(PhotoViewerActivity.java:4406)
atcom.android.mediascape.activity.PhotoViewerActivity.access$6500(PhotoViewerActivity.java:125)
atcom.android.mediascape.activity.PhotoViewerActivity$33$1.run(PhotoViewerActivity.java:4558)
atandroid.os.Handler.handleCallback(Handler.java:587)
atandroid.os.Handler.dispatchMessage(Handler.java:92)
atandroid.os.Looper.loop(Looper.java:123)
atandroid.app.ActivityThread.main(ActivityThread.java:4370)
atjava.lang.reflect.Method.invokeNative(Native Method)
atjava.lang.reflect.Method.invoke(Method.java:521)
atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
atcom.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
atdalvik.system.NativeStart.main(Native Method)

关于网络连接,在设计的时候可以设置个timeout的时间或者放入独立的线程来处理。

案例三:

Cpu资源统计100%或者接近100%

  07-21 14:55:00.625  1376  1390 E ActivityManager: ANR in com.tencent.mobileqq
  07-21 14:55:00.625  1376  1390 E ActivityManager: Reason: Broadcast of Intent { act=android.intent.action.SCREEN_ON flg=0x40000000 }
  07-21 14:55:00.625  1376  1390 E ActivityManager: Load: 16.32 / 13.7 / 7.58
  07-21 14:55:00.625  1376  1390 E ActivityManager: CPU usage from 0ms to 27668ms later:
  07-21 14:55:00.625  1376  1390 E ActivityManager:   62% 2180/com.tencent.mobileqq: 59% user + 2.2% kernel / faults: 58 minor
  07-21 14:55:00.625  1376  1390 E ActivityManager:   16% 1138/mediaserver: 2.5% user + 14% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   11% 1376/system_server: 8.9% user + 2.8% kernel / faults: 235 minor
  07-21 14:55:00.625  1376  1390 E ActivityManager:   3.2% 1128/adbd: 0.7% user + 2.5% kernel / faults: 16 minor
  07-21 14:55:00.625  1376  1390 E ActivityManager:   1.5% 5/events/0: 0% user + 1.5% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0.9% 1306/sm: 0.4% user + 0.5% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0.9% 1456/com.android.systemui: 0.8% user + 0.1% kernel / faults: 98 minor
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0.5% 1449/MOAL_WORK_QUEUE: 0% user + 0.5% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0.4% 1451/ksdioirqd/mmc2: 0% user + 0.4% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0% 253/irq/4-88pm860x: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0.2% 679/kondemand/0: 0% user + 0.2% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0.1% 1121/galcore daemon : 0% user + 0.1% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0% 1108/yaffs-bg-1: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0% 1307/atcmdsrv: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0% 1385/mma7660fc: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0% 1487/com.android.phone: 0% user + 0% kernel / faults: 2 minor
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0% 1489/com.android.launcher: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0% 6/khelper: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0% 254/88pm860x: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0% 631/file-storage: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0% 1123/galcore guard t: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0% 1133/vold: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0% 1136/rild: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0% 1144/simal: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0% 1554/wpa_supplicant: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0% 2211/com.tencent.mobileqq:sc: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:  +0% 3763/flush-31:14: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager: 100% TOTAL: 75% user + 23% kernel + 0.5% softirq
  07-21 14:55:00.625  1376  1390 E ActivityManager: CPU usage from 24385ms to 27245ms later with 99% awake:
  07-21 14:55:00.625  1376  1390 E ActivityManager:   58% 2180/com.tencent.mobileqq: 55% user + 2.3% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:     37% 2545/MSF: 37% user + 0.7% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:     5.5% 2544/MSF: 5.5% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:     2.3% 2359/er$SensorThread: 2.3% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:     0.7% 2978/MSF: 0.7% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:     0.7% 2982/ClientRecordThr: 0% user + 0.7% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   16% 1138/mediaserver: 2.5% user + 14% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:     10% 3723/CameraPreviewTh: 0.8% user + 9.2% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:     2.9% 2981/Record Thread 0: 2.5% user + 0.4% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:     2.1% 3715/mediaserver: 0% user + 2.1% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:     1.6% 1373/Playback Thread: 0.8% user + 0.8% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   16% 1376/system_server: 8.8% user + 7.2% kernel / faults: 4 minor
  07-21 14:55:00.625  1376  1390 E ActivityManager:     6.2% 1382/SurfaceFlinger: 4.6% user + 1.5% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:     3.1% 1389/er.ServerThread: 2.6% user + 0.5% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:     2.6% 1390/ActivityManager: 1% user + 1.5% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:     2% 1411/ScreenOffThread: 0% user + 2% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:     0.5% 1388/SensorService: 0% user + 0.5% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:     0.5% 1410/UEventObserver: 0.5% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:     0.5% 1455/er$SensorThread: 0% user + 0.5% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   1.7% 5/events/0: 0% user + 1.7% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0% 6/khelper: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0.3% 679/kondemand/0: 0% user + 0.3% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0.5% 1449/MOAL_WORK_QUEUE: 0% user + 0.5% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager:   0.5% 1456/com.android.systemui: 0.5% user + 0% kernel / faults: 2 minor
  07-21 14:55:00.625  1376  1390 E ActivityManager:    +0% 3809/Thread-358: 0% user + 0% kernel
  07-21 14:55:00.625  1376  1390 E ActivityManager: 100% TOTAL: 78% user + 21% kernel + 0.3% softirq

ANR发生前的CPU占用率到达了100%,这种情况下程序的运行会比平时慢很多。这种ANR需要结合traces.txt来看主线程调用栈中是否有耗时的操作,如果文件或数据库操作,如果没有,那么CPU占用可能就是最终导致程序执行超时的原因。

案例四:

死锁,线程间互相持有锁:

  "PowerManagerService" prio=5 tid=24 MONITOR
  |  group="main" sCount=1 dsCount=0 obj=0x41dd0eb0 self=0x5241b218
  |  sysTid=567 nice=0 sched=0/0 cgrp=apps handle=1380038664
  |  state=S schedstat=( 6682116007 11324451214 33313 ) utm=450 stm=219 core=1
  at com.android.server.am.ActivityManagerService.broadcastIntent(ActivityManagerService.java:~13045)
  - waiting to lock <0x41a874a0> (a com.android.server.am.ActivityManagerService) held by tid=12
  (android.server.ServerThread)
  at android.app.ContextImpl.sendBroadcast(ContextImpl.java:1144)
  at com.android.server.power.powerManagerService$DisplayBlankerI mpl.unblankAllDisplays(powerManagerService.java:3442)
  at com.android.server.power.DisplaypowerState$PhotonicModulator$1.run(DisplaypowerState.java:456)
  at android.os.Handler.handleCallback(Handler.java:800)
  at android.os.Handler.dispatchMessage(Handler.java:100)
  at android.os.Looper.loop(Looper.java:194)
  at android.os.HandlerThread.run(HandlerThread.java:60)
  
  "Binder_B" prio=5 tid=85 MONITOR
  |  group="main" sCount=1 dsCount=0 obj=0x 42744770 self=0x58329e88
  |  sysTid=3700 nice=-20 sched=0/0 cgrp=apps handle=1471424616
  |  state=S schedstat=( 1663727513 2044643318 6806 ) utm=132 stm=34 core=1
  at com.android.server.power.powerManagerService$DisplayBlankerImpl.toString(powerManagerService.java:~3449)
  - waiting to lock <0x41a7e420> (a com.android.server.power.powerManagerService$DisplayBlankerImpl) held by tid=24
  (PowerManagerService)
  at java.lang.StringBuilder.append(StringBuilder.java:202)
  at com.android.server.power.powerManagerService.dump(powerManagerService.java:3052)
  at android.os.Binder.dump(Binder.java:264)
  at android.os.Binder.onTransact(Binder.java:236)
  at android.os.I powerManager$Stub.onTransact(IpowerManager.java:373)
  at android.os.Binder.ex ecTransact(Binder.java:351)
  at dalvik.system.N ativeStart.run(Native Method)
  
  "android.server.ServerThread" prio=5 tid=12 MONITOR
  |  group="main" sCount=1 dsCount=0 obj=0x 41a76178 self=0x 507837a8
  |  sysTid=545 nice=-2 sched=0/0 cgrp=apps handle=1349936616
  |  state=S schedstat=( 15368096286 21707846934 69485 ) utm=1226 stm=310 core=0
  at com.android.server.power.powerManagerService.isScreenOnI nternal(powerManagerService.java:~2529)
  - waiting to lock <0x41a7e2e8> (a java.lang.Object) held by tid=85 (Binder_B)
  at com.android.server.power.powerManagerService.isScreenOn(powerManagerService.java:2522)
  at com.android.server.wm.WindowmanagerService.sendScreenStatusToClientsLocked(WindowmanagerService.java:7749)
  at com.android.server.wm.WindowmanagerService.setEventDispatching(WindowmanagerService.java:7628)
  at com.android.server.am.ActivityManagerService.updateEventDispatchingLocked(ActivityManagerService.java:8083)
  at com.android.server.am.ActivityManagerService.w akingU p(ActivityManagerService.java:8077)
  at com.android.server.power.Notifier.sendWakeUpBroadcast(Notifier.java:474)
  at com.android.server.power.Notifier.sendNextBroadcast(Notifier.java:455)
  at com.android.server.power.Notifier.access$700(Notifier.java:62)
  at com.android.server.power.Notifier$NotifierHandler.handleMessage(Notifier.java:600)
  at android.os.Handler.dispatchMessage(Handler.java:107)
  at android.os.Looper.loop(Looper.java:194)
  at com.android.server.ServerThread.run(SystemServer.java:1328)
  
  从trace文件看,是因为TID为24的线程等待一个TID为12的线程持有的锁,TID为12的线程等待一个TID为85的线程持有的锁,
  而TID为85的线程确等待一个TID为24的线程持有的锁,导致了循环等待的现象,对应的trace文件的语句如下:
  TID 24:- waiting to lock <0x 41a874a0> (a com.android.server.am.ActivityManagerService) held by tid=12
  (android.server.ServerThread)
  TI D 12: - waiting to lock <0x 41a7e2e8> (a java.lang.Object) held by tid=85 (Binder_B)
  TI D 85:- waiting to lock <0x 41a7e420> (a com.android.server.pow er.Pow erManagerService$DisplayBlankerImpl) held by
  tid=24 (PowerManagerService)

案例五:

在主线程处理大量图片,函数执行长时间不返回。


  
  JNI: CheckJNI is off; workarounds are on; pins=0; globals=430
  
  DALVIK THREADS:
  (mutexes: tll=0 tsl=0 tscl=0 ghl=0)
  
  "main" prio=5 tid=1 SUSPENDED
    | group="main" sCount=1 dsCount=0 obj=0x41594370 self=0x414cc4a8
    | sysTid=676 nice=0 sched=0/0 cgrp=apps handle=1074106708
    | state=S schedstat=( 40866013025 1474228595 30980 ) utm=3679 stm=407 core=2
    #00  pc 0002191c  /system/lib/libc.so (__futex_syscall3+8)
    #01  pc 0000ef5c  /system/lib/libc.so (__pthread_cond_timedwait_relative+48)
    #02  pc 0000efbc  /system/lib/libc.so (__pthread_cond_timedwait+64)
    #03  pc 000535fb  /system/lib/libdvm.so
    #04  pc 00053bc1  /system/lib/libdvm.so (dvmChangeStatus(Thread*, ThreadStatus)+34)
    #05  pc 00049477  /system/lib/libdvm.so
    #06  pc 0004d169  /system/lib/libdvm.so
    #07  pc 0004ea9b  /system/lib/libandroid_runtime.so
    #08  pc 00078165  /system/lib/libandroid_runtime.so (GraphicsJNI::createBitmap(_JNIEnv*, SkBitmap*, _jbyteArray*, int, _jbyteArray*, _jintArray*, int)+56)
    #09  pc 00074127  /system/lib/libandroid_runtime.so
    #10  pc 0001db4c  /system/lib/libdvm.so (dvmPlatformInvoke+112)
    #11  pc 0004e093  /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+398)
    #12  pc 00026f60  /system/lib/libdvm.so
    #13  pc 0002df78  /system/lib/libdvm.so (dvmMterpStd(Thread*)+76)
    #14  pc 0002b5dc  /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
    #15  pc 000604b5  /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+336)
    #16  pc 0004c671  /system/lib/libdvm.so
    #17  pc 0004f8e1  /system/lib/libandroid_runtime.so
    #18  pc 00063495  /system/lib/libandroid_runtime.so (android::NativeInputEventReceiver::consumeEvents(_JNIEnv*, bool, long long, bool*)+368)
    #19  pc 000636a7  /system/lib/libandroid_runtime.so
    #20  pc 0001db4c  /system/lib/libdvm.so (dvmPlatformInvoke+112)
    #21  pc 0004e093  /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+398)
    #22  pc 00026f60  /system/lib/libdvm.so
    #23  pc 0002df78  /system/lib/libdvm.so (dvmMterpStd(Thread*)+76)
    #24  pc 0002b5dc  /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
    #25  pc 00060799  /system/lib/libdvm.so (dvmInvokeMethod(Object*, Method const*, ArrayObject*, ArrayObject*, ClassObject*, bool)+392)
    #26  pc 00068707  /system/lib/libdvm.so
    #27  pc 00026f60  /system/lib/libdvm.so
    #28  pc 0002df78  /system/lib/libdvm.so (dvmMterpStd(Thread*)+76)
    #29  pc 0002b5dc  /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
    #30  pc 000604b5  /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+336)
    #31  pc 00049c7b  /system/lib/libdvm.so
    at android.graphics.Bitmap.nativeCopy(Native Method)
    at android.graphics.Bitmap.copy(Bitmap.java:556)
    at com.hmct.vision.utils.BitmapHelper.copyBitmap(BitmapHelper.java:203)
    at com.hmct.vision.Launcher.getPagePreview(Launcher.java:9147)
    at com.hmct.vision.Launcher.showPreviews(Launcher.java:9204)
    at com.hmct.vision.Workspace.showPreviews(Workspace.java:6087)
    at com.hmct.vision.Workspace$MyScaleListener.onScale(Workspace.java:6164)
    at android.view.ScaleGestureDetector.onTouchEvent(ScaleGestureDetector.java:437)
    at com.hmct.vision.Workspace.onInterceptTouchEvent(Workspace.java:1174)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1859)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2187)
    at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1523)
    at android.app.Activity.dispatchTouchEvent(Activity.java:2458)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2135)
    at android.view.View.dispatchPointerEvent(View.java:7891)
    at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4027)
    at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3906)
    at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3472)
    at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3522)
    at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3491)
    at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3598)
    at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3499)
    at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3655)
    at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3472)
    at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3522)
    at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3491)
    at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3499)
    at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3472)
    at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5612)
    at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5592)
    at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5563)
    at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5692)
    at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
    at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
    at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:176)
    at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:5665)
    at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:5711)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
    at android.view.Choreographer.doCallbacks(Choreographer.java:574)
    at android.view.Choreographer.doFrame(Choreographer.java:542)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
    at android.os.Handler.handleCallback(Handler.java:733)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:136)
    at android.app.ActivityThread.main(ActivityThread.java:5001)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:801)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:617)
    at dalvik.system.NativeStart.main(Native Method)

从trace文件看Launcher的showPreviews操作需要创建各屏幕的缩略图,如果是同步操作,那么随着屏幕数增多,ANR的概率就会越大。需要异步的处理这类缩略图显示。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值