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> [--] <start class name> <args>
* </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流程分析的主要内容,如果未能解决你的问题,请参考以下文章
Flutter App 针对 Android 12 CRASHES => FLAG_IMMUTABLE 或 FLAG_MUTABLE 在创建 PendingIntent 时指定