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 !=