標籤:
ActivityManagerService.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 (mController != null) { try { // 0 == continue, -1 = kill process immediately int res = mController.appEarlyNotResponding(app.processName, app.pid, annotation); if (res < 0 && app.pid != MY_PID) Process.killProcess(app.pid); } catch (RemoteException e) { mController = null; Watchdog.getInstance().setActivityController(null); } } long anrTime = SystemClock.uptimeMillis(); if (MONITOR_CPU_USAGE) { updateCpuStatsNow(); } synchronized (this) { // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down. if (mShuttingDown) { //如果系統正在關機,ANR不處理,return; Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation); return; } else if (app.notResponding) { //如果之前已經報過該進程ANR了,那麼不再執行下面的邏輯,直接列印“<span style="font-family: Arial, Helvetica, sans-serif;">Skipping duplicate ANR“,然後return;</span>” Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation); return; } else if (app.crashing) { //如果應用發生crash,此時ANR忽略掉,return; Slog.i(TAG, "Crashing app skipping 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; //將<span style="font-family: Arial, Helvetica, sans-serif;">notResponding 設為true,表示已經在處理該進程的ANR,下次再報ANR直接return;</span> // Log the ANR to the event log. EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid, //往event日誌中寫AM_ANR資訊,全域搜尋了下,只有這一個地方列印event ANR日誌,那麼如果event日誌中有此日誌項,就說明已經走進這個函數邏輯裡面了; app.processName, app.info.flags, annotation); // Dump thread traces as quickly as we can, starting with "interesting" processes. firstPids.add(app.pid); //將出ANR的進程加入<span style="font-family: Arial, Helvetica, sans-serif;">firstPids列表,後續列印該進程的trace;</span> int parentPid = app.pid; if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid; //將父進程也加入<span style="font-family: Arial, Helvetica, sans-serif;">firstPids列表;</span> if (parentPid != app.pid) firstPids.add(parentPid); if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID); //將system_server進程加入<span style="font-family: Arial, Helvetica, sans-serif;">firstPids列表,說明每次ANR的trace中必然包括system_server進程的trace;</span> for (int i = mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord r = 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); //將常駐進程也加入<span style="font-family: Arial, Helvetica, sans-serif;">firstPids列表中;</span> } else { lastPids.put(pid, Boolean.TRUE); } } } } } // Log the ANR to the main log. StringBuilder info = new StringBuilder(); info.setLength(0); info.append("ANR in ").append(app.processName); //"ANR in"也是分析ANR的關鍵日誌; if (activity != null && activity.shortComponentName != null) { info.append(" (").append(activity.shortComponentName).append(")"); } info.append("\n"); info.append("PID: ").append(app.pid).append("\n"); if (annotation != null) { info.append("Reason: ").append(annotation).append("\n"); } if (parent != null && parent != activity) { info.append("Parent: ").append(parent.shortComponentName).append("\n"); } final ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true); File tracesFile = dumpStackTraces(true, firstPids, processCpuTracker, lastPids, NATIVE_STACKS_OF_INTEREST); String cpuInfo = null; if (MONITOR_CPU_USAGE) { updateCpuStatsNow(); synchronized (mProcessCpuThread) { cpuInfo = mProcessCpuTracker.printCurrentState(anrTime); } info.append(processCpuTracker.printCurrentLoad()); info.append(cpuInfo); } info.append(processCpuTracker.printCurrentState(anrTime)); Slog.e(TAG, info.toString()); if (tracesFile == null) { //如果調用<span style="font-family: Arial, Helvetica, sans-serif;">dumpStackTraces沒有生存trace,那麼重新只列印ANR進程trace;</span> // There is no trace file, so dump (only) the alleged culprit's threads to the log Process.sendSignal(app.pid, Process.SIGNAL_QUIT); } addErrorToDropBox("anr", app, app.processName, activity, parent, annotation, //將trace檔案加入DropBox中,這麼說來只要發生ANR,並在日誌中有"ANR in",那麼在DropBox中必然有一份trace日誌,命名已‘ANR’形式; cpuInfo, tracesFile, null); if (mController != null) { try { // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately int res = mController.appNotResponding(app.processName, app.pid, info.toString()); if (res != 0) { if (res < 0 && app.pid != MY_PID) { Process.killProcess(app.pid); } else { synchronized (this) { mServices.scheduleServiceTimeoutLocked(app); } } return; } } catch (RemoteException e) { mController = null; Watchdog.getInstance().setActivityController(null); } } // 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; synchronized (this) { if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) { killUnneededProcessLocked(app, "background ANR"); 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()); // Bring up the infamous App Not Responding dialog Message msg = Message.obtain(); HashMap<String, Object> map = new HashMap<String, Object>(); msg.what = SHOW_NOT_RESPONDING_MSG; msg.obj = map; msg.arg1 = aboveSystem ? 1 : 0; map.put("app", app); if (activity != null) { map.put("activity", activity); } mHandler.sendMessage(msg); } }
appNotResponding()分析