android 保存crash log到本地

前言:

    开发APP的过程,一定会遇到App奔溃的bug,App崩溃是因为抛出异常,有异常就会crash。

正文

当应用出现crash会弹出一个弹框,frameworks/services/core/java/com/android/server/am/AppErrorDialog这个类就是具体实现,AppErrorDialog只是显示dialog,具体信息在rameworks/services/core/java/com/android/server/am/AppErrors中,这个类就是获取各种错误信息。

void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
            int callingPid, int callingUid) {
        long timeMillis = System.currentTimeMillis();
        String shortMsg = crashInfo.exceptionClassName;
        String longMsg = crashInfo.exceptionMessage;
        String stackTrace = crashInfo.stackTrace;
        if (shortMsg != null && longMsg != null) {
            longMsg = shortMsg + ": " + longMsg;
        } else if (shortMsg != null) {
            longMsg = shortMsg;
        }

        // If a persistent app is stuck in a crash loop, the device isn't very
        // usable, so we want to consider sending out a rescue party.
        if (r != null && r.persistent) {
            RescueParty.notePersistentAppCrash(mContext, r.uid);
        }

        AppErrorResult result = new AppErrorResult();
        TaskRecord task;
        synchronized (mService) {
            /**
             * If crash is handled by instance of {@link android.app.IActivityController},
             * finish now and don't show the app error dialog.
             */
            if (handleAppCrashInActivityController(r, crashInfo, shortMsg, longMsg, stackTrace,
                    timeMillis, callingPid, callingUid)) {
                return;
            }

            /**
             * If this process was running instrumentation, finish now - it will be handled in
             * {@link ActivityManagerService#handleAppDiedLocked}.
             */
            if (r != null && r.instr != null) {
                return;
            }

            // Log crash in battery stats.
            if (r != null) {
                mService.mBatteryStatsService.noteProcessCrash(r.processName, r.uid);
            }

            AppErrorDialog.Data data = new AppErrorDialog.Data();
            data.result = result;
            data.proc = r;

            // If we can't identify the process or it's already exceeded its crash quota,
            // quit right away without showing a crash dialog.
            if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, data)) {
                return;
            }

            final Message msg = Message.obtain();
            msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;

            task = data.task;
            msg.obj = data;
            mService.mUiHandler.sendMessage(msg);
        }

        int res = result.get();

        Intent appErrorIntent = null;
        MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res);
        if (res == AppErrorDialog.TIMEOUT || res == AppErrorDialog.CANCEL) {
            res = AppErrorDialog.FORCE_QUIT;
        }
        synchronized (mService) {
            if (res == AppErrorDialog.MUTE) {
                stopReportingCrashesLocked(r);
            }
            if (res == AppErrorDialog.RESTART) {
                mService.removeProcessLocked(r, false, true, "crash");
                if (task != null) {
                    try {
                        mService.startActivityFromRecents(task.taskId,
                                ActivityOptions.makeBasic().toBundle());
                    } catch (IllegalArgumentException e) {
                        // Hmm, that didn't work, app might have crashed before creating a
                        // recents entry. Let's see if we have a safe-to-restart intent.
                        final Set<String> cats = task.intent.getCategories();
                        if (cats != null && cats.contains(Intent.CATEGORY_LAUNCHER)) {
                            mService.startActivityInPackage(task.mCallingUid,
                                    task.mCallingPackage, task.intent,
                                    null, null, null, 0, 0,
                                    ActivityOptions.makeBasic().toBundle(),
                                    task.userId, null, null, "AppErrors");
                        }
                    }
                }
            }
            if (res == AppErrorDialog.FORCE_QUIT) {
                long orig = Binder.clearCallingIdentity();
                try {
                    // Kill it with fire!
                    mService.mStackSupervisor.handleAppCrashLocked(r);
                    if (!r.persistent) {
                        mService.removeProcessLocked(r, false, false, "crash");
                        mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
                    }
                } finally {
                    Binder.restoreCallingIdentity(orig);
                }
            }
            if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
                appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
            }
            if (r != null && !r.isolated && res != AppErrorDialog.RESTART) {
                // XXX Can't keep track of crash time for isolated processes,
                // since they don't have a persistent identity.
                mProcessCrashTimes.put(r.info.processName, r.uid,
                        SystemClock.uptimeMillis());
            }
        }

        if (appErrorIntent != null) {
            try {
                mContext.startActivityAsUser(appErrorIntent, new UserHandle(r.userId));
            } catch (ActivityNotFoundException e) {
                Slog.w(TAG, "bug report receiver dissappeared", e);
            }
        }
    }

这个方法中shortMsg、longMsg、stackTrace就是crash的信息,crashApplicationinner这个方法在出现crash就执行,因此在这个方法中保存就可以。

这里显示弹窗的位置,找出异常捕获的位置。一旦代码抛出异常,并且我们没有捕捉的情况下,JVM 会调用 Thread 的 dispatchUncaughtException 方法

public final void dispatchUncaughtException(Throwable e) {
       Thread.UncaughtExceptionHandler initialUeh =
               Thread.getUncaughtExceptionPreHandler();
       if (initialUeh != null) {
           try {
               initialUeh.uncaughtException(this, e);
           } catch (RuntimeException | Error ignored) {
               // Throwables thrown by the initial handler are ignored
           }
       }
       //这里会获取对应的 UncaughtExceptionHandler 对象,然后调用对应的 uncaughtException 方法
       getUncaughtExceptionHandler().uncaughtException(this, e);
}

public UncaughtExceptionHandler getUncaughtExceptionHandler() {
    //可以看到当 uncaughtExceptionHandler 没有赋值的时候,会返回 ThreadGroup 对象
    return uncaughtExceptionHandler != null ?
        uncaughtExceptionHandler : group;
}

 看上述代码,如果 App 中并没有设置 uncaughtExceptionHandler 对象,那么会执行 ThreadGroup的uncaughtException 方法:

    public void uncaughtException(Thread t, Throwable e) {
        if (parent != null) {
            parent.uncaughtException(t, e);
        } else {
            Thread.UncaughtExceptionHandler ueh =
                Thread.getDefaultUncaughtExceptionHandler();
            if (ueh != null) {
                ueh.uncaughtException(t, e);
            } else if (!(e instanceof ThreadDeath)) {
                System.err.print("Exception in thread \""
                                 + t.getName() + "\" ");
                e.printStackTrace(System.err);
            }
        }
    }

 代码中获知Thread.getDefaultUncaughtExceptionHandler() 获取默认的 UncaughtExceptionHandler ,然后调用 uncaughtException 方法。UncaughtExceptionHandler的初始化,要从系统的初始化开始,复杂流程就不赘述了,从RuntimeInit开始,

    public static final void main(String[] argv) {
        enableDdms();
        if (argv.length == 2 && argv[1].equals("application")) {
            if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application");
            redirectLogStreams();
        } else {
            if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool");
        }

        commonInit();

        /*
         * Now that we're running in interpreted code, call back into native code
         * to run the system.
         */
        nativeFinishInit();

        if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
    }

 这里重点看commonInit()方法

    protected static final void commonInit() {
        if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");

        /*
         * set handlers; these apply to all threads in the VM. Apps can replace
         * the default handler, but not the pre handler.
         */
        LoggingHandler loggingHandler = new LoggingHandler();
        Thread.setUncaughtExceptionPreHandler(loggingHandler);
        Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));

        ...代码省略...

        initialized = true;
    }

 Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));这里是上文中UncaughtExceptionHandler的初始化的地方,KillApplicationHandler 是实现了 Thread.UncaughtExceptionHandler 这个接口的,所以自然会重写 uncaughtException 方法

        public void uncaughtException(Thread t, Throwable e) {
            try {
                ensureLogging(t, e);

                // Don't re-enter -- avoid infinite loops if crash-reporting crashes.
                if (mCrashing) return;
                mCrashing = true;

                // Try to end profiling. If a profiler is running at this point, and we kill the
                // process (below), the in-memory buffer will be lost. So try to stop, which will
                // flush the buffer. (This makes method trace profiling useful to debug crashes.)
                if (ActivityThread.currentActivityThread() != null) {
                    ActivityThread.currentActivityThread().stopProfiling();
                }

                // Bring up crash dialog, wait for it to be dismissed
                ActivityManager.getService().handleApplicationCrash(
                        mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
            } catch (Throwable t2) {
                if (t2 instanceof DeadObjectException) {
                    // System process is dead; ignore
                } else {
                    try {
                        Clog_e(TAG, "Error reporting crash", t2);
                    } catch (Throwable t3) {
                        // Even Clog_e() fails!  Oh well.
                    }
                }
            } finally {
                // Try everything to make sure this process goes away.
                Process.killProcess(Process.myPid());
                System.exit(10);
            }
        }

 当出现crash是会执行ActivityManager.getService().handleApplicationCrash(mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));

 new ApplicationErrorReport.ParcelableCrashInfo(e)包含错误信息。

     public void handleApplicationCrash(IBinder app,
             ApplicationErrorReport.ParcelableCrashInfo crashInfo) {
         ProcessRecord r = findAppProcess(app, "Crash");
         final String processName = app == null ? "system_server"
                 : (r == null ? "unknown" : r.processName);
         
         handleApplicationCrashInner("crash", r, processName, crashInfo);
     }

    /* Native crash reporting uses this inner version because it needs to be somewhat
     * decoupled from the AM-managed cleanup lifecycle
     */
    void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
            ApplicationErrorReport.CrashInfo crashInfo) {
        EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
                UserHandle.getUserId(Binder.getCallingUid()), processName,
                r == null ? -1 : r.info.flags,
                crashInfo.exceptionClassName,
                crashInfo.exceptionMessage,
                crashInfo.throwFileName,
                crashInfo.throwLineNumber);

        StatsLog.write(StatsLog.APP_CRASH_OCCURRED,
                Binder.getCallingUid(),
                eventType,
                processName,
                Binder.getCallingPid(),
                (r != null && r.info != null) ? r.info.packageName : "", 
                (r != null && r.info != null) ? (r.info.isInstantApp()
                        ? StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__TRUE
                        : StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__FALSE)
                        : StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__UNAVAILABLE,
                r != null ? (r.isInterestingToUserLocked()
                        ? StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__FOREGROUND
                        : StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__BACKGROUND)
                        : StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__UNKNOWN
        );    

        addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);

        mAppErrors.crashApplication(r, crashInfo);
    }

 这里 mAppErrors.crashApplication(r, crashInfo)就是弹窗位置

保存crash Log

这里我是添加一个系统服务去监听这个方法。

一、在frameworks/base/core/java/android/os下面添加ICrashInfoService.aidl

 package android.os;
 
 import android.os.ICrashListener;
 
 interface ICrashInfoService {
     void setCrashListener(ICrashListener l);
      void crashChange(String crash);
}

并添加一个listener

package android.os;

interface ICrashListener {
    void crashChange(String crash);
}

二、在frameworks/base/core/java/android/app添加CrashManager

package android.app;

import android.content.Context;
import android.os.ICrashListener;
import android.os.ICrashInfoService;
import android.os.RemoteException;
import android.util.Slog;

public class CrashInfoManager {

    private Context mContext;
    private ICrashInfoService mService;

    public CrashInfoManager(Context context, ICrashInfoService service) {
        mContext = context;
        mService = service;
    }

    public void setCrashListener(ICrashListener l) throws RemoteException {
        if (mService != null) {
            mService.setCrashListener(l);
        }
    }

    public void crashChange(String crash) throws RemoteException {
        if (mService != null) {
            mService.crashChange(crash);
        }
    }
}

三、ICrashInfoService.aidl的实现,在frameworks/base/services/core/java/com/android/server/下添加CrashInfoService.java

package com.android.server;

import android.content.Context;
import android.os.Build;
import android.os.ICrashInfoService;
import android.os.ICrashListener;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Slog;

import java.text.SimpleDateFormat;
import java.util.Date;

public class CrashInfoService extends ICrashInfoService.Stub {
    private static final String TAG = CrashInfoService.class.getSimpleName();

    private Context mContext;
    private final RemoteCallbackList<ICrashListener> mCrashListenerList = new RemoteCallbackList<ICrashListener>();

    public CrashInfoService(Context context) {
        mContext = context;
        Slog.d(TAG, "CrashInfoService -- create --");
    }   

    @Override
    public void setCrashListener(ICrashListener l) {
        mCrashListenerList.register(l);
    }   

    @Override
    public void crashChange(String crash) {
        int n = mCrashListenerList.beginBroadcast();
        try {
            for (int i = 0; i < n; i++) {
                ICrashListener listener = mCrashListenerList.getBroadcastItem(i);
                if (listener != null) {
                    listener.crashChange(crash);
                }   
            }   
        } catch (RemoteException e) {
            e.printStackTrace();
        }   
        mCrashListenerList.finishBroadcast();
    }   
}

四、在frameworks/base/core/java/android/content/Context.java添加

public static final String CRASH_INFO_SERVICE = "crashInfo_service";

在frameworks/base/core/java/android/app/SystemServiceRegistry.java注册CrashInfoService

registerService(Context.CRASH_INFO_SERVICE, CrashInfoManager.class,
        new CachedServiceFetcher<CrashInfoManager>() {
    @Override
    public CrashInfoManager createService(ContextImpl ctx) {
        IBinder b = ServiceManager.getService(Context.CRASH_INFO_SERVICE);
        ICrashInfoService service = ICrashInfoService.Stub.asInterface(b);
        return new CrashInfoManager(ctx, service);
    }});

在frameworks/base/services/java/com/android/server/SystemServer.java添加CrashInfoService

    /**  
     * Starts a miscellaneous grab bag of stuff that has yet to be refactored
     * and organized.
     */
    private void startOtherServices() {
        final Context context = mSystemContext;
        VibratorService vibrator = null;
        IStorageManager storageManager = null;
        NetworkManagementService networkManagement = null;
        NetworkStatsService networkStats = null;
        NetworkPolicyManagerService networkPolicy = null;
        ConnectivityService connectivity = null;
        NetworkScoreService networkScore = null;
        NsdService serviceDiscovery= null;
        WindowManagerService wm = null;
        SerialService serial = null;
        NetworkTimeUpdateService networkTimeUpdater = null;
        CommonTimeManagementService commonTimeMgmtService = null;
        InputManagerService inputManager = null;
        TelephonyRegistry telephonyRegistry = null;
        ConsumerIrService consumerIr = null;
        MmsServiceBroker mmsService = null;
        HardwarePropertiesManagerService hardwarePropertiesService = null;
                             ...
                             ...

        // For debugging RescueParty
        if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_system",         false)) {
            throw new RuntimeException();
        }

        try {
            final String SECONDARY_ZYGOTE_PRELOAD = "SecondaryZygotePreload";
            // We start the preload ~1s before the webview factory preparation, to
            // ensure that it completes before the 32 bit relro process is forked
            // from the zygote. In the event that it takes too long, the webview
            // RELRO process will block, but it will do so without holding any locks.
            mZygotePreload = SystemServerInitThreadPool.get().submit(() -> {
                try {
                    Slog.i(TAG, SECONDARY_ZYGOTE_PRELOAD);
                    BootTimingsTraceLog traceLog = new BootTimingsTraceLog(
                            SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
                    traceLog.traceBegin(SECONDARY_ZYGOTE_PRELOAD);
                    if (!Process.zygoteProcess.preloadDefault(Build.SUPPORTED_32_BIT_ABIS[0])) {
                        Slog.e(TAG, "Unable to preload default resources");
                    }
                    traceLog.traceEnd();
                } catch (Exception ex) {
                    Slog.e(TAG, "Exception preloading default resources", ex);
                }
            }, SECONDARY_ZYGOTE_PRELOAD);

            traceBeginAndSlog("StartKeyAttestationApplicationIdProviderService");
            ServiceManager.addService("sec_key_att_app_id_provider",
                    new KeyAttestationApplicationIdProviderService(context));
            traceEnd();
                                ...
                                ...
            try {
                ServiceManager.addService(Context.CRASH_INFO_SERVICE, new com.android.server.CrashInfoService(context));
                traceEnd();
            } catch (Throwable e) {
                Slog.e(TAG, " ServiceManager.addService CrashInfoService failed...");
            }
                                ...
                                ...
}

五、在frameworks/base/services/core/java/com/android/server/am/AppErrors.java

void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
            int callingPid, int callingUid) {
        long timeMillis = System.currentTimeMillis();
        String shortMsg = crashInfo.exceptionClassName;
        String longMsg = crashInfo.exceptionMessage;
        String stackTrace = crashInfo.stackTrace;
        try {
            CrashInfoManager mCrashInfoManager = (CrashInfoManager) mContext.getSystemService(Context.CRASH_INFO_SERVICE);
            mCrashInfoManager.crashChange(shortMsg + longMsg + stackTrace);
        } catch (Exception e) { 
            e.printStackTrace();
        }    
        if (shortMsg != null && longMsg != null) {
            longMsg = shortMsg + ": " + longMsg;
        } else if (shortMsg != null) {
            longMsg = shortMsg;
        }

                                ...
                                ...
}

使用方法如下

CrashInfoManager mCrashInfoManager = (CrashInfoManager) context.getSystemService(Context.CRASH_INFO_SERVICE);
mCrashInfoManager.setCrashListener(new ICrashListener.Stub() {
    @Override
    public void crashChange(String crash) {
    }

在回调方法crashChange处理crash信息

到此可以获取crash信息了,在AppError.java中还有其他信息,比如

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);
                            }
                        }
                    }
                }
            }
        }

        // Log the ANR to the main log.
        StringBuilder info = new StringBuilder();
        info.setLength(0);
        info.append("ANR in ").append(app.processName);
        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");
        }

        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.
        File tracesFile = ActivityManagerService.dumpStackTraces(
                true, firstPids,
                (isSilentANR) ? null : processCpuTracker,
                (isSilentANR) ? null : lastPids,
                nativePids);

        String cpuInfo = null;
        if (ActivityManagerService.MONITOR_CPU_USAGE) {
            mService.updateCpuStatsNow();
            synchronized (mService.mProcessCpuTracker) {
                cpuInfo = mService.mProcessCpuTracker.printCurrentState(anrTime);
            }
            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);
        }

        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());

            // 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 != null) {
                map.put("activity", activity);
            }

            mService.mUiHandler.sendMessage(msg);
        }
    }

这个方法可以获取ANR的信息

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值