Android ANR是什麼及相應的解決方法

1、什麼是 ANR?

ANR:Application Not Responding,即應用無響應

2、ANR有哪些類型?

    ANR一般有三種類型:

    1. KeyDispatchTimeout(5 seconds) --主要類型按鍵或觸摸事件在特定時間內無響應

    2. BroadcastTimeout(10 seconds) --BroadcastReceiver在特定時間內無法處理完成

    3. ServiceTimeout(20 seconds) --小概率類型 Service在特定的時間內無法處理完成

3、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

    超時原因分析:

    超時時間的計數一般是從按鍵分發給app開始。超時的原因一般有兩種:

   (1)當前的事件沒有機會得到處理(即UI線程正在處理前一個事件,沒有及時的完成或者looper被某種原因阻塞住了)

    (2)當前的事件正在處理,但沒有及時完成

4、BroadcastTimeoutServiceTimeout:

    BroadcastReceive 及Service實際上都是在UI線程中執行,如果在規定的時間內無法完成,就會阻塞主線程。

5、解決方法:

    1. UI線程儘量只做跟UI相關的工作

    2. 耗時的工作(比如數據庫操作,I/O,連接網絡或者別的有可能阻礙UI線程的操作)把它放入單獨的線程處理

    3. 儘量用Handler來處理UIthread和別的thread之間的交互

    4.在BroadcastReceive和Service中執行耗時操作時,使用IntentService執行耗時操作

6、說了那麼多的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

7、如何去分析ANR?

    先看個LOG: 

    

04-01 13:12:11.572 I/InputDispatcher( 220): Application is not responding:Window{2b263310com.android.email/com.android.email.activity.SplitScreenActivitypaused=false}.
    5009.8ms since event, 5009.5ms since waitstarted
    04-0113:12:11.572 I/WindowManager( 220): Input event
    dispatching timedout sending
    tocom.android.email/com.android.email.activity.SplitScreenActivity
 
    04-01 13:12:14.123 I/Process( 220): Sending signal. PID: 21404 SIG: 3---發生ANR的時間和生成trace.txt的時間
    04-01 13:12:14.123 I/dalvikvm(21404):threadid=4: reacting to
    signal 3
    ……
    04-0113:12:15.872 E/ActivityManager( 220): ANR in
    com.android.email(com.android.email/.activity.SplitScreenActivity)
    04-0113:12:15.872 E/ActivityManager( 220):
    Reason:keyDispatchingTimedOut
    04-0113:12:15.872 E/ActivityManager( 220): Load: 8.68 / 8.37 / 8.53
    04-0113:12:15.872 E/ActivityManager( 220): CPUusage from 4361ms to 699ms ago ----CPU在ANR發生前的使用情況
 
    04-0113:12:15.872 E/ActivityManager( 220): 5.5%21404/com.android.email: 1.3% user + 4.1% kernel / faults:
    10 minor
    04-0113:12:15.872 E/ActivityManager( 220): 4.3%220/system_server: 2.7% user + 1.5% kernel / faults: 11
    minor 2 major
    04-0113:12:15.872 E/ActivityManager( 220): 0.9%52/spi_qsd.0: 0% user + 0.9% kernel
    04-0113:12:15.872 E/ActivityManager( 220): 0.5%65/irq/170-cyttsp-: 0% user + 0.5% kernel
    04-0113:12:15.872 E/ActivityManager( 220): 0.5%296/com.android.systemui: 0.5% user + 0% kernel
    04-0113:12:15.872 E/ActivityManager( 220): 100%TOTAL: 4.8% user + 7.6% kernel + 87% iowait
    04-0113:12:15.872 E/ActivityManager( 220): CPUusage from 3697ms to 4223ms later:-- ANR後CPU的使用量
    04-0113:12:15.872 E/ActivityManager( 220): 25%21404/com.android.email: 25% user + 0% kernel / faults: 191 minor
    04-0113:12:15.872 E/ActivityManager( 220): 16% 21603/__eas(par.hakan: 16% user + 0% kernel
    04-0113:12:15.872 E/ActivityManager( 220): 7.2% 21406/GC: 7.2% user + 0% kernel
    04-0113:12:15.872 E/ActivityManager( 220): 1.8% 21409/Compiler: 1.8% user + 0% kernel
    04-0113:12:15.872 E/ActivityManager( 220): 5.5%220/system_server: 0% user + 5.5% kernel / faults: 1 minor
    04-0113:12:15.872 E/ActivityManager( 220): 5.5% 263/InputDispatcher: 0% user + 5.5% kernel
    04-0113:12:15.872 E/ActivityManager( 220): 32%TOTAL: 28% user + 3.7% kernel

從LOG可以看出ANR的類型,CPU的使用情況,如果CPU使用量接近100%,說明當前設備很忙,有可能是CPU飢餓導致了ANR

如果CPU使用量很少,說明主線程被BLOCK了

如果IOwait很高,說明ANR有可能是主線程在進行I/O操作造成的

除了看LOG,解決ANR還得需要trace.txt文件,

如何獲取呢?可以用如下命令獲取

$chmod 777 /data/anr

$rm /data/anr/traces.txt

$ps

$kill -3 PID

adbpull data/anr/traces.txt ./mytraces.txt 

    從trace.txt文件,看到最多的是如下的信息:

-----pid 21404 at 2011-04-01 13:12:14 -----
  Cmdline: com.android.email
 
  DALVIK THREADS:
  (mutexes: tll=0tsl=0 tscl=0 ghl=0 hwl=0 hwll=0)
  "main" prio=5 tid=1NATIVE
  | group="main" sCount=1 dsCount=0obj=0x2aad2248 self=0xcf70
  | sysTid=21404 nice=0 sched=0/0cgrp=[fopen-error:2]
  handle=1876218976
  atandroid.os.MessageQueue.nativePollOnce(Native Method)
  atandroid.os.MessageQueue.next(MessageQueue.java:119)
  atandroid.os.Looper.loop(Looper.java:110)
  at android.app.ActivityThread.main(ActivityThread.java:3688)
  at java.lang.reflect.Method.invokeNative(Native Method)
  atjava.lang.reflect.Method.invoke(Method.java:507)
 
  atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
  at
  com.android.internal.os.ZygoteInit.main(ZygoteInit.java:624)
  at dalvik.system.NativeStart.main(Native Method)
 說明主線程在等待下條消息進入消息隊列

8、Thread狀態

ThreadState (defined at “dalvik/vm/thread.h “)

    THREAD_UNDEFINED = -1, /* makes enum compatible with int32_t */

    THREAD_ZOMBIE = 0, /* TERMINATED */

    THREAD_RUNNING = 1, /* RUNNABLE or running now */

    THREAD_TIMED_WAIT = 2, /* TIMED_WAITING in Object.wait() */

    THREAD_MONITOR = 3, /* BLOCKED on a monitor */

    THREAD_WAIT = 4, /* WAITING in Object.wait() */

    THREAD_INITIALIZING= 5, /* allocated, not yet running */

    THREAD_STARTING = 6, /* started, not yet on thread list */

    THREAD_NATIVE = 7, /* off in a JNI native method */

    THREAD_VMWAIT = 8, /* waiting on a VM resource */

    THREAD_SUSPENDED = 9, /* suspended, usually by GC or debugger */

9、如何調查並解決ANR

    1. 首先分析log

    2. 從trace.txt文件查看調用stack.

    3. 看代碼

    4. 仔細查看ANR的成因(iowait?block?memoryleak?)

10、案例:

    

案例1:關鍵詞:ContentResolver in AsyncTask onPostExecute, high iowait

原因:IOWait很高,說明當前系統在忙於I/O,因此數據庫操作被阻塞

final Message message=Message.restoreMessageWithId(mProviderContext,messageId);
    if(message==null){
    return;
}
Account account=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();

 關於AsyncTask:http://developer.android.com/reference/android/os/AsyncTask.html

 

案例2:關鍵詞:在UI線程進行網絡數據的讀寫

    
ANRin 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的時間或者放入獨立的線程來處理。

   關於Handler的問題,可以參考:http://developer.android.com/reference/android/os/Handler.html

案例3:關鍵詞:Memoryleak/Thread leak

11-1621:41:42.560 I/ActivityManager( 1190): ANR in process:android.process.acore (last in android.process.acore)
    11-1621:41:42.560 I/ActivityManager( 1190): Annotation:keyDispatchingTimedOut
    11-16 21:41:42.560 I/ActivityManager(1190): CPU usage:
    11-16 21:41:42.560 I/ActivityManager( 1190):Load: 11.5 / 11.1 / 11.09
    11-16 21:41:42.560 I/ActivityManager(1190): CPU usage from 9046ms to 4018ms ago:
    11-16 21:41:42.560I/ActivityManager( 1190): d.process.acore:98%= 97% user + 0% kernel / faults: 1134 minor
    11-16 21:41:42.560I/ActivityManager( 1190): system_server: 0% = 0% user + 0% kernel /faults: 1 minor
    11-16 21:41:42.560 I/ActivityManager( 1190): adbd:0% = 0% user + 0% kernel
    11-16 21:41:42.560 I/ActivityManager(1190): logcat: 0% = 0% user + 0% kernel
    11-16 21:41:42.560I/ActivityManager( 1190): TOTAL:100% = 98% user + 1% kernel
 
    Cmdline: android.process.acore
 
    DALVIK THREADS:
    "main"prio=5 tid=3 VMWAIT
    |group="main" sCount=1 dsCount=0 s=N obj=0x40026240self=0xbda8
    | sysTid=1815 nice=0 sched=0/0 cgrp=unknownhandle=-1344001376
    atdalvik.system.VMRuntime.trackExternalAllocation(NativeMethod)
    atandroid.graphics.Bitmap.nativeCreate(Native Method)
    atandroid.graphics.Bitmap.createBitmap(Bitmap.java:468)
    atandroid.view.View.buildDrawingCache(View.java:6324)
    atandroid.view.View.getDrawingCache(View.java:6178)
    atandroid.view.ViewGroup.drawChild(ViewGroup.java:1541)
    ……
    atcom.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1830)
    atandroid.view.ViewRoot.draw(ViewRoot.java:1349)
    atandroid.view.ViewRoot.performTraversals(ViewRoot.java:1114)
    atandroid.view.ViewRoot.handleMessage(ViewRoot.java:1633)
    atandroid.os.Handler.dispatchMessage(Handler.java:99)
    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)
 
    "Thread-408"prio=5 tid=329 WAIT
    |group="main" sCount=1 dsCount=0 s=N obj=0x46910d40self=0xcd0548
    | sysTid=10602 nice=0 sched=0/0 cgrp=unknownhandle=15470792
    at java.lang.Object.wait(Native Method)
    -waiting on <0x468cd420> (a java.lang.Object)
    atjava.lang.Object.wait(Object.java:288)
    atcom.android.dialer.CallLogContentHelper$UiUpdaterExecutor$1.run(CallLogContentHelper.java:289)
    atjava.lang.Thread.run(Thread.java:1096)

分析:

  atdalvik.system.VMRuntime.trackExternalAllocation(NativeMethod)內存不足導致block在創建bitmap上

    **MEMINFO in pid 1360 [android.process.acore] **

            native dalvik other total

            size: 17036 23111 N/A 40147

            allocated: 16484 20675 N/A 37159

            free: 296 2436 N/A 2732

    解決:如果機器的內存族,可以修改虛擬機的內存爲36M或更大,不過最好是複查代碼,查看哪些內存沒有釋放


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章