Android系统发生Java crash时候,没有去捕获处理它的话,它就会一路往上抛,最终来到main函数,如果main函数也没有处理这个异常,就会给到JVM来处理,JVM会给到当前的线程Thread来处理。
art/runtime/well_known_classes.cc
java_lang_Thread_dispatchUncaughtException = CacheMethod(env, java_lang_Thread, false, "dispatchUncaughtException", "(Ljava/lang/Throwable;)V");
调用到当前线程的dispatchUncaughtException 方法
libcore/ojluni/src/main/java/java/lang/Thread.java
/**
* Dispatch an uncaught exception to the handler. This method is
* intended to be called only by the runtime and by tests.
*这个方法只能被runtime执行, 当现成出现没有捕获的异常的时候执行,
* @hide
*/
public final void dispatchUncaughtException(Throwable e) {
Thread.UncaughtExceptionHandler initialUeh =
Thread.getUncaughtExceptionPreHandler();
if (initialUeh != null) {
try {
initialUeh.uncaughtException(this, e);
} catch (RuntimeException | Error ignored) {
// Throwables thrown by the initial handler are ignored
}
}
getUncaughtExceptionHandler().uncaughtException(this, e);
}
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
如果没有设置uncaughtExceptionHandler,将使用线程所在的线程组(ThreadGroup)来处理这个未捕获异常。线程组ThreadGroup实现了UncaughtExceptionHandler,所以可以用来处理未捕获异常。
libcore/ojluni/src/main/java/java/lang/ThreadGroup.java
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else {
Thread.UncaughtExceptionHandler ueh =
Thread.getDefaultUncaughtExceptionHandler();
if (ueh != null) {
ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
System.err.print("Exception in thread \""
+ t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
默认情况下,ThreadGroup处理未捕获异常的逻辑是:
1、首先将异常消息通知给父线程组(如果parent不为空的话);
2、然后尝试利用一个默认的defaultUncaughtExceptionHandler来处理异常;
3、如果没有默认的异常处理器则将错误信息输出打印到System.err。
如果设置了uncaughtExceptionHandler ,谁回调下面的这个接口就可以处理crash异常。
/libcore/ojluni/src/main/java/java/lang/Thread.java
@FunctionalInterface
public interface UncaughtExceptionHandler {
void uncaughtException(Thread t, Throwable e);
}
setUncaughtExceptionPreHandler
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
return defaultUncaughtExceptionHandler;
}
private static volatile UncaughtExceptionHandler uncaughtExceptionPreHandler;
public static void setUncaughtExceptionPreHandler(UncaughtExceptionHandler eh) {
uncaughtExceptionPreHandler = eh;
}
再看下 setUncaughtExceptionPreHandler 是什么时候设置的
它的设置在RuntimeInit.java中
不管是系统进程还是App进程,启动的时候都会走到这里,进行注册。
/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
public static final void main(String[] argv) {
......
commonInit();
......
}
protected static final void commonInit() {
LoggingHandler loggingHandler = new LoggingHandler();
Thread.setUncaughtExceptionPreHandler(loggingHandler);
//这里设置了默认的异常处理:KillApplicationHandler。
Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
}
再看下KillApplicationHandler:
/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
@Override //回调了uncaughtException接口,处理异常
public void uncaughtException(Thread t, Throwable e) {
try {
......
//上报给AMS 崩溃异常信息
ActivityManager.getService().handleApplicationCrash(
mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
} catch (Throwable t2) {
if (t2 instanceof DeadObjectException) {
// System process is dead; ignore
} else {
try {
Clog_e(TAG, "Error reporting crash", t2);
} catch (Throwable t3) {
// Even Clog_e() fails! Oh well.
}
}
} finally {
//杀掉进程
Process.killProcess(Process.myPid());
//退出当前进程
System.exit(10);
}
}
默认的异常处理(杀进程)是在RuntimeInit进程(作用:app运行时环境初始化,用来初始化运行时的一系列信息,其中包含异常处理)的main()方法里设置的。
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void handleApplicationCrash(IBinder app,
ApplicationErrorReport.ParcelableCrashInfo crashInfo) {
ProcessRecord r = findAppProcess(app, "Crash");
final String processName = app == null ? "system_server"
: (r == null ? "unknown" : r.processName);
handleApplicationCrashInner("crash", r, processName, crashInfo);
}
参数eventType是指事件类型,具体如下:
Java层未捕捉的异常:crash
ANR:anr
native层的异常:native_crash
现在我们看的是java的异常,所以这个类型传的是crash。
接着看handleApplicationCrashInner()函数:
void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
ApplicationErrorReport.CrashInfo crashInfo) {
EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
UserHandle.getUserId(Binder.getCallingUid()), processName,
r == null ? -1 : r.info.flags,
crashInfo.exceptionClassName,
crashInfo.exceptionMessage,
crashInfo.throwFileName,
crashInfo.throwLineNumber);
StatsLog.write(StatsLog.APP_CRASH_OCCURRED,
Binder.getCallingUid(),
eventType,
processName,
Binder.getCallingPid(),
(r != null && r.info != null) ? r.info.packageName : "",
(r != null && r.info != null) ? (r.info.isInstantApp()
? StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__TRUE
: StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__FALSE)
: StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__UNAVAILABLE,
r != null ? (r.isInterestingToUserLocked()
? StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__FOREGROUND
: StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__BACKGROUND)
: StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__UNKNOWN
);
addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
mAppErrors.crashApplication(r, crashInfo);
}
进行系统日志输出,具体的处理是在addErrorToDropBox()函数中。当启动Activity时候,如果找不到,会报错,这个时候systemserver进程中的启动数据依然存在,存在缓存信息,要清除。
接着看下AppErrors.crashApplication
/frameworks/base/services/core/java/com/android/server/am/AppErrors.java
void crashApplication{
......
crashApplicationInner(......);
......
}
void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
int callingPid, int callingUid) {
......
synchronized (mService) {
......
if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, data)) {
return;
}
AppErrorDialog.Data data = new AppErrorDialog.Data();
data.result = result;
data.proc = r;
final Message msg = Message.obtain();
msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;
taskId = data.taskId;
msg.obj = data;
// 发送消息,弹出crash对话框,等待用户选择
//如果选择重新启动,则从最近任务列表中找到崩溃进程,再次拉起
//如果选择强制退出,则杀掉app,进入kill流程
//如果选择显示应用信息,则启动系统页面的intent,打开应用详情页面
mService.mUiHandler.sendMessage(msg);
}
// 得到用户选择结果
int res = result.get();
Intent appErrorIntent = null;
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res);
// 如果是超时或者取消,则当成是强制退出
if (res == AppErrorDialog.TIMEOUT || res == AppErrorDialog.CANCEL) {
res = AppErrorDialog.FORCE_QUIT;
}
synchronized (mService) {
if (res == AppErrorDialog.MUTE) {
stopReportingCrashesLocked(r);
}
// 如果是重新启动
if (res == AppErrorDialog.RESTART) {
mService.mProcessList.removeProcessLocked(r, false, true, "crash");
if (taskId != INVALID_TASK_ID) {
try {
//1. 从最近的任务列表中找到崩溃进程,再次启动
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);
}
}
}
// 如果是退出
if (res == AppErrorDialog.FORCE_QUIT) {
long orig = Binder.clearCallingIdentity();
try {
// Kill it with fire!
// 杀掉这个进程
mService.mAtmInternal.onHandleAppCrash(r.getWindowProcessController());
if (!r.isPersistent()) {
mService.mProcessList.removeProcessLocked(r, false, false, "crash");
mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
}
} finally {
Binder.restoreCallingIdentity(orig);
}
}
// 如果是显示应用信息
if (res == AppErrorDialog.APP_INFO) {
appErrorIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
appErrorIntent.setData(Uri.parse("package:" + r.info.packageName));
appErrorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
}
if (r != null && !r.isolated && res != AppErrorDialog.RESTART) {
// XXX Can't keep track of crash time for isolated processes,
// since they don't have a persistent identity.
mProcessCrashTimes.put(r.info.processName, r.uid,
SystemClock.uptimeMillis());
}
}
if (appErrorIntent != null) {
try {
// 2. 启动一个系统页面的intent 来显示应用信息
mContext.startActivityAsUser(appErrorIntent, new UserHandle(r.userId));
} catch (ActivityNotFoundException e) {
Slog.w(TAG, "bug report receiver dissappeared", e);
}
}
}
makeAppCrashingLocked
private boolean makeAppCrashingLocked(ProcessRecord app,
String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
app.setCrashing(true);
// 封装崩溃信息到 ProcessErrorStateInfo 中
app.crashingReport = generateProcessError(app,
ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
// 获取当前user的 error receiver;停止广播接收
app.startAppProblemLocked();
// 停是冻结屏幕
app.getWindowProcessController().stopFreezingActivities();
// 调用 handleAppCrashLocked
return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace,
data);
}
封装崩溃信息到 ProcessErrorStateInfo 中
获取当前user的 error receiver;停止广播接收
停是冻结屏幕
handleAppCrashLocked()
boolean handleAppCrashLocked(ProcessRecord app, String reason,
String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
......
// 同一个进程,如果连续两次崩溃的间隔小于 一分钟,则认为崩溃过于频繁
if (crashTime != null && now < crashTime + ProcessList.MIN_CRASH_INTERVAL) {
// The process crashed again very quickly. If it was a bound foreground service, let's
// try to restart again in a while, otherwise the process loses!
Slog.w(TAG, "Process " + app.info.processName
+ " has crashed too many times: killing!");
EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
app.userId, app.info.processName, app.uid);
// 2.8.1 回调 atm的onHandleAppCrash
mService.mAtmInternal.onHandleAppCrash(app.getWindowProcessController());
if (!app.isPersistent()) {
// 如果不是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.
if (!app.isolated) {
// XXX We don't have a way to mark isolated processes
// as bad, since they don't have a peristent identity.
mBadProcesses.put(app.info.processName, app.uid,
new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
mProcessCrashTimes.remove(app.info.processName, app.uid);
}
app.bad = true;
app.removed = true;
// 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, "crash");
// 恢复顶部的activity
mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
if (!showBackground) {
return false;
}
}
mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
} else {
// 不是一分钟内连续崩溃
final int affectedTaskId = mService.mAtmInternal.finishTopCrashedActivities(
app.getWindowProcessController(), reason);
if (data != null) {
data.taskId = affectedTaskId;
}
if (data != null && crashTimePersistent != null
&& now < crashTimePersistent + ProcessList.MIN_CRASH_INTERVAL) {
data.repeating = true;
}
}
......
// 如果 app的crashHandler存在,则交给其处理
if (app.crashHandler != null) mService.mHandler.post(app.crashHandler);
return true;
}
如果是两次连续崩溃小于一分钟,则认为是频繁崩溃。
调用onHandleAppCrash方法
如果不是persistent进程,则不再重启,除非用户主动触发
移除进程中的所有服务,且不再重启
恢复栈顶的activity
不是连续崩溃,则记录崩溃受影响的taskid
如果 app的crashHandler存在,则交给其处理
/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@Override
public void onHandleAppCrash(WindowProcessController wpc) {
synchronized (mGlobalLock) {
mRootActivityContainer.handleAppCrash(wpc);
}
}
//RootActivityContainer.java
void handleAppCrash(WindowProcessController app) {
// 遍历所有的ActivityDisplay
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
// 遍历ActivityDisplay中管理的所有 ActivityStack
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
// 获取activity stack对象
final ActivityStack stack = display.getChildAt(stackNdx);
stack.handleAppCrash(app);
}
}
}
>ActivityStack.java
void handleAppCrash(WindowProcessController app) {
// 循环ActivityStack中管理的 TaskRecord
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
// 得到 TaskRecord中管理的所有 ActivityRecord集合
final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
// 遍历 ActivityRecord集合,得到每一个 ActivityRecord对象
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
// 如果是崩溃的进程,则销毁activity
if (r.app == app) {
// Force the destroy to skip right to removal.
r.app = null;
//
getDisplay().mDisplayContent.prepareAppTransition(
TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
// finish销毁当前activity
finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,
"handleAppCrashedLocked");
}
}
}
}
AMS端在收到App的崩溃后,大概流程如下:
把崩溃信息通过 DBS 服务,写入到Dropbox文件中。dropbox支持错误类型:crash、wtf、anr
停止崩溃进程接收广播;增加ServiceRecord中的crashcount数;销毁所有的activies;
弹出崩溃对话框,等待用户选择
- 如果选择重新启动,则从最近任务列表中找到崩溃进程,再次拉起
- 如果选择强制退出,则杀掉app,进入kill流程
- 如果选择显示应用信息,则启动系统页面的intent,打开应用详情页面
Binder服务死亡通知
在RuntimeInit uncaughtException 末尾会执行
finally {
// Try everything to make sure this process goes away.
// 最终关闭kill掉进程
Process.killProcess(Process.myPid());
System.exit(10);
}
public static final void killProcess(int pid) {
sendSignal(pid, SIGNAL_KILL);
}
public static final native void sendSignal(int pid, int signal);
给指定的进程发送一个 SIGNAL_KILL 信号。应用进程已经被杀死,但是还没完。因为system server进程中有注册Binder服务的死亡监听。当App进程死亡后,会回调到AMS
的死亡监听中,此时还需要处理Binder死亡通知回调逻辑。
在创建进程的过程中,ActivityThread会调用AMS的 attachApplication(), 内部会调用到 attachApplicationLocked()方法。在这里注册的Binder的死亡通知。
ActivityThread.java
@GuardedBy("this")
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
//...
try {
AppDeathRecipient adr = new AppDeathRecipient(
app, pid, thread);
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
} catch (RemoteException e) {
app.resetPackageList(mProcessStats);
mProcessList.startProcessLocked(app,
new HostingRecord("link fail", processName));
return false;
}
//...
}
当有binder服务死亡,会调用 AppDeathRecipient 的 binderDied()方法:
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private final class AppDeathRecipient implements IBinder.DeathRecipient {
final ProcessRecord mApp;
final int mPid;
final IApplicationThread mAppThread;
AppDeathRecipient(ProcessRecord app, int pid,
IApplicationThread thread) {
if (DEBUG_ALL) Slog.v(
TAG, "New death recipient " + this
+ " for thread " + thread.asBinder());
mApp = app;
mPid = pid;
mAppThread = thread;
}
@Override
public void binderDied() {
if (DEBUG_ALL) Slog.v(
TAG, "Death received in " + this
+ " for thread " + mAppThread.asBinder());
synchronized(ActivityManagerService.this) {
appDiedLocked(mApp, mPid, mAppThread, true);
}
}
}
@GuardedBy("this")
final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread,
boolean fromBinderDied) {
......
// 如果没有被杀,再次杀app
if (!app.killed) {
if (!fromBinderDied) {
killProcessQuiet(pid);
}
ProcessList.killProcessGroup(app.uid, pid);
app.killed = true;
}
......
// 调用 handleAppDiedLocked
handleAppDiedLocked(app, false, true);
......
}
//...
}
final void handleAppDiedLocked(ProcessRecord app,
boolean restarting, boolean allowRestart) {
int pid = app.pid;
// 清理service、broadcastreveiver、contentprovider等信息
boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1,
false /*replacingPid*/);
if (!kept && !restarting) {
// 移除崩溃进程在AMS中的代表 ProcessRecord
removeLruProcessLocked(app);
if (pid > 0) {
ProcessList.remove(pid);
}
}
if (mProfileData.getProfileProc() == app) {
clearProfilerLocked();
}
// 继续调用 atm的 handleAppDied
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);
});
}
/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
public void handleAppDied(WindowProcessController wpc, boolean restarting,
Runnable finishInstrumentationCallback) {
synchronized (mGlobalLockWithoutBoost) {
// Remove this application's activities from active lists.
// 清理activities相关信息
boolean hasVisibleActivities = mRootActivityContainer.handleAppDied(wpc);
wpc.clearRecentTasks();
wpc.clearActivities();
if (wpc.isInstrumenting()) {
finishInstrumentationCallback.run();
}
if (!restarting && hasVisibleActivities) {
mWindowManager.deferSurfaceLayout();
try {
if (!mRootActivityContainer.resumeFocusedStacksTopActivities()) {
// 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.
// 确保恢复顶部的activity
mRootActivityContainer.ensureActivitiesVisible(null, 0,
!PRESERVE_WINDOWS);
}
} finally {
// windows相关
mWindowManager.continueSurfaceLayout();
}
}
}
}
当App发生崩溃后,除了弹出对话框,发送kill命令杀掉自身后。AMS还会收到App进程的Binder服务死亡通知,只有当走完Binder的 binderDied()流程后,整个崩溃流程才算真正结束。