1. 程式人生 > >Android-ANR總結原理分析

Android-ANR總結原理分析

1、概述
ANR即Application Not Responding(應用程式無響應),一般在ANR的時候會彈出一個應用無響應對話方塊,同時會候產生一個日誌檔案trace.txt,位於/data/anr/資料夾下面,trace檔案是Android Davik虛擬機器在收到異常終止訊號時產生的,最常見的一個觸發條件就是Android應用中產生了FC(force close)。由於該檔案的產生是在DVM中的,所以只有執行DVM例項的程序才能產生該檔案,也就是說只有Java程式碼才能產生該檔案,App應用的Native層(如Android Library、用c/c++編譯的庫)即使異常也不會產生ANR日誌檔案。我們可以通過ANR產生的traces日誌檔案分析應用在哪裡產生了ANR,以此來有效解決應用中的ANR。

2、ANR產生的原因

只用當應用程式的UI執行緒響應超時才會引起ANR,超時原因一般有兩種:

1.當前的事件沒有機會得到處理,例如UI執行緒正在響應另一個事件,當前事件由於某種原因被阻塞了。

2.當前的事件正在被處理,但是由於好事太長沒有能夠及時完成

根據ANR產生的原因不同,超時時間也不盡相同,從本質上講,產生ANR的原因有三種,大致可以對應到Android中四大元件中的三個(Activity、BroadcastReceive、Service)

第一種:KeyDispatchTimeout:最常見的一種型別,原因是View事件或者觸控事件在特定時間內(5s)無法得到響應

第二種:BroadcastTimeout:BroadcastReceiver的onReceive函式執行在主執行緒,並在特定的時間內(10s)無法完成處理

第三種:ServiceTimeout:Service的各個生命週期函式在特定時間內(20s)無法完成響應

3.典型的ANR場景

1)主執行緒頻繁進行IO操作,比如讀寫檔案或者資料庫;
2)硬體操作如進行呼叫照相機或者錄音等操作;
3)多執行緒操作的死鎖,導致主執行緒等待超時;
4)主執行緒操作呼叫join()方法、sleep()方法或者wait()方法;
5)耗時動畫/耗資源行為導致CPU負載過重
6)system server中發生WatchDog ANR;
7)service binder的數量達到上限

4.ANR的定位和分析

1)Logcat分析

查詢關鍵字(ANR|ActivityManager)
這裡寫圖片描述

/system_process E/ActivityManager:
ANR in admanager.lbjfan.com.anrdemo (admanager.lbjfan.com.anrdemo/.MainActivity)
                                                             PID: 12639
                                                             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.  Wait queue length: 6.  Wait queue head age: 5841.3ms.)
                                                             Load: 13.28 / 11.53 / 9.48
                                                             CPU usage from 71228ms to 0ms ago (1970-03-01 00:08:47.864 to 1970-03-01 00:09:59.093):
                                                               15% 920/system_server: 9.2% user + 5.9% kernel / faults: 10139 minor 285 major
                                                               8.2% 13985/com.tencent.mm: 6.5% user + 1.6% kernel / faults: 35481 minor 1879 major
                                                               0.1% 555/fingerprintd: 0% user + 0.1% kernel / faults: 51 minor 22 major
                                                               3.5% 266/mmcqd/0: 0% user + 3.5% kernel
                                                               3.2% 4424/com.tencent.android.qqdownloader:daemon: 1.7% user + 1.5% kernel / faults: 12007 minor 357 major
                                                               3.2% 430/adbd: 0.4% user + 2.7% kernel / faults: 2002 minor
                                                               3.1% 135/kswapd0: 0% user + 3.1% kernel
                                                               1.8% 12271/com.tencent.mobileqq: 1.2% user + 0.5% kernel / faults: 8799 minor 580 major
                                                               1.6% 11695/com.cleanmaster.mguard: 1.5% user + 0.1% kernel / faults: 9171 minor 72 major
                                                               1.3% 13039/com.tencent.mm:push: 0.9% user + 0.3% kernel / faults: 9969 minor 192 major
                                                               1.2% 4954/com.google.android.gms: 0.9% user + 0.2% kernel / faults: 7546 minor 209 major
                                                               1.1% 342/logd: 0.3% user + 0.8% kernel / faults: 628 minor 3 major
                                                               1.1% 1485/kworker/u13:3: 0% user + 1.1% kernel
                                                               1.1% 10/rcu_preempt: 0% user + 1.1% kernel
                                                               1.1% 12166/com.android.vending: 0.8% user + 0.3% kernel / faults: 9897 minor 380 major
                                                               1% 3846/com.tencent.qqmusic:QQPlayerService: 0.6% user + 0.4% kernel / faults: 7354 minor 485 major
                                                               1% 10486/kworker/u13:4: 0% user + 1% kernel
                                                               1% 11251/kworker/u13:1: 0% user + 1% kernel
                                                               1% 9498/com.cleanmaster.security:DefendService: 0.7% user + 0.3% kernel / faults: 11998 minor 287 major
                                                               0.9% 1973/kworker/u13:5: 0% user + 0.9% kernel
                                                               0.9% 14113/com.tencent.mm:exdevice: 0.7% user + 0.1% kernel / faults: 8802 minor 142 major
                                                               0.8% 10814/com.tencent.qqmusic: 0.4% user + 0.4% kernel / faults: 9823 minor 221 major
                                                               0.8% 2062/sogou.mobile.explorer: 0.5% user + 0.3% kernel / faults: 8532 minor 1288 major
                                                               0.8% 528/netd: 0.1% user + 0.7% kernel / faults: 4203 minor 35 major
                                                               0.8% 3925/com.google.android.gms.persistent: 0.4% user + 0.3% kernel / faults: 12578 minor 546 major
                                                               0.7% 556/cnss_diag: 0.6% user + 0% kernel / faults: 121 minor 5 major
                                                               0.6% 4971/com.cleanmaster.mguard:service: 0.4% user + 0.2% kernel / faults: 7468 minor 174 major
                                                               0.5% 9180/com.tencent.android.qqdownloader: 0.2% user + 0.3% kernel / faults: 9571 minor 216 major
                                                               0.5% 15/ksoftirqd/1: 0% user + 0.5% kernel
                                                               0.4% 3280/com.android.phone: 0.2% user + 0.2% kernel / faults: 1857 minor 133 major
                                                               0.4% 8489/kworker/0:1: 0% user + 0.4% kernel
                                                               0.4% 3127/sdcard: 0% user + 0.4% kernel / faults: 92 minor 17 major
                                                               0.4% 397/servicemanager: 0.1% user + 0.2% kernel / faults: 127 minor
                                                               0.4% 11878/swift.space.cleaner.free:service: 0.2% user + 0.1% kernel / faults: 6087 minor 140 major
                                                               0.4% 20/ksoftirqd/2: 0% user + 0.4% kernel
                                                               0.4% 8761/com.netease.cloudmusic:play: 0.3% user + 0% kernel / faults: 4819 minor 977 major
                                                               0.3% 6525/com.tencent.qqlive:services: 0.2% user + 0.1% kernel / faults: 7834 minor 483 major
                                                               0.3% 12250/com.tencent.mobileqq:MSF: 0.2% user + 0.1% kernel / faults: 5368 minor 114 major
                                                               0.3% 9717/com.speed.boost.booster:service: 0.1% user + 0.1% kernel / faults: 5526 minor 77 major
                                                               0.3% 8524/sogou.mobile.explorer:push_service: 0.2% user + 0.1% kernel / faults: 6280 minor 42 major
                                                               0.3% 427/irq/215-fc38800: 0% user + 0.3% kernel
                                                               0.3% 8721/kworker/1:2: 0% user + 0.3% kernel
                                                               0.3% 260/cfinteractive: 0% user + 0.3% kernel
                                                               0.3% 294/msm-core:sampli: 0% user + 0.3% kernel
                                                               0.1% 8756/kworker/u12:3: 0% user + 0.1% kernel
                                                               0.1% 11204/kworker/2:0: 0% user + 0.1% kernel
                                                               0.3% 3150/com.android.systemui: 0.1% user + 0.1% kernel / faults: 3318 minor 129 major
                                                               0.2% 7244/kworker/u12:2: 0% user + 0.2% kernel
                                                               0% 3084/VosMCThread: 0% user + 0% kerne

可以看到,Logcat日誌資訊中主要包含如下內容:

1)導致ANR的類名及所在包名:
admanager.lbjfan.com.anrdemo (admanager.lbjfan.com.anrdemo/.MainActivity)

2)導致ANR的程序名及ID:admanager.lbjfan.com.anrdemo,12639

3)ANR產生的原因(型別):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. Wait queue length: 6. Wait queue head age: 5841.3ms.),明顯屬於KeyDispatchTimeout型別。

4)系統中CPU使用率的統計資訊及某段時間內的變換情況

2).從trace.txt檔案分析

ANR Logcat資訊可以幫助我們分析引發ANR的具體類的資訊以及ANR的型別,但是卻無法幫助我們定位到具體引發問題的程式碼行,這時候就需要藉助ANR發生過程中生成的堆疊資訊檔案data/anr/trace.txt

獲取trace檔案:adb pull /data/anr/trace.txt

trace.txt檔案分析

由於trace檔案記錄的是整個手機的ANR日誌,所以我們需要根據程序名(包名)和ANR發生的時間找到對應日誌,具體以pid 程序id開始,以pid程序id結束。由於阻塞始終會發生在主執行緒,因此我們需要關注
執行緒名為main的執行緒狀態。下面摘出一部分關鍵日誌進行分析:

//關鍵日誌的起始標記
----- pid 20678 at 2018-08-13 21:58:59 -----
//應用程式包名
Cmd line: admanager.lbjfan.com.anrdemo
Build fingerprint: 'Android/aosp_bullhead/bullhead:7.1.2/N2G48C/han-li03221443:userdebug/test-keys'

//手機的CPU架構
ABI: 'arm64'

//堆記憶體資訊
Heap: 33% free, 4MB/6MB; 27144 objects
Dumping cumulative Gc timings

Total time spent in GC: 10.680ms
Mean GC size throughput: 68MB/s
Mean GC object throughput: 1.32996e+06 objects/s
Total number of allocations 41348
Total bytes allocated 5MB
Total bytes freed 753KB

//手機Memory記憶體資訊
Free memory 2MB
Free memory until GC 2MB
Free memory until OOME 187MB
Total memory 6MB
Max memory 192MB
Zygote space size 1128KB
Total mutator paused time: 463us
Total time waiting for GC to complete: 938ns
Total GC count: 1
Total GC time: 10.680ms
Total blocking GC count: 0
Total blocking GC time: 0

//主執行緒日誌分析
//基本資訊:main-執行緒名稱,prio-執行緒優先順序,tid-執行緒id,Sleeping-執行緒狀態
"main" prio=5 tid=1 Sleeping
  //詳細資訊:group-執行緒組名稱,sCount-執行緒被掛起的次數,dsCount-執行緒被偵錯程式颳起的次數,obj-執行緒的Java物件地址,self-執行緒本身的Native物件地址
  | group="main" sCount=1 dsCount=0 obj=0x75190ed0 self=0x7f72095a00
  //執行緒的排程資訊:sysTid-linux系統中核心執行緒id(觀察發現主執行緒的執行緒號和程序號相同),nice-執行緒排程的優先順序,cgrp-執行緒排程組,sched-執行緒排程策略和優先順序,handle-執行緒處理函式地址
  | sysTid=20678 nice=-10 cgrp=default sched=0/0 handle=0x7f75fe0a98
  //上下文資訊:state-執行緒排程狀態,schedstat-執行緒在CPU中的執行時間、執行緒等待時間、執行緒執行的時間片長度,utm-執行緒在使用者狀態中排程的時間值,core-最後執行這個執行緒的CPU核序號
  | state=S schedstat=( 274637713 30817705 229 ) utm=20 stm=6 core=1 HZ=100
  //堆疊資訊:stack-堆疊地址,stackSize-堆疊大小,餘下的為堆疊資訊,也是我們分析引發ANR問題的關鍵
  | stack=0x7fc8318000-0x7fc831a000 stackSize=8MB
  | held mutexes=
  at java.lang.Thread.sleep!(Native method)
  - sleeping on <0x02f69763> (a java.lang.Object)
  at java.lang.Thread.sleep(Thread.java:371)
  - locked <0x02f69763> (a java.lang.Object)
  at java.lang.Thread.sleep(Thread.java:313)
  at admanager.lbjfan.com.anrdemo.MainActivity$1.onClick(MainActivity.java:24)
  at android.view.View.performClick(View.java:5637)
  at android.view.View$PerformClick.run(View.java:22429)
  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)

"Jit thread pool worker thread 0" daemon prio=5 tid=2 Native
  | group="main" sCount=1 dsCount=0 obj=0x12c64790 self=0x7f6a635000
  | sysTid=20683 nice=9 cgrp=default sched=0/0 handle=0x7f71701450
  | state=S schedstat=( 696978 5677 2 ) utm=0 stm=0 core=2 HZ=100
  | stack=0x7f71603000-0x7f71605000 stackSize=1021KB
  | held mutexes=
  kernel: __switch_to+0x8c/0x98
  kernel: futex_wait_queue_me+0xd4/0x130
  kernel: futex_wait+0xfc/0x210
  kernel: do_futex+0xe0/0x920
  kernel: SyS_futex+0x11c/0x1b0
  kernel: cpu_switch_to+0x48/0x4c
  native: #00 pc 000000000001bcec  /system/lib64/libc.so (syscall+28)
  native: #01 pc 00000000000e7e4c  /system/lib64/libart.so (_ZN3art17ConditionVariable16WaitHoldingLocksEPNS_6ThreadE+156)
  native: #02 pc 000000000046c910  /system/lib64/libart.so (_ZN3art10ThreadPool7GetTaskEPNS_6ThreadE+248)
  native: #03 pc 000000000046bdac  /system/lib64/libart.so (_ZN3art16ThreadPoolWorker3RunEv+124)
  native: #04 pc 000000000046b6d0  /system/lib64/libart.so (_ZN3art16ThreadPoolWorker8CallbackEPv+132)
  native: #05 pc 0000000000068734  /system/lib64/libc.so (_ZL15__pthread_startPv+208)
  native: #06 pc 000000000001da7c  /system/lib64/libc.so (__start_thread+16)
  (no managed stack frames)

//關鍵日誌的結束標記
----- end 20678 -----

由於ANR只會發生在主執行緒,所以我們需要關注主執行緒的狀態,從上 面日誌中分析可以知道:發生ANR時主執行緒的狀態為Sleep,且引起該狀態的地方在MainActivity$1.onClick(MainActivity.java:24)
這裡寫圖片描述

3)使用AndroidStudio分析工具

有時候檢視trace檔案是及其困難的,很難定位到具體的程式碼位置,這時候就可以藉助AndroidStudio提供的工具:Analyze-AnalyzeStacktrace,然後新增得到的trace,如下:這裡寫圖片描述

5.ANR原始碼分析

下面分析Service內onCreate發生ANR異常時原始碼的執行情況

大家都知道Android中的四大元件啟動時,都會通過跨程序的方式利用Handler訊息機制最終將訊息Push到ActivityThread中的內部類去處理,因此我先在ActivityThread中搜索service.onCreate呼叫,然後依次追溯:

注:下面均以刪除無關程式碼

ActivityThread中呼叫:

  private void handleCreateService(CreateServiceData data) {
            //呼叫service的onCreate
            service.onCreate();

    }

該方法由Activity的內部類H(繼承與Handler)接收到Servic onCreate訊息時呼叫,該訊息由通過scheduleCreateService發出,該方法被ActiveService類呼叫

        public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
            updateProcessState(processState, false);
            CreateServiceData s = new CreateServiceData();
            s.token = token;
            s.info = info;
            s.compatInfo = compatInfo;

            sendMessage(H.CREATE_SERVICE, s);
        }

ActiveServicde的realStartServiceLocked方法呼叫上面方法,這個方法比較關鍵需要認真分析:

private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {

        r.app = app;
        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

        final boolean newService = app.services.add(r);
        //傳送delay訊息(SERVICE_TIMEOUT_MSG)
        bumpServiceExecutingLocked(r, execInFg, "create");
        mAm.updateLruProcessLocked(app, false, null);
        updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
        mAm.updateOomAdjLocked();

        boolean created = false;
        try {
            synchronized (r.stats.getBatteryStats()) {
                r.stats.startLaunchedLocked();
            }
            mAm.notifyPackageUse(r.serviceInfo.packageName,
                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            //最終執行服務的onCreate()方法
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
            Slog.w(TAG, "Application dead when creating service " + r);
            mAm.appDiedLocked(app);
            throw e;
        } finally {
            if (!created) {
                // Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                //當service啟動完畢,則remove SERVICE_TIMEOUT_MSG訊息
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);

                // Cleanup.
                if (newService) {
                    app.services.remove(r);
                    r.app = null;
                }

                // Retry.
                if (!inDestroying) {
                    scheduleServiceRestartLocked(r, false);
                }
            }
        }

        if (r.whitelistManager) {
            app.whitelistManager = true;
        }

        requestServiceBindingsLocked(r, execInFg);

        updateServiceClientActivitiesLocked(app, null, true);

        // If the service is in the started state, and there are no
        // pending arguments, then fake up one so its onStartCommand() will
        // be called.
        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null, 0));
        }

        sendServiceArgsLocked(r, execInFg, true);
    }

bumpServiceExecutingLocked方法內又呼叫了scheduleServiceTimeoutLocked方法:

    void scheduleServiceForegroundTransitionTimeoutLocked(ServiceRecord r) {
        if (r.app.executingServices.size() == 0 || r.app.thread == null) {
            return;
        }
        //指定id為SERVICE_TIMEOUT_MSG的訊息
        Message msg = mAm.mHandler.obtainMessage(
                ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG);
        msg.obj = r;
        r.fgWaiting = true;
        //前臺Service和後臺Service傳送的Delay訊息時間不同
        mAm.mHandler.sendMessageDelayed(msg, SERVICE_START_FOREGROUND_TIMEOUT);
    }

serviceDoneExecutingLocked方法

    private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
            boolean finishing) {
        r.executeNesting--;
        if (r.executeNesting <= 0) {
            if (r.app != null) {
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                        "Nesting at 0 of " + r.shortName);
                r.app.execServicesFg = false;
                r.app.executingServices.remove(r);
                if (r.app.executingServices.size() == 0) {
                    if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
                            "No more executingServices of " + r.shortName);
                   //remove掉id為SERVICE_TIMEOUT_MSG的訊息,從上面的分析可知,該方法是onCreate呼叫之前發出的一個Delay執行的訊息
                   mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
                } else if (r.executeFg) {
                    // Need to re-evaluate whether the app still needs to be in the foreground.
                    for (int i=r.app.executingServices.size()-1; i>=0; i--) {
                        if (r.app.executingServices.valueAt(i).executeFg) {
                            r.app.execServicesFg = true;
                            break;
                        }
                    }
                }
                if (inDestroying) {
                    mDestroyingServices.remove(r);
                    r.bindings.clear();
                }
                mAm.updateOomAdjLocked(r.app, true);
            }
            r.executeFg = false;
            if (r.tracker != null) {
                r.tracker.setExecuting(false, mAm.mProcessStats.getMemFactorLocked(),
                        SystemClock.uptimeMillis());
                if (finishing) {
                    r.tracker.clearCurrentOwner(r, false);
                    r.tracker = null;
                }
            }
            if (finishing) {
                if (r.app != null && !r.app.persistent) {
                    r.app.services.remove(r);
                    if (r.whitelistManager) {
                        updateWhitelistManagerLocked(r.app);
                    }
                }
                r.app = null;
            }
        }
    }

小結:Service啟動呼叫onCreate方法之前send一個Delay執行的訊息,當發生異常或者Service的onCreate方法執行完畢之後,remove掉之前send的訊息,如果onCreate方法執行時間超過Delay的時間,那麼該訊息就會被處理,此時如果Delay的時間是我們設定的ANR時間,則發生ANR,系統作出處理,否則該訊息被remove,不會被執行。以一種觀察者模式的角度去實現。

id為SERVICE_TIMEOUT_MSG的訊息被AMS中MainHandler接收

            case SERVICE_TIMEOUT_MSG: {
                if (mDidDexOpt) {
                    mDidDexOpt = false;
                    Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
                    nmsg.obj = msg.obj;
                    mHandler.sendMessageDelayed(nmsg, ActiveServices.SERVICE_TIMEOUT);
                    return;
                }
                mServices.serviceTimeout((ProcessRecord)msg.obj);
            } break;

ActiveService的serviceTimeout方法中呼叫AppErrors中的appNotResponding方法,很明顯ANR異常處理的方法:

    final void appNotResponding(ProcessRecord app, ActivityRecord activity,
            ActivityRecord parent, boolean aboveSystem, final String annotation) {
        ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
        SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);

        if (mService.mController != null) {
            try {
                // 0 == continue, -1 = kill process immediately
                int res = mService.mController.appEarlyNotResponding(
                        app.processName, app.pid, annotation);
                if (res < 0 && app.pid != MY_PID) {
                    app.kill("anr", true);
                }
            } catch (RemoteException e) {
                mService.mController = null;
                Watchdog.getInstance().setActivityController(null);
            }
        }

        long anrTime = SystemClock.uptimeMillis();
        if (ActivityManagerService.MONITOR_CPU_USAGE) {
            mService.updateCpuStatsNow();
        }

        // Unless configured otherwise, swallow ANRs in background processes & kill the process.
        boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
                Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;

        boolean isSilentANR;

        synchronized (mService) {
            // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
            if (mService.mShuttingDown) {
                Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation);
                return;
            } else if (app.notResponding) {
                Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation);
                return;
            } else if (app.crashing) {
                Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);
                return;
            } else if (app.killedByAm) {
                Slog.i(TAG, "App already killed by AM skipping ANR: " + app + " " + annotation);
                return;
            } else if (app.killed) {
                Slog.i(TAG, "Skipping died app ANR: " + app + " " + annotation);
                return;
            }

            // In case we come through here for the same app before completing
            // this one, mark as anring now so we will bail out.
            app.notResponding = true;

            // Log the ANR to the event log.
            EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid,
                    app.processName, app.info.flags, annotation);

            // Dump thread traces as quickly as we can, starting with "interesting" processes.
            firstPids.add(app.pid);

            // Don't dump other PIDs if it's a background ANR
            isSilentANR = !showBackground && !isInterestingForBackgroundTraces(app);
            if (!isSilentANR) {
                int parentPid = app.pid;
                if (parent != null && parent.app != null && parent.app.pid > 0) {
                    parentPid = parent.app.pid;
                }
                if (parentPid != app.pid) firstPids.add(parentPid);

                if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID);

                for (int i = mService.mLruProcesses.size() - 1; i >= 0; i--) {
                    ProcessRecord r = mService.mLruProcesses.get(i);
                    if (r != null && r.thread != null) {
                        int pid = r.pid;
                        if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
                            if (r.persistent) {
                                firstPids.add(pid);
                                if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);
                            } else if (r.treatLikeActivity) {
                                firstPids.add(pid);
                                if (DEBUG_ANR) Slog.i(TAG, "Adding likely IME: " + r);
                            } else {
                                lastPids.put(pid, Boolean.TRUE);
                                if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r);
                            }
                        }
                    }
                }
            }
        }

        //輸出ANR異常Log

        // Log the ANR to the main log.
        StringBuilder info = new StringBuilder();
        info.setLength(0);
        //ANR發生時的程序Name
        info.append("ANR in ").append(app.processName);
        if (activity != null && activity.shortComponentName != null) {
            info.append(" (").append(activity.shortComponentName).append(")");
        }
        info.append("\n");
        //程序ID
        info.append("PID: ").append(app.pid).append("\n");
        //ANR發生的原因
        if (annotation != null) {
            info.append("Reason: ").append(annotation).append("\n");
        }
        if (parent != null && parent != activity) {
            info.append("Parent: ").append(parent.shortComponentName).append("\n");
        }

        ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);

        // don't dump native PIDs for background ANRs unless it is the process of interest
        String[] nativeProcs = null;
        if (isSilentANR) {
            for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) {
                if (NATIVE_STACKS_OF_INTEREST[i].equals(app.processName)) {
                    nativeProcs = new String[] { app.processName };
                    break;
                }
            }
        } else {
            nativeProcs = NATIVE_STACKS_OF_INTEREST;
        }

        int[] pids = nativeProcs == null ? null : Process.getPidsForCommands(nativeProcs);
        ArrayList<Integer> nativePids = null;

        if (pids != null) {
            nativePids = new ArrayList<Integer>(pids.length);
            for (int i : pids) {
                nativePids.add(i);
            }
        }

        // For background ANRs, don't pass the ProcessCpuTracker to
        // avoid spending 1/2 second collecting stats to rank lastPids.
        //dump棧資訊
        File tracesFile = mService.dumpStackTraces(true, firstPids,
                                                   (isSilentANR) ? null : processCpuTracker,
                                                   (isSilentANR) ? null : lastPids,
                                                   nativePids);

        String cpuInfo = null;
        if (ActivityManagerService.MONITOR_CPU_USAGE) {
            mService.updateCpuStatsNow();
            synchronized (mService.mProcessCpuTracker) {
                //各程序使用CPU情況
                cpuInfo = mService.mProcessCpuTracker.printCurrentState(anrTime);
            }
            //CPU當前負載
            info.append(processCpuTracker.printCurrentLoad());
            info.append(cpuInfo);
        }

        info.append(processCpuTracker.printCurrentState(anrTime));

        Slog.e(TAG, info.toString());
        if (tracesFile == null) {
            // There is no trace file, so dump (only) the alleged culprit's threads to the log
            Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
        }
        //將anr資訊新增到dropbox
        mService.addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,
                cpuInfo, tracesFile, null);

        if (mService.mController != null) {
            try {
                // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
                int res = mService.mController.appNotResponding(
                        app.processName, app.pid, info.toString());
                if (res != 0) {
                    if (res < 0 && app.pid != MY_PID) {
                        app.kill("anr", true);
                    } else {
                        synchronized (mService) {
                            mService.mServices.scheduleServiceTimeoutLocked(app);
                        }
                    }
                    return;
                }
            } catch (RemoteException e) {
                mService.mController = null;
                Watchdog.getInstance().setActivityController(null);
            }
        }

        synchronized (mService) {
            mService.mBatteryStatsService.noteProcessAnr(app.processName, app.uid);

            if (isSilentANR) {
                app.kill("bg anr", true);
                return;
            }

            // Set the app's notResponding state, and look up the errorReportReceiver
            makeAppNotRespondingLocked(app,
                    activity != null ? activity.shortComponentName : null,
                    annotation != null ? "ANR " + annotation : "ANR",
                    info.toString());

            ////通過Handler訊息機制彈出ANR對話方塊
            // Bring up the infamous App Not Responding dialog
            Message msg = Message.obtain();
            HashMap<String, Object> map = new HashMap<String, Object>();
            msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
            msg.obj = map;
            msg.arg1 = aboveSystem ? 1 : 0;
            map.put("app", app);
            if (activity !=