Android 12 应用Java crash流程分析

Posted pecuyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 12 应用Java crash流程分析相关的知识,希望对你有一定的参考价值。

文章托管在gitee上 Android Notes , 同步csdn
本文基于android12 分析

概述

目前为止,Android应用进程是通过zygote进程fork出来的子进程,然后执行一些应用相关的初始化,最后进入应用入口 — ActivityThread 的main方法。应用在main方法中调用attachApplication通知系统应用启动完成,同时注册IApplicationThread对象到系统进程(通过linkToDeath监听其死亡),最后应用进入主消息循环后就正常运行起来了。当应用发生Java crash时,则会向system_server 上报crash事件,并会弹出crash对话框,以供用户操作是重启还是关闭应用等操作。当应用进程退出后,系统会收到其 IApplicationThread binder died通知,之后系统会做一些进程相关清理的收尾工作。

对于系统进程本身而言,它也是通过zygote进程fork出来的子进程,可以看成一个特殊的应用进程,当其发生Java crash时,也会通过binder调用AMS#handleApplicationCrash上报自身出现了crash,不过这个调用和一般应用不同,不需要进行跨进程。

当发生应用或系统进程Java crash时,可以在event log里面查找 am_crash 看其发生crash简略信息,在crash log里面可以看到详细的堆栈信息。

接下来,首先看应用进程的初始化,之后再分析当其发生crash时的处理流程,最后分析进程退出后系统的清理工作。

应用进程启动简述

以桌面点击图标为例,当应用进程还不存在时,系统会通过socket连接zygote进程,让其fork一个新进程。如下,当zygote收到一个请求后,通过processCommand处理请求,调用Zygote.forkSimpleApps方法创建一个新进程。当新进程启动后,调用ZygoteInit#zygoteInit进行初始化,并在main方法执行时,向系统上报其启动完成,之后就可以继续启动应用界面了。

Zygote#forkSimpleApps

/**
 * Reads a command from the command socket. If a child is successfully forked, a
 * @code Runnable that calls the childs main method (or equivalent) is returned in the child
 * process. @code null is always returned in the parent process (the zygote).
 * If multipleOK is set, we may keep processing additional fork commands before returning.
 *
 * If the client closes the socket, an @code EOF condition is set, which callers can test
 * for by calling @code ZygoteConnection.isClosedByPeer.
 */
Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) 
  ...
  Runnable result = Zygote.forkSimpleApps(argBuffer,
        zygoteServer.getZygoteSocketFileDescriptor(),
        peer.getUid(), Zygote.minChildUid(peer), parsedArgs.mNiceName); // 创建新进程
  if (result == null)  // 此处是parent,也即 zygote
      // parent; we finished some number of forks. Result is Boolean.
      // We already did the equivalent of handleParentProc().
      ZygoteHooks.postForkCommon();
      // argBuffer contains a command not understood by forksimpleApps.
      continue;
   else  // 此处是子进程逻辑
      // child; result is a Runnable.
      zygoteServer.setForkChild();
      Zygote.setAppProcessName(parsedArgs, TAG);  // ??? Necessary?
      return result; // 返回的runable执行其run,最终会调用入口main方法
  
...

Zygote.forkSimpleApps方法如下:

/// @frameworks/base/core/java/com/android/internal/os/Zygote.java
/**
 * Fork a new app process from the zygote. argBuffer contains a fork command that
 * request neither a child zygote, nor a wrapped process. Continue to accept connections
 * on the specified socket, use those to refill argBuffer, and continue to process
 * sufficiently simple fork requests. We presume that the only open file descriptors
 * requiring special treatment are the session socket embedded in argBuffer, and
 * zygoteSocket.
 */
static @Nullable Runnable forkSimpleApps(@NonNull ZygoteCommandBuffer argBuffer,
                                         @NonNull FileDescriptor zygoteSocket,
                                         int expectedUid,
                                         int minUid,
                                         @Nullable String firstNiceName) 
    boolean in_child =
            argBuffer.forkRepeatedly(zygoteSocket, expectedUid, minUid, firstNiceName);
    if (in_child)  // 当是子进程时,调用childMain
        return childMain(argBuffer, /*usapPoolSocket=*/null, /*writePipe=*/null);
     else 
        return null;
    

新进程启动后,在childMain中会调用 ZygoteInit#zygoteInit 初始化新进程

ZygoteInit#zygoteInit

/// frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
/**
 * The main function called when started through the zygote process. This could be unified with
 * main(), if the native code in nativeFinishInit() were rationalized with Zygote startup.<p>
 *
 * Current recognized args:
 * <ul>
 * <li> <code> [--] &lt;start class name&gt;  &lt;args&gt;
 * </ul>
 *
 * @param targetSdkVersion target SDK version
 * @param disabledCompatChanges set of disabled compat changes for the process (all others
 *                              are enabled)
 * @param argv             arg strings
 */
public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
        String[] argv, ClassLoader classLoader) 
    if (RuntimeInit.DEBUG) 
        Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
    

    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
    RuntimeInit.redirectLogStreams();

    RuntimeInit.commonInit(); // 一些通用初始化
    ZygoteInit.nativeZygoteInit();  // native初始化,比如初始化binder
    return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
            classLoader); //调用入口的main方法。对应应用调用ActivityThread的main方法,对于system_server调用com.android.server.SystemServer的main方法

ZygoteInit#commonInit

主要看RuntimeInit.commonInit方法,这个涉及到crash相关的初始化。

@UnsupportedAppUsage
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(); // 主要负责打印log的handler
    RuntimeHooks.setUncaughtExceptionPreHandler(loggingHandler);// pre handler ,确保crash log被打印
    // 设置 crash handler 为 KillApplicationHandler
    Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));

    ...

Thread#setDefaultUncaughtExceptionHandler

/**
 * Set the default handler invoked when a thread abruptly terminates
 * due to an uncaught exception, and no other handler has been defined
 * for that thread.
 */
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) 
    // Android-removed: SecurityManager stubbed out on Android.
    /*
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) 
        sm.checkPermission(
            new RuntimePermission("setDefaultUncaughtExceptionHandler")
                );
    
    */

     defaultUncaughtExceptionHandler = eh;
 

AMS#attachApplicationLocked

当应用进程执行其ActivityThread的 main方法时,会调用attachApplication向系统通知其已启动完毕,并注册一个IApplicationThread binder对象,通过这个对象系统可以调度应用做很多事情(比如启动Activity),也可以设置一个死亡监听,当应用进程退出后系统会收到通知。相关逻辑如下:

// @frameworks/base/core/java/android/app/ActivityThread.java
@UnsupportedAppUsage
private void attach(boolean system, long startSeq)  // 应用端的处理
    sCurrentActivityThread = this;
    mConfigurationController = new ConfigurationController(this);
    mSystemThread = system;
    if (!system) 
        RuntimeInit.setApplicationObject(mAppThread.asBinder());// 设置IApplicationThread binder对象,crash的时候会用到
        final IActivityManager mgr = ActivityManager.getService();
        try 
            mgr.attachApplication(mAppThread, startSeq); // 向系统注册IApplicationThread binder对象
         catch (RemoteException ex) 
            throw ex.rethrowFromSystemServer();
        
...

// @frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@GuardedBy("this")
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
        int pid, int callingUid, long startSeq)  // 系统端 AMS 的处理
          ...
          final String processName = app.processName;
          try 
              AppDeathRecipient adr = new AppDeathRecipient(
                      app, pid, thread);
              thread.asBinder().linkToDeath(adr, 0);  // 注册死亡监听
              app.setDeathRecipient(adr);
           catch (RemoteException e) 
              app.resetPackageList(mProcessStats);
              mProcessList.startProcessLocked(app,
                      new HostingRecord("link fail", processName),
                      ZYGOTE_POLICY_FLAG_EMPTY);
              return false;
          
          // 打印 am_proc_bound log
          EventLogTags.writeAmProcBound(app.userId, pid, app.processName);
...

Java crash 处理流程

当应用发生Java exception时,art会将此异常交于相关handler处理。在此流程中,应用会向系统上报自身crash事件,当系统收到请求后会显示crash弹框,提示应用异常,并提供用户一些操作选项,比如关闭、重启或者上报问题。比如选择关闭,则会进行杀进程并清理进程相关记录。

Thread::HandleUncaughtExceptions

当发生Java 异常时,art会调用此方法处理异常,它会回调 Java 线程的 dispatchUncaughtException方法

/// @art/runtime/thread.cc
void Thread::HandleUncaughtExceptions(ScopedObjectAccessAlreadyRunnable& soa) 
  if (!IsExceptionPending()) 
    return;
  
  ScopedLocalRef<jobject> peer(tlsPtr_.jni_env, soa.AddLocalReference<jobject>(tlsPtr_.opeer));
  ScopedThreadStateChange tsc(this, kNative);

  // Get and clear the exception.
  ScopedLocalRef<jthrowable> exception(tlsPtr_.jni_env, tlsPtr_.jni_env->ExceptionOccurred());
  tlsPtr_.jni_env->ExceptionClear();

  // Call the Thread instance's dispatchUncaughtException(Throwable)
  tlsPtr_.jni_env->CallVoidMethod(peer.get(),
      WellKnownClasses::java_lang_Thread_dispatchUncaughtException,
      exception.get()); // jni 回调 Java Thread 的 dispatchUncaughtException

  // If the dispatchUncaughtException threw, clear that exception too.
  tlsPtr_.jni_env->ExceptionClear();


Thread#dispatchUncaughtException

处理异常分发

/**
 * Dispatch an uncaught exception to the handler. This method is
 * intended to be called only by the runtime and by tests.
 *
 * @hide
 */
// Android-changed: Make dispatchUncaughtException() public, for use by tests.
public final void dispatchUncaughtException(Throwable e) 
    // BEGIN Android-added: uncaughtExceptionPreHandler for use by platform.
    Thread.UncaughtExceptionHandler initialUeh =  // Android添加预处理handler
            Thread.getUncaughtExceptionPreHandler();
    if (initialUeh != null) 
        try 
            initialUeh.uncaughtException(this, e);
         catch (RuntimeException | Error ignored) 
            // Throwables thrown by the initial handler are ignored
        
    
    // END Android-added: uncaughtExceptionPreHandler for use by platform.
    getUncaughtExceptionHandler().uncaughtException(this, e); // 获取handler并处理异常

getUncaughtExceptionHandler

没有设置uncaughtExceptionHandler,则会返回group,也就是让 ThreadGroup 来处理;如果应用设置了uncaughtExceptionHandler,则会交给应用处理。

/**
 * Returns the handler invoked when this thread abruptly terminates
 * due to an uncaught exception. If this thread has not had an
 * uncaught exception handler explicitly set then this thread's
 * <tt>ThreadGroup</tt> object is returned, unless this thread
 * has terminated, in which case <tt>null</tt> is returned.
 * @since 1.5
 * @return the uncaught exception handler for this thread
 */
public UncaughtExceptionHandler getUncaughtExceptionHandler() 
    return uncaughtExceptionHandler != null ?
        uncaughtExceptionHandler : group;

通常应用默认没有设置 uncaughtExceptionHandler,则会走 ThreadGroup的 uncaughtException

注意:之前默认设置的是 defaultUncaughtExceptionHandler,而另外一个针对当前线程有效的是 uncaughtExceptionHandler,两者不是一个。

private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
// 注意此处的 static
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;

// 设置默认的,针对所有
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) 
     defaultUncaughtExceptionHandler = eh;
 

// 设置当前Thread的
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) 
   checkAccess();
   uncaughtExceptionHandler = eh;

// Android新增的 目前主要用于确保打印crash log
public static void setUncaughtExceptionPreHandler(UncaughtExceptionHandler eh) 
    uncaughtExceptionPreHandler = eh;

ThreadGroup#uncaughtException

/**
 * Called by the Java Virtual Machine when a thread in this
 * thread group stops because of an uncaught exception, and the thread
 * does not have a specific @link Thread.UncaughtExceptionHandler
 * installed.
 */
public void uncaughtException(Thread t, Throwable e) 
    if (parent != null) //有parent则继续向上派发
        parent.uncaughtException(t, e);
     else 
      // 获取之前设置的默认的UncaughtExceptionHandler,也就是 KillApplicationHandler
        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);
        
    

最后,会将异常传给默认的handler来处理,也就是之前设置的 KillApplicationHandler

KillApplicationHandler#uncaughtException

@Override
public void uncaughtException(Thread t, Throwable e) 
    try 
        ensureLogging(t, e); // 打印log

        // Don't re-enter -- avoid infinite loops if crash-reporting crashes.
        if (mCrashing) return;
        mCrashing = true; // 标记应用在crash中

        // 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( // 向系统上报crash事件
                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  // 确保进程会退出,因为可能上报时失败或没有被系统kill,需要主动进行退出
        // Try everything to make sure this process goes away.
        Process.killProcess(Process.myPid());
        System.exit(10);  // 最后强制退出
    

KillApplicationHandler#ensureLogging

该方法主要是用来打印crash log

private void ensureLogging(Thread t, Throwable e) 
    if (!mLoggingHandler.mTriggered)  // 还没触发过
        try 
            mLoggingHandler.uncaughtException(t, e); // 处理log
         catch (Throwable loggingThrowable) 
            // Ignored.
        
    

LoggingHandler处理crash log打印

private static class LoggingHandler implements Thread.UncaughtExceptionHandler 
    public volatile boolean mTriggered = false;

    @Override
    public void uncaughtException(Thread t, Throwable e) 
        mTriggered = true;// 标记已进入

        // Don't re-enter if KillApplicationHandler has already run
        if (mCrashing) return;

        // mApplicationObject is null for non-zygote java programs (e.g. "am")
        // There are also apps running with the system UID. We don't want the
        // first clause in either of these two cases, only for system_server.
        if (mApplicationObject == null && (Process.SYSTEM_UID == Process.myUid()))  // 打印系统crash log
            Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
         else  // 打印应用 crash log
            logUncaught(t.getName(), ActivityThread.currentProcessName(), Process.myPid(), e);
        
    

RuntimeInit#logUncaught
打印应用crash log

public static void logUncaught(String threadName, String processName, int pid, Throwable e) 
    StringBuilder message = new StringBuilder();
    // The "FATAL EXCEPTION" string is still used on Android even though
    // apps can set a custom UncaughtExceptionHandler that renders uncaught
    // exceptions non-fatal.
    message.append("FATAL EXCEPTION: ").append(threadName).append("\\n");
    if (processName != null) 
        message.append("Process: ").append(processName).append(", ");
    
    message.append("PID: ").append(pid);
    Clog_e(TAG, message.toString(), e);

结合上面,当系统进程crash时打印

E AndroidRuntime:  "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), + e

应用crash时打印

E AndroidRuntime: FATAL EXCEPTION: threadName
E AndroidRuntime: Process: xxx, PID: xxx

crash上报过程

在应用端通过如下代码进行上报。

ActivityManager.getService().handleApplicationCrash(...)

ActivityManager.getService() 获取的是 AMS 的 Binder Proxy 对象,因此会调用到AMS进行处理。

ActivityManagerService#handleApplicationCrash

/// @frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
/**
 * Used by @link com.android.internal.os.RuntimeInit to report when an application crashes.
 * The application process will exit immediately after this call returns.
 * @param app object of the crashing app, null for the system server
 * @param crashInfo describing the exception
 */
public void handleApplicationCrash(IBinder app,  // IApplicationThread BinderProxy
        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); // 内部版本。


ActivityManagerService#handleApplicationCrashInner

/* 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) 
    float loadingProgress = 1;
    IncrementalMetrics incrementalMetrics = null;
    // Obtain Incremental information if available
    ...

    // event log打印crash, 可以搜索 am_crash
    EventLogTags.writeAmCrash(Binder.getCallingPid(),
            UserHandle.getUserId(Binder.getCallingUid()), processName,
            r == null ? -1 : r.info.flags,
            crashInfo.exceptionClassName,
            crashInfo.exceptionMessage,
            crashInfo.throwFileName,
            crashInfo.throwLineNumber);

    FrameworkStatsLog.write(FrameworkStatsLog.APP_CRASH_OCCURRED,
            (r != null) ? r.uid : -1,  eventType, processName, ...incrementalMetrics... );

    final int relaunchReason = r == null ? RELAUNCH_REASON_NONE
                    : r.getWindowProcessController().computeRelaunchReason();
    final String relaunchReasonString = relaunchReasonToString(relaunchReason);
    if (crashInfo.crashTag == null) 
        crashInfo.crashTag = relaunchReasonString;
     else 
        crashInfo.crashTag = crashInfo.crashTag + " " + relaunchReasonString;
    
    // 输出到 Dropbox, 路径是 /data/system/dropbox
    addErrorToDropBox(
            eventType, r, processName, null, null, null, null, null, null, crashInfo,
            new Float(loadingProgress), incrementalMetrics, null);

    mAppErrors.crashApplication(r, crashInfo); // 继续执行crash,显示crash对话框


AppErrors#crashApplication

/**
 * Bring up the "unexpected error" dialog box for a crashing app.
 * Deal with edge cases (intercepts from instrumented applications,
 * ActivityController, error intent receivers, that sort of thing).
 * @param r the application crashing
 * @param crashInfo describing the failure
 */
void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) 
    final int callingPid = Binder.getCallingPid();
    final int callingUid = Binder.getCallingUid();

    final long origId = Binder.clearCallingIdentity();
    try 
        crashApplicationInner(r, crashInfo, callingPid, callingUid);
     finally 
        Binder.restoreCallingIdentity(origId);
    

AppErrors#crashApplicationInner

显示crash对话框,并等待点击对话框按钮,当点击相关按钮或者超时后处理相关逻辑

private void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
        int callingPid, int callingUid) 
    long timeMillis = System.currentTimeMillis();
    String shortMsg = crashInfo.exceptionClassName; // 异常类名,比如 java.lang.IllegalArgumentException
    String longMsg = crashInfo.exceptionMessage; // 发生异常信息
    String stackTrace = crashInfo.stackTrace; // crash 堆栈
    if (shortMsg != null && longMsg != null) 
        longMsg = shortMsg + ": " + longMsg;
     else if (shortMsg != null) 
        longMsg = shortMsg;
    

    if (r != null) 
        mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode(),
                PackageWatchdog.FAILURE_REASON_APP_CRASH); // 通知PackageWatchdog 应用crash

        mService.mProcessList.noteAppKill(r, (crashInfo != null
                  && "Native crash".equals(crashInfo.exceptionClassName))
                  ? ApplicationExitInfo.REASON_CRASH_NATIVE
                  : ApplicationExitInfo.REASON_CRASH,
                  ApplicationExitInfo.SUBREASON_UNKNOWN,
                "crash"); // 记录app kill
    

    final int relaunchReason = r != null
            ? r.getWindowProcessController().computeRelaunchReason() : RELAUNCH_REASON_NONE;

    AppErrorResult result = new AppErrorResult();
    int taskId;
    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))  // IActivityController处理crash,比如monkey下
            return;
        

        // Suppress crash dialog if the process is being relaunched due to a crash during a free
        // resize.
        if (relaunchReason == RELAUNCH_REASON_FREE_RESIZE)  // 在resize时 发生crash导致relaunch
            return;
        

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

        // Log crash in battery stats.
        if (r != null) 
            mService.mBatteryStatsService.noteProcessCrash(r.processName, r.uid);
        
        // 发送消息显示dialog消息
        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))  // 处理crash状态,比如太频繁或次数限制,在12h内 crash 要小于12次, 否则不会显示 crash对话框。当然,当用户主动启动应用的时候,这个记录将会被清除掉。
            return;
        

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

        taskId = data.taskId;
        msg.obj = data;
        mService.mUiHandler.sendMessage(msg); // 发消息显示crash对话框
    

    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; // 超时或取消都会强制退出
    
    switch (res) 
        case AppErrorDialog.MUTE: // 禁止再弹框,
            synchronized (mBadProcessLock) 
                stopReportingCrashesLBp(r);
            
            break;
        case AppErrorDialog.RESTART: // 重启应用,
            synchronized (mService) 
                mService.mProcessList.removeProcessLocked(r, false, true,
                        ApplicationExitInfo.REASON_CRASH, "crash");
            
            if (taskId != INVALID_TASK_ID) 
                try 
                    mService.startActivityFromRecents(taskId,
                            ActivityOptions.makeBasic().toBundle());
                 catch (IllegalArgumentException e) 
                    // Hmm...that didn't work. Task should either be in recents or associated
                    // with a stack.
                    Slog.e(TAG, "Could not restart taskId=" + taskId, e);
                
            
            break;
        case AppErrorDialog.FORCE_QUIT: // 强制退出。
            final long orig = Binder.clearCallingIdentity();
            try 
                // Kill it with fire!
                mService.mAtmInternal.onHandleAppCrash(r.getWindowProcessController());
                if (!r.isPersistent()) 
                    synchronized (mService) 
                        mService.mProcessList.removeProcessLocked(r, false, false,
                                ApplicationExitInfo.REASON_CRASH, "crash");
                    
                    mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
                
             finally 
                Binder.restoreCallingIdentity(orig);
            
            break;
        case AppErrorDialog.APP_INFO: // 进入设置里app的详情页
            appErrorIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            appErrorIntent.setData(Uri.parse("package:" + r.info.packageName));
            appErrorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            break;
        case AppErrorDialog.FORCE_QUIT_AND_REPORT:// 通过intent上报crash事件,android.intent.action.APP_ERROR
            synchronized (mProcLock) 
                appErrorIntent = createAppErrorIntentLOSP(r, timeMillis, crashInfo);
            
            break;
    

    if (appErrorIntent != null)  // 执行intent启动相关页
        try 
            mContext.startActivityAsUser(appErrorIntent, new UserHandle(r.userId));
         catch (ActivityNotFoundException e) 
            Slog.w(TAG, "bug report receiver dissappeared", e);
        
    


AppErrors#makeAppCrashingLocked

设置app crash状态,并处理crash状态。 返回true表示显示crash对话框

@GuardedBy("mService")
private boolean makeAppCrashingLocked(ProcessRecord app,
        String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) 
    synchronized (mProcLock) 
        final ProcessErrorStateRecord errState = app.mErrorState;
        errState.setCrashing(true); // 设置 mCrashing = true
        errState.setCrashingReport(generateProcessError(app,
                ActivityManager.ProcessErrorStateInfo.CRASHED,
                null, shortMsg, longMsg, stackTrace));
        errState.startAppProblemLSP(); // 设置是否需要 report
        app.getWindowProcessController().stopFreezingActivities(); // 停止冻结屏幕
        synchronized (mBadProcessLock) 
            return handleAppCrashLSPB(app, "force-crash" /*reason*/, shortMsg, longMsg,
                    stackTrace, data);
        
    

AppErrors#handleAppCrashLSPB

@GuardedBy("mService", "mProcLock", "mBadProcessLock")
private boolean handleAppCrashLSPB(ProcessRecord app, String reason,
        String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) 
    final long now = SystemClock.uptimeMillis();
    final boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(),
            Settings.Secure.ANR_SHOW_BACKGROUND, 0,
            mService.mUserController.getCurrentUserId()) != 0;

    Long crashTime;
    Long crashTimePersistent;
    final String processName = app.processName;
    final int uid = app.uid;
    final int userId = app.userId;
    final boolean isolated = app.isolated;
    final boolean persistent = app.isPersistent();
    final WindowProcessController proc = app.getWindowProcessController();
    final ProcessErrorStateRecord errState = app.mErrorState;

    if (!app.isolated) 
        crashTime = mProcessCrashTimes.get(processName, uid); // 上次crash时间
        crashTimePersistent = mProcessCrashTimesPersistent.get(processName, uid); // 上次crash时间,显示启动时也不会清理
     else 
        crashTime = crashTimePersistent = null;
    

    // Bump up the crash count of any services currently running in the proc.
    boolean tryAgain = app.mServices.incServiceCrashCountLocked(now);// 检测是否需要重启服务

    final boolean quickCrash = crashTime != null
            && now < crashTime + ActivityManagerConstants.MIN_CRASH_INTERVAL; // 两次crash时间间隔小于 2分钟 则crash过快
    if (quickCrash || isProcOverCrashLimitLBp(app, now))  // crash 过快或超过限制
        // The process either crashed again very quickly or has been crashing periodically in
        // the last few hours. If it was a bound foreground service, let's try to restart again
        // in a while, otherwise the process loses!
        Slog.w(TAG, "Process " + processName + " has crashed too many times, killing!"
                + " Reason: " + (quickCrash ? "crashed quickly" : "over process crash limit"));
        EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
                userId, processName, uid); // 输出 crash 过多
        mService.mAtmInternal.onHandleAppCrash(proc);// 通知所有Activity app crash
        if (!persistent)  // 非 persistent
            // We don't want to start this process again until the user
            // explicitly does so...  but for persistent process, we really
            // need to keep it running.  If a persistent process is actually
            // repeatedly crashing, then badness for everyone.
            EventLog.writeEvent(EventLogTags.AM_PROC_BAD, userId, uid,
                    processName); // 输出 proc bad 的 event log
            if (!isolated) 
                // XXX We don't have a way to mark isolated processes
                // as bad, since they don't have a persistent identity.
                markBadProcess(processName, app.uid,
                        new BadProcessInfo(now, shortMsg, longMsg, stackTrace));// 添加到bad process 列表
                mProcessCrashTimes.remove(processName, app.uid);
                mProcessCrashCounts.remove(processName, app.uid);
            
            errState.setBad(true); // 标记process 为 bad
            app.setRemoved(true);
            final AppStandbyInternal appStandbyInternal =
                    LocalServices.getService(AppStandbyInternal.class);
            if (appStandbyInternal != null)  // 处理 appStandby 相关
                appStandbyInternal.restrictApp(
                        // Sometimes the processName is the same as the package name, so use
                        // that if we don't have the ApplicationInfo object.
                        // AppStandbyController will just return if it can't find the app.
                        app.info != null ? app.info.packageName : processName,
                        userId, UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY);
            
            // Don't let services in this process be restarted and potentially
            // annoy the user repeatedly.  Unless it is persistent, since those
            // processes run critical code.
            mService.mProcessList.removeProcessLocked(app, false, tryAgain,
                    ApplicationExitInfo.REASON_CRASH, "crash"); // 此处直接移除process
            mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */); // 尝试 resume top
            if (!showBackground) 
                return false;
            
        
        mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */); // 如果是persistent的,直接resume top
     else 
        // 尝试 finish 该crash app 所有栈的top Activity 并返回finish的 top taskId, 重启应用时可能会用到
        final int affectedTaskId = mService.mAtmInternal.finishTopCrashedActivities(
                        proc, reason);
        if (data != null) 
            data.taskId = affectedTaskId;
        
        if (data != null && crashTimePersistent != null
                && now < crashTimePersistent + ActivityManagerConstants.MIN_CRASH_INTERVAL) 
            data.repeating = true; // 2 分钟内再次 crash
        
    

    if (data != null && tryAgain) // 2分钟内,前台或被前台绑定的服务crash,在限制次数内(16次),则会tryAgain,对话框多出一个restart按钮
        data.isRestartableForService = true;
    

    // If the crashing process is what we consider to be the "home process" and it has been
    // replaced by a third-party app, clear the package preferred activities from packages
    // with a home activity running in the process to prevent a repeatedly crashing app
    // from blocking the user to manually clear the list.
    if (proc.isHomeProcess() && proc.hasActivities() && (app.info.flags & FLAG_SYSTEM) == 0) 
        proc.clearPackagePreferredForHomeActivities(); // 三方桌面crash,清除默认选项
    

    if (!isolated)  // 保存crash时间和更新次数
        // XXX Can't keep track of crash times for isolated processes,
        // because they don't have a persistent identity.
        mProcessCrashTimes.put(processName, uid, now);
        mProcessCrashTimesPersistent.put(processName, uid, now);
        updateProcessCrashCountLBp(processName, uid, now);
    

    if (errState.getCrashHandler() != null) 
        mService.mHandler.post(errState.getCrashHandler());
    
    return true;


AppErrors#isProcOverCrashLimitLBp

判断crash次数是否超过限制,在12h内只能crash 12次,否则将不会显示crash对话框,当然这个记录在显示启动应用的时候会被清除,比如ProcessList#startProcessLocked方法中有相关处理。

@GuardedBy("mBadProcessLock")
private boolean isProcOverCrashLimitLBp(ProcessRecord app, long now) 
    final Pair<Long, Integer> crashCount = mProcessCrashCounts.get(app.processName, app.uid);
    return !app.isolated && crashCount != null
            && now < (crashCount.first + PROCESS_CRASH_COUNT_RESET_INTERVAL) // 12小时
            && crashCount.second >= PROCESS_CRASH_COUNT_LIMIT; // 12次


ProcessList#startProcessLocked 方法如下,对进程状态有一些调整:

frameworks/base/services/core/java/com/android/server/am/ProcessList.java
@GuardedBy("mService")
ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
        boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
        int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid,
        String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) 
    long startTime = SystemClock.uptimeMillis();
    ProcessRecord app;
    if (!isolated) 
        app = getProcessRecordLocked(processName, info.uid);
        checkSlow(startTime, "startProcess: after getProcessRecord");

        if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0)  // 后台启动的
            // If we are in the background, then check to see if this process
            // is bad.  If so, we will just silently fail.
            if (mService.mAppErrors.isBadProcess(processName, info.uid)) // bad状态的不在启动
                if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
                        + "/" + processName);
                return null;
            
         else  // 显式启动情况
            // When the user is explicitly starting a process, then clear its
            // crash count so that we won't make it bad until they see at
            // least one crash dialog again, and make the process good again
            // if it had been bad.
            if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
                    + "/" + processName);
            mService.mAppErrors.resetProcessCrashTime(processName, info.uid);// 清除crash次数的记录
            if (mService.mAppErrors.isBadProcess(processName, info.uid)) // 清除bad状态
                EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
                        UserHandle.getUserId(info.uid), info.uid,
                        info.processName);
                mService.mAppErrors.clearBadProcess(processName, info.uid);
                if (app != null) 
                    app.mErrorState.setBad(false);
                
            
        
    ...

AppErrors#handleShowAppErrorUi

再回到 crashApplicationInner,当发送显示对话框后,UiThread将会处理 SHOW_ERROR_UI_MSG消息,这部分实现在AMS的UiHandler

public void handleMessage(Message msg) 
    switch (msg.what) 
        case SHOW_ERROR_UI_MSG: 
            mAppErrors.handleShowAppErrorUi(msg); // 回调 AppErrors 的 handleShowAppErrorUi 方法
            ensureBootCompleted();
         break;

接下来看 AppErrors#handleShowAppErrorUi

void handleShowAppErrorUi(Message msg) 
    AppErrorDialog.Data data = (AppErrorDialog.Data) msg.obj;
    boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(),
            Settings.Secure.ANR_SHOW_BACKGROUND, 0,
            mService.mUserController.getCurrentUserId()) != 0; // 显示bg进程的dialog

    final int userId;
    synchronized (mProcLock) 
        final ProcessRecord proc = data.proc;
        final AppErrorResult res = data.result;
        if (proc == null) 
            Slog.e(TAG, "handleShowAppErrorUi: proc is null");
            return;
        
        final ProcessErrorStateRecord errState = proc.mErrorState;
        userId = proc.userId;
        if (errState.getDialogController().hasCrashDialogs())  // 已经显示,
            Slog.e(TAG, "App already has crash dialog: " + proc);
            if (res != null) 
                res.set(AppErrorDialog.ALREADY_SHOWING);
            
            return;
        
        boolean isBackground = (UserHandle.getAppId(proc.uid)
                >= Process.FIRST_APPLICATION_UID
                && proc.getPid() != MY_PID);
        for (int profileId : mService.mUserController.getCurrentProfileIds()) 
            isBackground &= (userId != profileId);
        
        if (isBackground && !showBackground) // ANR_SHOW_BACKGROUND settings值没开,禁止显示后台进程crash
            Slog.w(TAG, "Skipping crash dialog of " + proc + ": background");
            if (res != null) 
                res.set(AppErrorDialog.BACKGROUND_USER);
            
            return;
        
        Long crashShowErrorTime = null;
        synchronized (mBadProcessLock) 
            if (!proc.isolated) 
                crashShowErrorTime = mProcessCrashShowDialogTimes.get(proc.processName,
                        proc.uid);
            
            final boolean showFirstCrash = Settings.Global.getInt(
                    mContext.getContentResolver(),
                    Settings.Global.SHOW_FIRST_CRASH_DIALOG, 0) != 0; // 是否第一次就显示,默认是关闭的
            final boolean showFirstCrashDevOption = Settings.Secure.getIntForUser(
                    mContext.getContentResolver(),
                    Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
                    0,
                    mService.mUserController.getCurrentUserId()) != 0;
            final boolean crashSilenced = mAppsNotReportingCrashes != null
                    && mAppsNotReportingCrashes.contains(proc.info.packageName);// 之前点过 mute按钮
            final long now = SystemClock.uptimeMillis();
            final boolean shouldThottle = crashShowErrorTime != null
                    && now < crashShowErrorTime + ActivityManagerConstants.MIN_CRASH_INTERVAL;//离上次显示crash dialog时间小于2分钟
            if ((mService.mAtmInternal.canShowErrorDialogs() || showBackground) // mAtmInternal判断可以显示 或者 可以显示后台
                    && !crashSilenced && !shouldThottle     // 没有 mute,离上次显示crash过去2分钟
                    && (showFirstCrash || showFirstCrashDevOption || data.repeating)) // 默认实现是初次不显示,在2分钟内的再次crash才显示
                errState.getDialogController().showCrashDialogs(data); //  显示 dialog
                if (!proc.isolated) 
                    mProcessCrashShowDialogTimes.put(proc.processName, proc.uid, now);
                
             else 
                // The device is asleep, so just pretend that the user
                // saw a crash dialog and hit "force quit".
                if (res != null) 
                    res.set(AppErrorDialog.CANT_SHOW);
                
            
        
    


如下是atm判断是否显示error dialog的方法:

/// ActivityTaskManagerService.LocalService extends ActivityTaskManagerInternal
@Override
public boolean canShowErrorDialogs() 
    synchronized (mGlobalLock) 
        return mShowDialogs && !mSleeping && !mShuttingDown // 机器没有休眠、关闭
                && !mKeyguardController.isKeyguardOrAodShowing(DEFAULT_DISPLAY) // 没有锁屏或显示 AOD
                && !hasUserRestriction(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS,
                mAmInternal.getCurrentUserId())    // user 没有被限制
                && !(UserManager.isDeviceInDemoMode(mContext)
                && mAmInternal.getCurrentUser().isDemo());  // 没有处于 demo mode 下
    

接下来看 dialog 的显示

ErrorDialogController#showCrashDialogs

/// @frameworks/base/services/core/java/com/android/server/am/ErrorDialogController.java
@GuardedBy("mProcLock")
void showCrashDialogs(AppErrorDialog.Data data) 
    // 收集crash应用所属的 display Context
    List<Context> contexts = getDisplayContexts(false /* lastUsedOnly */);
    mCrashDialogs = new ArrayList<>();
    for (int i = contexts.size() - 1; i >= 0; i--)  // 对每个Context创建一个dialog
        final Context c = contexts.get(i);
        mCrashDialogs.add(new AppErrorDialog(c, mService, data));
    
    mService.mUiHandler.post(() ->  // 将这些dialog显示出来
        List<AppErrorDialog> dialogs;
        synchronized (mProcLock) 
            dialogs = mCrashDialogs;
        
        if (dialogs != null) 
            forAllDialogs(dialogs, Dialog::show); // 调用 dialog.show
        
    );

AppErrorDialog 的构造方法和 onCreate 方法中有许多初始化操作,此处省略。

AppErrorDialog#onClick

处理点击事件

/// @frameworks/base/services/core/java/com/android/server/am/AppErrorDialog.java
@Override
public void onClick(View v) 
    switch (v.getId()) 
        case com.android.internal.R.id.aerr_restart: // 重启
            mHandler.obtainMessage(RESTART).sendToTarget();
            break;
        case com.android.internal.R.id.aerr_report: // 上报
            mHandler.obtainMessage(FORCE_QUIT_AND_REPORT).sendToTarget();
            break;
        case com.android.internal.R.id.aerr_close:// 关闭
            mHandler.obtainMessage(FORCE_QUIT).sendToTarget();
            break;
        case com.android.internal.R.id.aerr_app_info:// app详情页
            mHandler.obtainMessage(APP_INFO).sendToTarget();
            break;
        case com.android.internal.R.id.aerr_mute:// 不再显示,
            mHandler.obtainMessage(MUTE).sendToTarget();
            break;
        default:
            break;
    


// 处理消息
private final Handler mHandler = new Handler() 
    public void handleMessage(Message msg) 
        setResult(msg.what);  // 设置 result ,比如 FORCE_QUIT
        dismiss();  // 关闭dialog,如果没有设置result,则默认设置为 FORCE_QUIT
    
;

// 该方法用于设置点击的结果,通知 APPErrors 继续
private void setResult(int result) 
    synchronized (mProcLock) 
        if (mProc != null) 
            // Don't dismiss again since it leads to recursive call between dismiss and this method.
            mProc.mErrorState.getDialogController().clearCrashDialogs(false /* needDismiss */);
        
    
    mResult.set(result); // 设置result通知APPErrors 继续执行

    // Make sure we don't have time timeout still hanging around.
    mHandler.removeMessages(TIMEOUT);

再回到 crashApplicationInner,当点击对话框按钮或者超时后,会设置一个result,之后会继续处理结果

int res = result.get(); // 当获取result后返回, 使用的是Java的 wait/notify 机制

Intent appErrorIntent = null;
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res);
if (res == AppErrorDialog.TIMEOUT || res == AppErrorDialog.CANCEL) 
    res = AppErrorDialog.FORCE_QUIT;

switch (res) 
    ...
    case AppErrorDialog.FORCE_QUIT:
        final long orig = Binder.clearCallingIdentity();
        try 
            // Kill it with fire!
            mService.mAtmInternal.onHandleAppCrash(r.getWindowProcessController());//通知atm应用crash,准备关闭动画等
            if (!r.isPersistent())  // 如果不是persistent应用 则会移除此应用
                synchronized (mService) 
                    mService.mProcessList.removeProcessLocked(r, false, false,
                            ApplicationExitInfo.REASON_CRASH, "crash"); // 移除进程,并kill
                
                mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);//再尝试resume top
            
         finally 
            Binder.restoreCallingIdentity(orig);
        
        break;

ProcessList#removeProcessLocked

@GuardedBy("mService")
boolean removeProcessLocked(ProcessRecord app,
        boolean callerWillRestart, boolean allowRestart, int reasonCode, String reason) 
    return removeProcessLocked(app, callerWillRestart, allowRestart, reasonCode,
            ApplicationExitInfo.SUBREASON_UNKNOWN, reason); // 调用重载方法


@GuardedBy("mService")
boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart,
        boolean allowRestart, int reasonCode, int subReason, String reason) 
    final String name = app.processName;
    final int uid = app.uid;
    if (DEBUG_PROCESSES) Slog.d(TAG_PROCESSES,
            "Force removing proc " + app.toShortString() + " (" + name + "/" + uid + ")");

    ProcessRecord old = mProcessNames.get(name, uid);
    if (old != app) 
        // This process is no longer active, so nothing to do.
        Slog.w(TAG, "Ignoring remove of inactive process: " + app);
        return false;
    
    removeProcessNameLocked(name, uid);  // 移除 process 记录
    mService.mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());

    boolean needRestart = false;
    final int pid = app.getPid();
    if ((pid > 0 && pid != ActivityManagerService.MY_PID)
            || (pid == 0 && app.isPendingStart()))  // 非系统进程 或 待启动
        if (pid > 0)  // 进程存在,
            mService.removePidLocked(pid, app); // 移除 pid 记录
            app.setBindMountPending(false);
            mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
            mService.mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
            if (app.isolated) 
                mService.mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
                mService.getPackageManagerInternal().removeIsolatedUid(app.uid);
            
        
        boolean willRestart = false;
        if (app.isPersistent() && !app.isolated)  // persistent 应用会重启
            if (!callerWillRestart) 
                willRestart = true;
             else 
                needRestart = true;
            
        
        app.killLocked(reason, reasonCode, subReason, true); // kill 应用
        mService.handleAppDiedLocked(app, pid, willRestart, allowRestart,
                false /* fromBinderDied */);  // 杀进程后的清理
        if (willRestart)  // 重启动
            removeLruProcessLocked(app);
            mService.addAppLocked(app.info, null, false, null /* ABI override */,
                    ZYGOTE_POLICY_FLAG_EMPTY);
        
     else 
        mRemovedProcesses.add(app);
    

    return needRestart;


ProcessRecord#killLocked

杀进程实现

/// @frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java
@GuardedBy("mService")
void killLocked(String reason, @Reason int reasonCode, @SubReason int subReason,
        boolean noisy) 
    if (!mKilledByAm)  // 还没有被 am kill
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill");
        if (mService != null && (noisy || info.uid == mService.mCurOomAdjUid)) 
            mService.reportUidInfoMessageLocked(TAG,
                    "Killing " + toShortString() + " (adj " + mState.getSetAdj()
                    + "): " + reason, info.uid);
        
        if (mPid > 0) 
            mService.mProcessList.noteAppKill(this, reasonCode, subReason, reason);
            EventLog.writeEvent(EventLogTags.AM_KILL,
                    userId, mPid, processName, mState.getSetAdj(), reason); // 打印 am_kill
            Process.killProcessQuiet(mPid); // 静默杀死应用
            ProcessList.killProcessGroup(uid, mPid); // 杀死应用组
         else 
            mPendingStart = false;
        
        if (!mPersistent)  // 非persistent设置kill标志
            synchronized (mProcLock) 
                mKilled = true;
                mKilledByAm = true;
                mKillTime = SystemClock.uptimeMillis();
            
        
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    

AMS#handleAppDiedLocked

执行清理工作

/**
 * Main function for removing an existing process from the activity manager
 * as a result of that process going away.  Clears out all connections
 * to the process.
 */
@GuardedBy("this")
final void handleAppDiedLocked(ProcessRecord app, int pid,
        boolean restarting, boolean allowRestart, boolean fromBinderDied) 
    boolean kept = cleanUpApplicationRecordLocked(app, pid, restarting, allowRestart, -1,
            false /*replacingPid*/, fromBinderDied); // 清理应用相关记录
    if (!kept && !restarting) 
        removeLruProcessLocked(app);
        if (pid > 0) 
            ProcessList.remove(pid);
        
    

    mAppProfiler.onAppDiedLocked(app);
    // atm 处理应用死亡
    mAtmInternal.handleAppDied(app.getWindowProcessController(), restarting, () -> 
        Slog.w(TAG, "Crash of app " + app.processName
                + " running instrumentation " + app.getActiveInstrumentation().mClass);
        Bundle info = new Bundle();
        info.putString("shortMsg", "Process crashed.");
        finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
    );


AMS$cleanUpApplicationRecordLocked
@GuardedBy("this")
final boolean cleanUpApplicationRecordLocked(ProcessRecord app, int pid,
        boolean restarting, boolean allowRestart, int index, boolean replacingPid,
        boolean fromBinderDied) 
    boolean restart;
    synchronized (mProcLock) 
        if (index >= 0) 
            removeLruProcessLocked(app);
            ProcessList.remove(pid);
        

        // We don't want to unlinkDeathRecipient immediately, if it's not called from binder
        // and it's not isolated, as we'd need the signal to bookkeeping the dying process list.
        restart = app.onCleanupApplicationRecordLSP(mProcessStats, allowRestart,
                fromBinderDied || app.isolated /* unlinkDeath */);// 清理应用相关记录

        // Cancel pending frozen task if there is any.
        mOomAdjuster.mCachedAppOptimizer.unscheduleFreezeAppLSP(app);
    
    mAppProfiler.onCleanupApplicationRecordLocked(app);
    skipCurrentReceiverLocked(app); // 略过发给app的广播
    updateProcessForegroundLocked(app, false, 0, false);
    mServices.killServicesLocked(app, allowRestart); // 移除应用服务相关连接
    mPhantomProcessList.onAppDied(pid);

    // If the app is undergoing backup, tell the backup manager about it
    ...

    mProcessList.scheduleDispatchProcessDiedLocked(pid, app.info.uid);// 派发进程死亡通知

    // If this is a preceding instance of another process instance
    allowRestart = mProcessList.handlePrecedingAppDiedLocked(app);

    // If the caller is restarting this app, then leave it in its
    // current lists and let the caller take care of it.
    if (restarting) 
        return false;
    

    if (!app.isPersistent() || app.isolated)  // 非persistent,移除记录
        if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
                "Removing non-persistent process during cleanup: " + app);
        if (!replacingPid) 
            mProcessList.removeProcessNameLocked(app.processName, app.uid, app);
        
        mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());
     else if (!app.isRemoved())  // persistent, 保留进程记录
        // This app is persistent, so we need to keep its record around.
        // If it is not already on the pending app list, add it there
        // and start a new process for it.
        if (mPersistentStartingProcesses.indexOf(app) < 0) 
            mPersistentStartingProcesses.add(app);
            restart = true;
        
    
    if ((DEBUG_PROCESSES || DEBUG_CLEANUP) && mProcessesOnHold.contains(app)) Slog.v(
            TAG_CLEANUP, "Clean-up removing on hold: " + app);
    mProcessesOnHold.remove(app);

    mAtmInternal.onCleanUpApplicationRecord(app.getWindowProcessController());
    mProcessList.noteProcessDiedLocked(app);// 移除一些监听

    if (restart && allowRestart && !app.isolated)  // 需要重启
        // We have components that still need to be running in the
        // process, so re-launch it.
        if (index < 0) 
            ProcessList.remove(pid);
        

        // Remove provider publish timeout because we will start a new timeout when the
        // restarted process is attaching (if the process contains launching providers).
        mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, app);

        mProcessList.addProcessNameLocked(app); // 重新添加记录
        app.setPendingStart(false);
        mProcessList.startProcessLocked(app, new HostingRecord("restart", app.processName),
                ZYGOTE_POLICY_FLAG_EMPTY);  // 启动新进程
        return true;
     else if (pid > 0 && pid != MY_PID)  // 移除,结束
        // Goodbye!
        removePidLocked(pid, app);
        mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
        mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
        if (app.isolated) 
            mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
        
        app.setPid(0);
    
    return false;


ProcessRecord#onCleanupApplicationRecordLSP
/// @frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java
@GuardedBy("mService", "mProcLock")
boolean onCleanupApplicationRecordLSP(ProcessStatsService processStats, boolean allowRestart,
        boolean unlinkDeath) 
    mErrorState.onCleanupApplicationRecordLSP();//清除一些error状态

    resetPackageList(processStats);
    if (unlinkDeath)  // 有条件的 unlink,
        unlinkDeathRecipient(); // 执行此操作后进程退出后系统不会收到binderDied回调
    
    makeInactive(processStats);
    setWaitingToKill(null);

    mState.onCleanupApplicationRecordLSP();
    mServices.onCleanupApplicationRecordLocked(); // 服务清理,
    mReceivers.onCleanupApplicationRecordLocked(); // 广播清理,

    return mProviders.onCleanupApplicationRecordLocked(allowRestart);// provider清理

接下来看atm的一些清理工作

ActivityTaskManagerService.LocalService#handleAppDied
@HotPath(caller = HotPath.PROCESS_CHANGE)
@Override
public void handleAppDied(WindowProcessController wpc, boolean restarting,
        Runnable finishInstrumentationCallback) 
    synchronized (mGlobalLockWithoutBoost) 
        mTaskSupervisor.beginDeferResume();
        final boolean hasVisibleActivities;
        try 
            // Remove this application's activities from active lists.
            hasVisibleActivities = wpc.handleAppDied(); // 清理进程的 activities
         finally 
            mTaskSupervisor.endDeferResume();
        

        if (!restarting && hasVisibleActivities) 
            deferWindowLayout();
            try 
                if (!mRootWindowContainer.resumeFocusedTasksTopActivities())  // resume activity
                    // If there was nothing to resume, and we are not already restarting
                    // this process, but there is a visible activity that is hosted by the
                    // process...then make sure all visible activities are running, taking
                    // care of restarting this process.
                    mRootWindowContainer.ensureActivitiesVisible(null, 0,
                            !PRESERVE_WINDOWS);
                
           

以上是关于Android 12 应用Java crash流程分析的主要内容,如果未能解决你的问题,请参考以下文章

Android 12 进程native crash流程分析

Android 12 进程native crash流程分析

Android怎样捕获应用的crash信息

Android 平台的Crash崩溃捕获-全

获取Android崩溃crash信息并写入日志发送邮件

Flutter App 针对 Android 12 CRASHES => FLAG_IMMUTABLE 或 FLAG_MUTABLE 在创建 PendingIntent 时指定