欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android發(fā)生ANR后的信息采集過(guò)程

 更新時(shí)間:2023年07月28日 11:16:34   作者:尹學(xué)姐  
這篇文章主要為大家介紹了Android發(fā)生ANR后的信息采集過(guò)程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

發(fā)生ANR后

系統(tǒng)會(huì)為我們提供一些信息,便于我們分析問(wèn)題,如生成trace文件,在log中打印CPU信息等。

這篇文章,我們來(lái)看看ANR發(fā)生之后,系統(tǒng)會(huì)提供給我們哪些信息,以及這些信息是如何采集和輸出的。

系統(tǒng)提供的信息

系統(tǒng)提供給我們的信息,主要有:

  • EventLog中會(huì)打印 "am_anr" 的日志
  • MainLog中會(huì)打印ANR發(fā)生的進(jìn)程、原因、CPU負(fù)載等信息
  • /data/anr路徑下會(huì)生成一個(gè)trace文件,打印出主要進(jìn)程的堆棧信息
  • dropbox會(huì)保存trace文件和CPU負(fù)載信息data/system/dropbox目錄

采集信息源碼

發(fā)生 ANR 后,不管是哪種類型的 ANR,系統(tǒng)都會(huì)調(diào)用到appNotResponding方法中,進(jìn)行信息的采集工作。

這個(gè)方法所在的位置,在不同的Android版本有區(qū)別。舊版本是在AMS中,新版本是在ProcessErrorStateRecord類中。

我們以新版本的appNotResponding源碼為例,分步進(jìn)行講解。

  • appNotResponding傳入?yún)?shù)
void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
            String parentShortComponentName, WindowProcessController parentProcess,
            boolean aboveSystem, String annotation, boolean onlyDumpSelf) {
}

其中annotation就是shortMsg,表示ANR發(fā)生的原因。

  • 先獲取一次CPU信息
long anrTime = SystemClock.uptimeMillis();
        if (isMonitorCpuUsage()) {
            mService.updateCpuStatsNow();
        }
  • 設(shè)置annotation
// Store annotation here as instance above will not be hit on all paths.
            setAnrAnnotation(annotation);
  • 判斷是否需要跳過(guò)
// PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
            if (mService.mAtmInternal.isShuttingDown()) {
                Slog.i(TAG, "During shutdown skipping ANR: " + this + " " + annotation);
                return;
            } else if (isNotResponding()) {
                Slog.i(TAG, "Skipping duplicate ANR: " + this + " " + annotation);
                return;
            } else if (isCrashing()) {
                Slog.i(TAG, "Crashing app skipping ANR: " + this + " " + annotation);
                return;
            } else if (mApp.isKilledByAm()) {
                Slog.i(TAG, "App already killed by AM skipping ANR: " + this + " " + annotation);
                return;
            } else if (mApp.isKilled()) {
                Slog.i(TAG, "Skipping died app ANR: " + this + " " + annotation);
                return;
            }

有幾種情況會(huì)跳過(guò):

  • 如果正在關(guān)機(jī)中
  • 如果已經(jīng)被標(biāo)記為notResponding,正在處理 ANR 中
  • 進(jìn)程正在 crash 處理中
  • 進(jìn)程已經(jīng)被 AMS 殺掉
  • 進(jìn)程已經(jīng)被殺
  • 設(shè)置notResponding的標(biāo)記
setNotResponding(true);
  • 打印am_anr的EventLog
EventLog.writeEvent(EventLogTags.AM_ANR, mApp.userId, pid, mApp.processName,
                    mApp.info.flags, annotation);
  • 獲取需要dump的所有進(jìn)程id
// 先把當(dāng)前進(jìn)程添加到firstPids
            firstPids.add(pid);
            // 如果是silentAnr,則不需要dump其他進(jìn)程,silentAnr主要是后臺(tái)anr
            isSilentAnr = isSilentAnr();
            if (!isSilentAnr && !onlyDumpSelf) {
               // 將parentPid加入firstPids
                int parentPid = pid;
                if (parentProcess != null && parentProcess.getPid() > 0) {
                    parentPid = parentProcess.getPid();
                }
                if (parentPid != pid) firstPids.add(parentPid);
               // MY_PID是system_server的pid,將system_server加入firstPids
                if (MY_PID != pid && MY_PID != parentPid) firstPids.add(MY_PID);
                final int ppid = parentPid;
                // 所有進(jìn)程,按lru的順序排列
                mService.mProcessList.forEachLruProcessesLOSP(false, r -> {
                    if (r != null && r.getThread() != null) {
                        int myPid = r.getPid();
                        if (myPid > 0 && myPid != pid && myPid != ppid && myPid != MY_PID) {
                            if (r.isPersistent()) {
                                firstPids.add(myPid); // 將persisitent進(jìn)程加入firstPids
                            } else if (r.mServices.isTreatedLikeActivity()) {
                                firstPids.add(myPid);   // treatedLikeActivity
                            } else {
                                lastPids.put(myPid, Boolean.TRUE);  // 其他進(jìn)程加入lastPids
                            }
                        }
                    }
                });
            }
        }

加入firstPids的進(jìn)程:

  • 當(dāng)前進(jìn)程
  • parent 進(jìn)程
  • system_server 進(jìn)程
  • 生成mainlog
StringBuilder info = new StringBuilder();
        info.setLength(0);
        info.append("ANR in ").append(mApp.processName);
        if (activityShortComponentName != null) {
            info.append(" (").append(activityShortComponentName).append(")");
        }
        info.append("\n");
        info.append("PID: ").append(pid).append("\n");
        if (annotation != null) {
            info.append("Reason: ").append(annotation).append("\n");
        }
        if (parentShortComponentName != null
                && parentShortComponentName.equals(activityShortComponentName)) {
            info.append("Parent: ").append(parentShortComponentName).append("\n");
        }
        if (errorId != null) {
            info.append("ErrorId: ").append(errorId.toString()).append("\n");
        }
        info.append("Frozen: ").append(mApp.mOptRecord.isFrozen()).append("\n");

初始化一個(gè)StringBuilder對(duì)象info,用來(lái)記錄輸出到mainLog里的內(nèi)容。

主要包含如下內(nèi)容:

  • ANR in xxx
  • PID: xxx
  • Reason: xxx (shortMsg)
  • Parent: xxx (可能沒(méi)有)
  • ErrorId: xxx (可能沒(méi)有)
  • Frozen: 是否frozen
  • CPU信息
  • 收集需要 dump 的native pids
String[] nativeProcs = null;
        if (isSilentAnr || onlyDumpSelf) {
            for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) {
                // 寫(xiě)死在watchdog中的native進(jìn)程,主要包含audioserver、cameraserver等。
                if (NATIVE_STACKS_OF_INTEREST[i].equals(mApp.processName)) {
                    nativeProcs = new String[] { mApp.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<>(pids.length);
            for (int i : pids) {
                nativePids.add(i);
            }
        }

NATIVE_STACKS_OF_INTEREST寫(xiě)死在WatchDog.java文件,主要包含audioserver、cameraserver等。

  • 開(kāi)始dump trace文件
// 生成ProcessCpuTracker
       ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
       File tracesFile = ActivityManagerService.dumpStackTraces(firstPids,
                isSilentAnr ? null : processCpuTracker, isSilentAnr ? null : lastPids,
                nativePids, tracesFileException, offsets, annotation, criticalEventLog);

dump trace文件的具體細(xì)節(jié),以及SignalCatcher線程監(jiān)聽(tīng)信號(hào),下一篇文章再詳細(xì)講。

  • 再次獲取CPU信息,并打印mainLog
if (isMonitorCpuUsage()) {
            mService.updateCpuStatsNow();
            mService.mAppProfiler.printCurrentCpuState(report, anrTime);
            info.append(processCpuTracker.printCurrentLoad());
            info.append(report);
        }
        info.append(processCpuTracker.printCurrentState(anrTime));
        // 打印mainLog,tag為ActivityManager
        Slog.e(TAG, info.toString());
  • 保存到 dropbox
mService.addErrorToDropBox("anr", mApp, mApp.processName, activityShortComponentName,
                parentShortComponentName, parentPr, null, report.toString(), tracesFile,
                null, new Float(loadingProgress), incrementalMetrics, errorId);

把traces文件、CPU使用率等信息,保存到dropbox,即data/system/dropbox目錄

  • 如果是后臺(tái) ANR,直接殺進(jìn)程
if (isSilentAnr() && !mApp.isDebugging()) {
                mApp.killLocked("bg anr", ApplicationExitInfo.REASON_ANR, true);
                return;
            }
  • 設(shè)置AppnotRespondingReport(到這里,AMS 才能查詢到進(jìn)程是否發(fā)生 ANR)
synchronized (mProcLock) {
                // 設(shè)置AppNotRespondingReport
                makeAppNotRespondingLSP(activityShortComponentName,
                        annotation != null ? "ANR " + annotation : "ANR", info.toString());
                mDialogController.setAnrController(anrController);
            }
private void makeAppNotRespondingLSP(String activity, String shortMsg, String longMsg) {
        setNotResponding(true);
        if (mService.mAppErrors != null) {
            // 設(shè)置NotRespondingReport
            mNotRespondingReport = mService.mAppErrors.generateProcessError(mApp,
                    ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
                    activity, shortMsg, longMsg, null);
        }
        startAppProblemLSP();
        mApp.getWindowProcessController().stopFreezingActivities();
    }
  • 喚醒 ANR 彈窗
if (mService.mUiHandler != null) {
                // 喚醒AppNotResponding彈窗
                Message msg = Message.obtain();
                msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
                msg.obj = new AppNotRespondingDialog.Data(mApp, aInfo, aboveSystem);
                mService.mUiHandler.sendMessageDelayed(msg, anrDialogDelayMs);
            }

到這里,AppNotResponding的流程就講完了。

從AMS獲取App的ErrorState

AMS提供一個(gè)public的接口,用于查詢所有進(jìn)程的ErrorState

public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
        synchronized (mProcLock) {
            // 遍歷所有進(jìn)程
            mProcessList.forEachLruProcessesLOSP(false, app -> {
                // 獲取進(jìn)程的mErrorState
                final ProcessErrorStateRecord errState = app.mErrorState;
                final boolean crashing = errState.isCrashing();
                final boolean notResponding = errState.isNotResponding();
                if ((app.getThread() != null) && (crashing || notResponding)) {
                    ActivityManager.ProcessErrorStateInfo report = null;
                    if (crashing) {
                       // 如果是crashing,需要獲取CrashingReport
                        report = errState.getCrashingReport();
                    } else if (notResponding) {
                       // 如果是notResponding,需要獲取notRespondingReport
                        report = errState.getNotRespondingReport();
                    }
                    if (report != null) {
                        if (errList[0] == null) {
                            errList[0] = new ArrayList<>(1);
                        }
                        errList[0].add(report);
                    } else {
                        Slog.w(TAG, "Missing app error report, app = " + app.processName +
                                " crashing = " + crashing +
                                " notResponding = " + notResponding);
                    }
                }
            });
        }
        return errList[0];
    }

這個(gè)方法的作用,主要是找到出現(xiàn) Crash 或 ANR 的進(jìn)程列表。可以通過(guò)循環(huán)調(diào)用該方法,判斷進(jìn)程是否發(fā)生 ANR。

不過(guò)這個(gè)判斷不會(huì)很準(zhǔn),因?yàn)橹挥挟?dāng)發(fā)生 ANR 的進(jìn)程的notRespondingReport生成后,才會(huì)返回該進(jìn)程。由前面的分析克制,生成notRespondingReport的時(shí)機(jī),是在dump trace完成之后,彈出ANR彈窗之前。

以下幾種情況會(huì)導(dǎo)致我們無(wú)法獲取到進(jìn)程的ErrorState

  • 用戶可能在我們調(diào)用方法之間,殺掉進(jìn)程
  • 對(duì)于oppo和vivo手機(jī),發(fā)生ANR后會(huì)自動(dòng)殺死進(jìn)程,幾乎沒(méi)辦法拿到

總結(jié)

當(dāng) ANR 發(fā)生時(shí),系統(tǒng)會(huì)調(diào)用appNotResponding方法,修改進(jìn)程的ErrorState狀態(tài),同時(shí)dump豐富的信息。

主要流程如下:

  • am_anr信息,輸出到EventLog(這是ANR發(fā)生的起點(diǎn))
  • 獲取重要進(jìn)程的trace信息,保存到/data/anr/traces.txt
    • Java進(jìn)程:當(dāng)前進(jìn)程、parent進(jìn)程、system_server、top 5的進(jìn)程
    • Native進(jìn)程:audioserver、cameraserver
  • ANR reasonCPU使用情況,輸出到 MainLog
  • CPU使用情況及traces文件信息,保存到/data/system/dropbox
  • 如果是后臺(tái)ANR,直接殺進(jìn)程
  • 如果是前臺(tái)ANR,設(shè)置notRespondingReport,激活 ANR 彈窗

以上就是Android發(fā)生ANR后的信息采集過(guò)程的詳細(xì)內(nèi)容,更多關(guān)于Android ANR信息采集的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論