Android系統(tǒng)發(fā)生Java crash時(shí)候酌壕,沒有去捕獲處理它的話蒸播,它就會(huì)一路往上拋,最終來到main函數(shù)场航,如果main函數(shù)也沒有處理這個(gè)異常缠导,就會(huì)給到JVM來處理,JVM會(huì)給到當(dāng)前的線程Thread來處理溉痢。
art/runtime/well_known_classes.cc
java_lang_Thread_dispatchUncaughtException = CacheMethod(env, java_lang_Thread, false, "dispatchUncaughtException", "(Ljava/lang/Throwable;)V");
調(diào)用到當(dāng)前線程的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.
*這個(gè)方法只能被runtime執(zhí)行僻造, 當(dāng)現(xiàn)成出現(xiàn)沒有捕獲的異常的時(shí)候執(zhí)行憋他,
* @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;
}
如果沒有設(shè)置uncaughtExceptionHandler,將使用線程所在的線程組(ThreadGroup)來處理這個(gè)未捕獲異常髓削。線程組ThreadGroup實(shí)現(xiàn)了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);
}
}
}
默認(rèn)情況下立膛,ThreadGroup處理未捕獲異常的邏輯是:
1揪罕、首先將異常消息通知給父線程組(如果parent不為空的話);
2宝泵、然后嘗試?yán)靡粋€(gè)默認(rèn)的defaultUncaughtExceptionHandler來處理異常好啰;
3、如果沒有默認(rèn)的異常處理器則將錯(cuò)誤信息輸出打印到System.err儿奶。
如果設(shè)置了uncaughtExceptionHandler 坎怪,誰回調(diào)下面的這個(gè)接口就可以處理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 是什么時(shí)候設(shè)置的
它的設(shè)置在RuntimeInit.java中
不管是系統(tǒng)進(jìn)程還是App進(jìn)程廓握,啟動(dòng)的時(shí)候都會(huì)走到這里搅窿,進(jìn)行注冊(cè)。
/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);
//這里設(shè)置了默認(rèn)的異常處理:KillApplicationHandler隙券。
Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
}
再看下KillApplicationHandler:
/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
@Override //回調(diào)了uncaughtException接口男应,處理異常
public void uncaughtException(Thread t, Throwable e) {
try {
......
//上報(bào)給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 {
//殺掉進(jìn)程
Process.killProcess(Process.myPid());
//退出當(dāng)前進(jìn)程
System.exit(10);
}
}
默認(rèn)的異常處理(殺進(jìn)程)是在RuntimeInit進(jìn)程(作用:app運(yùn)行時(shí)環(huán)境初始化,用來初始化運(yùn)行時(shí)的一系列信息娱仔,其中包含異常處理)的main()方法里設(shè)置的沐飘。
/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);
}
參數(shù)eventType是指事件類型,具體如下:
Java層未捕捉的異常:crash
ANR:anr
native層的異常:native_crash
現(xiàn)在我們看的是java的異常牲迫,所以這個(gè)類型傳的是crash耐朴。
接著看handleApplicationCrashInner()函數(shù):
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);
}
進(jìn)行系統(tǒng)日志輸出,具體的處理是在addErrorToDropBox()函數(shù)中盹憎。當(dāng)啟動(dòng)Activity時(shí)候筛峭,如果找不到,會(huì)報(bào)錯(cuò)陪每,這個(gè)時(shí)候systemserver進(jìn)程中的啟動(dòng)數(shù)據(jù)依然存在影晓,存在緩存信息,要清除檩禾。
接著看下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;
// 發(fā)送消息挂签,彈出crash對(duì)話框,等待用戶選擇
//如果選擇重新啟動(dòng)盼产,則從最近任務(wù)列表中找到崩潰進(jìn)程饵婆,再次拉起
//如果選擇強(qiáng)制退出,則殺掉app戏售,進(jìn)入kill流程
//如果選擇顯示應(yīng)用信息侨核,則啟動(dòng)系統(tǒng)頁面的intent草穆,打開應(yīng)用詳情頁面
mService.mUiHandler.sendMessage(msg);
}
// 得到用戶選擇結(jié)果
int res = result.get();
Intent appErrorIntent = null;
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res);
// 如果是超時(shí)或者取消,則當(dāng)成是強(qiáng)制退出
if (res == AppErrorDialog.TIMEOUT || res == AppErrorDialog.CANCEL) {
res = AppErrorDialog.FORCE_QUIT;
}
synchronized (mService) {
if (res == AppErrorDialog.MUTE) {
stopReportingCrashesLocked(r);
}
// 如果是重新啟動(dòng)
if (res == AppErrorDialog.RESTART) {
mService.mProcessList.removeProcessLocked(r, false, true, "crash");
if (taskId != INVALID_TASK_ID) {
try {
//1. 從最近的任務(wù)列表中找到崩潰進(jìn)程芹关,再次啟動(dòng)
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!
// 殺掉這個(gè)進(jìn)程
mService.mAtmInternal.onHandleAppCrash(r.getWindowProcessController());
if (!r.isPersistent()) {
mService.mProcessList.removeProcessLocked(r, false, false, "crash");
mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
}
} finally {
Binder.restoreCallingIdentity(orig);
}
}
// 如果是顯示應(yīng)用信息
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. 啟動(dòng)一個(gè)系統(tǒng)頁面的intent 來顯示應(yīng)用信息
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);
// 獲取當(dāng)前user的 error receiver续挟;停止廣播接收
app.startAppProblemLocked();
// 停是凍結(jié)屏幕
app.getWindowProcessController().stopFreezingActivities();
// 調(diào)用 handleAppCrashLocked
return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace,
data);
}
封裝崩潰信息到 ProcessErrorStateInfo 中
獲取當(dāng)前user的 error receiver紧卒;停止廣播接收
停是凍結(jié)屏幕
handleAppCrashLocked()
boolean handleAppCrashLocked(ProcessRecord app, String reason,
String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
......
// 同一個(gè)進(jìn)程侥衬,如果連續(xù)兩次崩潰的間隔小于 一分鐘,則認(rèn)為崩潰過于頻繁
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 回調(diào) atm的onHandleAppCrash
mService.mAtmInternal.onHandleAppCrash(app.getWindowProcessController());
if (!app.isPersistent()) {
// 如果不是persistent進(jìn)程,則不再重啟跑芳,除非用戶主動(dòng)觸發(fā)
// 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.
// 移除進(jìn)程中的所有服務(wù)
mService.mProcessList.removeProcessLocked(app, false, tryAgain, "crash");
// 恢復(fù)頂部的activity
mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
if (!showBackground) {
return false;
}
}
mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
} else {
// 不是一分鐘內(nèi)連續(xù)崩潰
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;
}
如果是兩次連續(xù)崩潰小于一分鐘,則認(rèn)為是頻繁崩潰博个。
調(diào)用onHandleAppCrash方法
如果不是persistent進(jìn)程,則不再重啟怀樟,除非用戶主動(dòng)觸發(fā)
移除進(jìn)程中的所有服務(wù),且不再重啟
恢復(fù)棧頂?shù)腶ctivity
不是連續(xù)崩潰盆佣,則記錄崩潰受影響的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對(duì)象
final ActivityStack stack = display.getChildAt(stackNdx);
stack.handleAppCrash(app);
}
}
}
>ActivityStack.java
void handleAppCrash(WindowProcessController app) {
// 循環(huán)ActivityStack中管理的 TaskRecord
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
// 得到 TaskRecord中管理的所有 ActivityRecord集合
final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
// 遍歷 ActivityRecord集合,得到每一個(gè) ActivityRecord對(duì)象
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
// 如果是崩潰的進(jìn)程共耍,則銷毀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銷毀當(dāng)前activity
finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,
"handleAppCrashedLocked");
}
}
}
}
AMS端在收到App的崩潰后虑灰,大概流程如下:
把崩潰信息通過 DBS 服務(wù),寫入到Dropbox文件中痹兜。dropbox支持錯(cuò)誤類型:crash穆咐、wtf、anr
停止崩潰進(jìn)程接收廣播字旭;增加ServiceRecord中的crashcount數(shù)对湃;銷毀所有的activies;
彈出崩潰對(duì)話框遗淳,等待用戶選擇
- 如果選擇重新啟動(dòng)拍柒,則從最近任務(wù)列表中找到崩潰進(jìn)程,再次拉起
- 如果選擇強(qiáng)制退出屈暗,則殺掉app斤儿,進(jìn)入kill流程
- 如果選擇顯示應(yīng)用信息,則啟動(dòng)系統(tǒng)頁面的intent恐锦,打開應(yīng)用詳情頁面
Binder服務(wù)死亡通知
在RuntimeInit uncaughtException 末尾會(huì)執(zhí)行
finally {
// Try everything to make sure this process goes away.
// 最終關(guān)閉kill掉進(jìn)程
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);
給指定的進(jìn)程發(fā)送一個(gè) SIGNAL_KILL 信號(hào)往果。應(yīng)用進(jìn)程已經(jīng)被殺死,但是還沒完一铅。因?yàn)閟ystem server進(jìn)程中有注冊(cè)Binder服務(wù)的死亡監(jiān)聽陕贮。當(dāng)App進(jìn)程死亡后,會(huì)回調(diào)到AMS
的死亡監(jiān)聽中潘飘,此時(shí)還需要處理Binder死亡通知回調(diào)邏輯肮之。
在創(chuàng)建進(jìn)程的過程中掉缺,ActivityThread會(huì)調(diào)用AMS的 attachApplication(), 內(nèi)部會(huì)調(diào)用到 attachApplicationLocked()方法。在這里注冊(cè)的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;
}
//...
}
當(dāng)有binder服務(wù)死亡眶明,會(huì)調(diào)用 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;
}
......
// 調(diào)用 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) {
// 移除崩潰進(jìn)程在AMS中的代表 ProcessRecord
removeLruProcessLocked(app);
if (pid > 0) {
ProcessList.remove(pid);
}
}
if (mProfileData.getProfileProc() == app) {
clearProfilerLocked();
}
// 繼續(xù)調(diào)用 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相關(guān)信息
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.
// 確保恢復(fù)頂部的activity
mRootActivityContainer.ensureActivitiesVisible(null, 0,
!PRESERVE_WINDOWS);
}
} finally {
// windows相關(guān)
mWindowManager.continueSurfaceLayout();
}
}
}
}
當(dāng)App發(fā)生崩潰后柑土,除了彈出對(duì)話框蜀肘,發(fā)送kill命令殺掉自身后。AMS還會(huì)收到App進(jìn)程的Binder服務(wù)死亡通知稽屏,只有當(dāng)走完Binder的 binderDied()流程后扮宠,整個(gè)崩潰流程才算真正結(jié)束。