一 概述
App crash(全称Application crash), 对于Crash可分为native crash和framework crash(包含app crash在内),对于crash相信很多app开发者都会遇到,那么上层什么时候会出现crash呢,系统又是如何处理crash的呢。例如,在app大家经常使用try…catch语句,那么如果没有有效catch exception,就是导致应用crash,发生没有catch exception,系统便会来进行捕获,并进入crash流程。如果你是从事Android系统开发或者架构相关工作,或者遇到需要解系统性的疑难杂症,那么很有必要了解系统Crash处理流程,知其然还需知其所以然;如果你仅仅是App初级开发,可能本文并非很适合阅读,整个系统流程错综复杂。
在Android系统启动系列文章,已讲述过上层应用都是由Zygote fork孵化而来,分为system_server系统进程和各种应用进程,在这些进程创建之初会设置未捕获异常的处理器,当系统抛出未捕获的异常时,最终都交给异常处理器。
对于system_server进程:文章Android系统启动-SystemServer上篇,system_server启动过程中由RuntimeInit.java的commonInit方法设置UncaughtHandler,用于处理未捕获异常;
对于普通应用进程:文章理解Android进程创建流程 ,进程创建过程中,同样会调用RuntimeInit.java的commonInit方法设置UncaughtHandler。
1.1 crash调用链
crash流程的方法调用关系来结尾:
AMP.handleApplicationCrash
AMS.handleApplicationCrash
AMS.findAppProcess
AMS.handleApplicationCrashInner
AMS.addErrorToDropBox
AMS.crashApplication
AMS.makeAppCrashingLocked
AMS.startAppProblemLocked
ProcessRecord.stopFreezingAllLocked
ActivityRecord.stopFreezingScreenLocked
WMS.stopFreezingScreenLocked
WMS.stopFreezingDisplayLocked
AMS.handleAppCrashLocked
mUiHandler.sendMessage(SHOW_ERROR_MSG)
Process.killProcess(Process.myPid());
System.exit(10);
接下来说说这个过程。
1.2 涉及代码
/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
/frameworks/base/core/java/android/app/ActivityManagerNative.java (含内部类AMP)
/frameworks/base/core/java/android/app/ApplicationErrorReport.java
/frameworks/base/services/core/java/com/android/server/
- am/ActivityManagerService.java
- am/ProcessRecord.java
- am/ActivityRecord.java
- am/ActivityStackSupervisor.java
- am/ActivityStack.java
- am/ActivityRecord.java
- am/BroadcastQueue.java
- wm/WindowManagerService.java
/libcore/libart/src/main/java/java/lang/Thread.java
二 Crash处理流程
那么接下来以commonInit()方法为起点来展开说明。
2.1 RuntimeInit.commonInit
public class RuntimeInit {
...
private static final void commonInit() {
//设置默认的未捕获异常处理器,UncaughtHandler实例化过程【见小节2】
Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
...
}
}
setDefaultUncaughtExceptionHandler()只是将异常处理器handler对象赋给Thread成员变量,即Thread.defaultUncaughtHandler = new UncaughtHandler()。接下来看看UncaughtHandler对象实例化过程。
2.2 UncaughtHandler
RuntimeInit.java
private static class UncaughtHandler implements Thread.UncaughtExceptionHandler {
//覆写接口方法
public void uncaughtException(Thread t, Throwable e) {
try {
//保证crash处理过程不会重入
if (mCrashing) return;
mCrashing = true;
if (mApplicationObject == null) {
//system_server进程
Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
} else {
//普通应用进程
StringBuilder message = new StringBuilder();
message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n");
final String processName = ActivityThread.currentProcessName();
if (processName != null) {
message.append("Process: ").append(processName).append(", ");
}
message.append("PID: ").append(Process.myPid());
Clog_e(TAG, message.toString(), e);
}
//启动crash对话框,等待处理完成 【见小节2.1和3】
ActivityManagerNative.getDefault().handleApplicationCrash(
mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
} catch (Throwable t2) {
...
} finally {
//确保当前进程彻底杀掉【见小节11】
Process.killProcess(Process.myPid());
System.exit(10);
}
}
}
1.当system进程crash的信息:
- 开头*** FATAL EXCEPTION IN SYSTEM PROCESS [线程名];
- 接着输出发生crash时的调用栈信息;
2.当app进程crash时的信息:
- 开头FATAL EXCEPTION: [线程名];
- 紧接着 Process: [进程名], PID: [进程id];
- 最后输出发生crash时的调用栈信息。
看到这里,你就会发现要从log中搜索crash信息,只需要搜索关键词FATAL EXCEPTION;如果需要进一步筛选只搜索系统crash信息,则可以搜索的关键词可以有多样,比如*** FATAL EXCEPTION。
当输出完crash信息到logcat里面,这只是crash流程的刚开始阶段,接下来弹出crash对话框,ActivityManagerNative.getDefault()返回的是ActivityManagerProxy(简称AMP),AMP经过binder调用最终交给ActivityManagerService(简称AMS)中相应的方法去处理,故接下来调用的是AMS.handleApplicationCrash()。
注意: mApplicationObject等于null,一定不是普通的app进程. 但是除了system进程, 也有可能是shell进程, 即通过app_process + 命令参数 的方式创建的进程.
2.2.1 CrashInfo
ApplicationErrorReport.java
public class ApplicationErrorReport implements Parcelable {
...
public static class CrashInfo {
public CrashInfo(Throwable tr) {
StringWriter sw = new StringWriter();
PrintWriter pw = new FastPrintWriter(sw, false, 256);
tr.printStackTrace(pw); //输出栈trace
pw.flush();
stackTrace = sw.toString();
exceptionMessage = tr.getMessage();
Throwable rootTr = tr;
while (tr.getCause() != null) {
tr = tr.getCause();
if (tr.getStackTrace() != null && tr.getStackTrace().length > 0) {
rootTr = tr;
}
String msg = tr.getMessage();
if (msg != null && msg.length() > 0) {
exceptionMessage = msg;
}
}
exceptionClassName = rootTr.getClass().getName();
if (rootTr.getStackTrace().length > 0) {
StackTraceElement trace = rootTr.getStackTrace()[0];
throwFileName = trace.getFileName();
throwClassName = trace.getClassName();
throwMethodName = trace.getMethodName();
throwLineNumber = trace.getLineNumber();
} else {
throwFileName = "unknown";
throwClassName = "unknown";
throwMethodName = "unknown";
throwLineNumber = 0;
}
}
...
}
}
将crash信息文件名,类名,方法名,对应行号以及异常信息都封装到CrashInfo对象。
2.3 handleApplicationCrash
ActivityManagerService.java
public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
//获取进程record对象【见小节3.1】
ProcessRecord r = findAppProcess(app, "Crash");
final String processName = app == null ? "system_server"
: (r == null ? "unknown" : r.processName);
//【见小节4】
handleApplicationCrashInner("crash", r, processName, crashInfo);
}
关于进程名(processName):
- 当远程IBinder对象为空时,则进程名为system_server;
- 当远程IBinder对象不为空,且ProcessRecord为空时,则进程名为unknown;
- 当远程IBinder对象不为空,且ProcessRecord不为空时,则进程名为ProcessRecord对象中相应进程名。
2.3.1 findAppProcess
ActivityManagerService.java
private ProcessRecord findAppProcess(IBinder app, String reason) {
if (app == null) {
return null;
}
synchronized (this) {
final int NP = mProcessNames.getMap().size();
for (int ip=0; ip<NP; ip++) {
SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
final int NA = apps.size();
for (int ia=0; ia<NA; ia++) {
ProcessRecord p = apps.valueAt(ia);
//当找到目标进程则返回
if (p.thread != null && p.thread.asBinder() == app) {
return p;
}
}
}
//如果代码执行到这里,表明无法找到应用所在的进程
return null;
}
}
其中 mProcessNames = new ProcessMap();对于代码mProcessNames.getMap()返回的是mMap,而mMap= new ArrayMap<String, SparseArray>();
知识延伸:SparseArray和ArrayMap是Android专门针对内存优化而设计的取代Java API中的HashMap的数据结构。对于key是int类型则使用SparseArray,可避免自动装箱过程;对于key为其他类型则使用ArrayMap。HashMap的查找和插入时间复杂度为O(1)的代价是牺牲大量的内存来实现的,而SparseArray和ArrayMap性能略逊于HashMap,但更节省内存。
再回到mMap,这是以进程name为key,再以(uid为key,以ProcessRecord为Value的)结构体作为value。下面看看其get()和put()方法
//获取mMap中(name,uid)所对应的ProcessRecord
public ProcessRecord get(String name, int uid) {};
//将(name,uid, value)添加到mMap
public ProcessRecord put(String name, int uid, ProcessRecord value) {};
findAppProcess()根据app(IBinder类型)来查询相应的目标对象ProcessRecord。
有了进程记录对象ProcessRecord和进程名processName,则进入执行Crash处理方法,继续往下看。
2.4 handleApplicationCrashInner
ActivityManagerService.java
void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
ApplicationErrorReport.CrashInfo crashInfo) {
//将Crash信息写入到Event log
EventLog.writeEvent(EventLogTags.AM_CRASH,...);
//将错误信息添加到DropBox
addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
//【见小节5】
crashApplication(r, crashInfo);
}
其中addErrorToDropBox是将crash的信息输出到目录/data/system/dropbox。例如system_server的dropbox文件名为[email protected] (xxx代表的是时间戳)
2.5 crashApplication
ActivityManagerService.java
private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
long timeMillis = System.currentTimeMillis();
String shortMsg = crashInfo.exceptionClassName;
String longMsg = crashInfo.exceptionMessage;
String stackTrace = crashInfo.stackTrace;
if (shortMsg != null && longMsg != null) {
longMsg = shortMsg + ": " + longMsg;
} else if (shortMsg != null) {
longMsg = shortMsg;
}
AppErrorResult result = new AppErrorResult();
synchronized (this) {
// 当存在ActivityController的情况,比如monkey
if (mController != null) {
try {
String name = r != null ? r.processName : null;
int pid = r != null ? r.pid : Binder.getCallingPid();
int uid = r != null ? r.info.uid : Binder.getCallingUid();
//调用monkey的appCrashed
if (!mController.appCrashed(name, pid,
shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"))
&& "Native crash".equals(crashInfo.exceptionClassName)) {
Slog.w(TAG, "Skip killing native crashed app " + name
+ "(" + pid + ") during testing");
} else {
Slog.w(TAG, "Force-killing crashed app " + name
+ " at watcher's request");
if (r != null) {
r.kill("crash", true);
} else {
Process.killProcess(pid);
killProcessGroup(uid, pid);
}
}
return;
}
} catch (RemoteException e) {
mController = null;
Watchdog.getInstance().setActivityController(null);
}
}
//清除远程调用者uid和pid信息,并保存到origId
final long origId = Binder.clearCallingIdentity();
...
//【见小节6】
if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) {
Binder.restoreCallingIdentity(origId);
return;
}
Message msg = Message.obtain();
msg.what = SHOW_ERROR_MSG;
HashMap data = new HashMap();
data.put("result", result);
data.put("app", r);
msg.obj = data;
//发送消息SHOW_ERROR_MSG,弹出提示crash的对话框,等待用户选择【见小节10】
mUiHandler.sendMessage(msg);
//恢复远程调用者uid和pid
Binder.restoreCallingIdentity(origId);
}
//进入阻塞等待,直到用户选择crash对话框"退出"或者"退出并报告"
int res = result.get();
Intent appErrorIntent = null;
synchronized (this) {
if (r != null && !r.isolated) {
// 将崩溃的进程信息保存到mProcessCrashTimes
mProcessCrashTimes.put(r.info.processName, r.uid,
SystemClock.uptimeMillis());
}
if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
//创建action="android.intent.action.APP_ERROR",组件为r.errorReportReceiver的Intent
appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
}
}
if (appErrorIntent != null) {
try {
//启动Intent为appErrorIntent的Activity
mContext.startActivityAsUser(appErrorIntent, new UserHandle(r.userId));
} catch (ActivityNotFoundException e) {
Slog.w(TAG, "bug report receiver dissappeared", e);
}
}
}
该方法主要做的两件事:
- 调用makeAppCrashingLocked,继续处理crash流程;
- 发送消息SHOW_ERROR_MSG,弹出提示crash的对话框,等待用户选择;
2.6 makeAppCrashingLocked
ActivityManagerService.java
private boolean makeAppCrashingLocked(ProcessRecord app, String shortMsg, String longMsg, String stackTrace) {
app.crashing = true;
//封装crash信息到crashingReport对象
app.crashingReport = generateProcessError(app,
ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
//【见小节7】
startAppProblemLocked(app);
//停止屏幕冻结【见小节8】
app.stopFreezingAllLocked();
//【见小节9】
return handleAppCrashLocked(app, "force-crash", shortMsg, longMsg, stackTrace);
}
2.7 startAppProblemLocked
ActivityManagerService.java
void startAppProblemLocked(ProcessRecord app) {
app.errorReportReceiver = null;
for (int userId : mCurrentProfileIds) {
if (app.userId == userId) {
//获取当前用户下的crash应用的error receiver【见小节7.1】
app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
mContext, app.info.packageName, app.info.flags);
}
}
//忽略当前app的广播接收【见小节7.2】
skipCurrentReceiverLocked(app);
}
该方法主要功能:
- 获取当前用户下的crash应用的error receiver;
- 忽略当前app的广播接收;
2.7.1 getErrorReportReceiver
ApplicationErrorReport.java
public static ComponentName getErrorReportReceiver(Context context,
String packageName, int appFlags) {
//检查Settings中的"send_action_app_error"是否使能错误报告的功能
int enabled = Settings.Global.getInt(context.getContentResolver(),
Settings.Global.SEND_ACTION_APP_ERROR, 0);
if (enabled == 0) {
//1.当未使能时,则直接返回
return null;
}
PackageManager pm = context.getPackageManager();
String candidate = null;
ComponentName result = null;
try {
//获取该crash应用的安装器的包名
candidate = pm.getInstallerPackageName(packageName);
} catch (IllegalArgumentException e) {
}
if (candidate != null) {
result = getErrorReportReceiver(pm, packageName, candidate);//【见下文】
if (result != null) {
//2.当找到该crash应用的安装器,则返回;
return result;
}
}
if ((appFlags&ApplicationInfo.FLAG_SYSTEM) != 0) {
//该系统属性名为"ro.error.receiver.system.apps"
candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
result = getErrorReportReceiver(pm, packageName, candidate);//【见下文】
if (result != null) {
//3.当crash应用是系统应用时,且系统属性指定error receiver时,则返回;
return result;
}
}
//该默认属性名为"ro.error.receiver.default"
candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
//4.当默认属性值指定error receiver时,则返回;
return getErrorReportReceiver(pm, packageName, candidate); //【见下文】
}
getErrorReportReceiver:这是同名不同输入参数的另一个方法:
static ComponentName getErrorReportReceiver(PackageManager pm, String errorPackage,
String receiverPackage) {
if (receiverPackage == null || receiverPackage.length() == 0) {
return null;
}
//当安装应用程序的安装器Crash,则直接返回
if (receiverPackage.equals(errorPackage)) {
return null;
}
//ACTION_APP_ERROR值为"android.intent.action.APP_ERROR"
Intent intent = new Intent(Intent.ACTION_APP_ERROR);
intent.setPackage(receiverPackage);
ResolveInfo info = pm.resolveActivity(intent, 0);
if (info == null || info.activityInfo == null) {
return null;
}
//创建包名为receiverPackage的组件
return new ComponentName(receiverPackage, info.activityInfo.name);
}
2.7.2 skipCurrentReceiverLocked
ActivityManagerService.java
void skipCurrentReceiverLocked(ProcessRecord app) {
for (BroadcastQueue queue : mBroadcastQueues) {
queue.skipCurrentReceiverLocked(app); //【见小节7.2.1】
}
}
2.7.2.1 skipCurrentReceiverLocked
BroadcastQueue.java
public void skipCurrentReceiverLocked(ProcessRecord app) {
BroadcastRecord r = null;
//查看app进程中的广播
if (mOrderedBroadcasts.size() > 0) {
BroadcastRecord br = mOrderedBroadcasts.get(0);
if (br.curApp == app) {
r = br;
}
}
if (r == null && mPendingBroadcast != null && mPendingBroadcast.curApp == app) {
r = mPendingBroadcast;
}
if (r != null) {
//结束app进程的广播结束
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
//广播调度
scheduleBroadcastsLocked();
}
}
2.8 PR.stopFreezingAllLocked
ProcessRecord.java
public void stopFreezingAllLocked() {
int i = activities.size();
while (i > 0) {
i--;
activities.get(i).stopFreezingScreenLocked(true); //【见小节8.1】
}
}
其中activities类型为ArrayList,停止进程里所有的Activity
2.8.1 AR.stopFreezingScreenLocked
ActivityRecord.java
public void stopFreezingScreenLocked(boolean force) {
if (force || frozenBeforeDestroy) {
frozenBeforeDestroy = false;
//mWindowManager类型为WMS //【见小节8.1.1】
service.mWindowManager.stopAppFreezingScreen(appToken, force);
}
}
其中appToken是IApplication.Stub类型,即WindowManager的token。
2.8.1.1 WMS.stopFreezingScreenLocked
WindowManagerService.java
@Override
public void stopFreezingScreen() {
//权限检查
if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN,
"stopFreezingScreen()")) {
throw new SecurityException("Requires FREEZE_SCREEN permission");
}
synchronized(mWindowMap) {
if (mClientFreezingScreen) {
mClientFreezingScreen = false;
mLastFinishedFreezeSource = "client";
final long origId = Binder.clearCallingIdentity();
try {
stopFreezingDisplayLocked(); //【见流程8.1.1.1】
} finally {
Binder.restoreCallingIdentity(origId);
}
}
}
}
2.8.1.2 WMS.stopFreezingDisplayLocked
WindowManagerService.java
private void stopFreezingDisplayLocked() {
if (!mDisplayFrozen) {
return; //显示没有冻结,则直接返回
}
//往往跟屏幕旋转相关
...
mDisplayFrozen = false;
//从上次冻屏到现在的总时长
mLastDisplayFreezeDuration = (int)(SystemClock.elapsedRealtime() - mDisplayFreezeTime);
//移除冻屏的超时消息
mH.removeMessages(H.APP_FREEZE_TIMEOUT);
mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
boolean updateRotation = false;
//获取默认的DisplayContent
final DisplayContent displayContent = getDefaultDisplayContentLocked();
final int displayId = displayContent.getDisplayId();
ScreenRotationAnimation screenRotationAnimation =
mAnimator.getScreenRotationAnimationLocked(displayId);
//屏幕旋转动画的相关操作
if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
&& screenRotationAnimation.hasScreenshot()) {
DisplayInfo displayInfo = displayContent.getDisplayInfo();
boolean isDimming = displayContent.isDimming();
if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, isDimming)) {
mExitAnimId = mEnterAnimId = 0;
}
//加载动画最大时长为10s
if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
getTransitionAnimationScaleLocked(), displayInfo.logicalWidth,
displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {
scheduleAnimationLocked();
} else {
screenRotationAnimation.kill();
mAnimator.setScreenRotationAnimationLocked(displayId, null);
updateRotation = true;
}
} else {
if (screenRotationAnimation != null) {
screenRotationAnimation.kill();
mAnimator.setScreenRotationAnimationLocked(displayId, null);
}
updateRotation = true;
}
//经过层层调用到InputManagerService服务,IMS服务使能输入事件分发功能
mInputMonitor.thawInputDispatchingLw();
boolean configChanged;
//当display被冻结时不再计算屏幕方向,以避免不连续的状态。
configChanged = updateOrientationFromAppTokensLocked(false);
//display冻结时,执行gc操作
mH.removeMessages(H.FORCE_GC);
mH.sendEmptyMessageDelayed(H.FORCE_GC, 2000);
//mScreenFrozenLock的类型为PowerManager.WakeLock,即释放屏幕冻结的锁
mScreenFrozenLock.release();
if (updateRotation) {
//更新当前的屏幕方向
configChanged |= updateRotationUncheckedLocked(false);
}
if (configChanged) {
//向mH发送configuraion改变的消息
mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
}
}
该方法主要功能:
- 处理屏幕旋转相关逻辑;
- 移除冻屏的超时消息;
- 屏幕旋转动画的相关操作;
- 使能输入事件分发功能;
- display冻结时,执行gc操作;
- 更新当前的屏幕方向;
- 向mH发送configuraion改变的消息。
2.9 AMS.handleAppCrashLocked
private boolean handleAppCrashLocked(ProcessRecord app, String reason, String shortMsg, String longMsg, String stackTrace) {
long now = SystemClock.uptimeMillis();
Long crashTime;
if (!app.isolated) {
crashTime = mProcessCrashTimes.get(app.info.processName, app.uid);
} else {
crashTime = null;
}
//当同一个进程,连续两次crash的时间间隔小于1分钟时,则认为crash太过于频繁
if (crashTime != null && now < crashTime+ProcessList.MIN_CRASH_INTERVAL) {
EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
app.userId, app.info.processName, app.uid);
//【见小节9.1】
mStackSupervisor.handleAppCrashLocked(app);
if (!app.persistent) {
//不再重启非persistent进程,除非用户显式地调用
EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.userId, app.uid,
app.info.processName);
if (!app.isolated) {
//将当前app加入到mBadProcesses
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;
//移除进程的所有服务,保证不再重启【见小节9.2】
removeProcessLocked(app, false, false, "crash");
//恢复最顶部的Activity【见小节9.3】
mStackSupervisor.resumeTopActivitiesLocked();
return false;
}
mStackSupervisor.resumeTopActivitiesLocked();
} else {
//此处reason="force-crash"【见小节9.4】
mStackSupervisor.finishTopRunningActivityLocked(app, reason);
}
//运行在当前进程中的所有服务的crash次数执行加1操作
for (int i=app.services.size()-1; i>=0; i--) {
ServiceRecord sr = app.services.valueAt(i);
sr.crashCount++;
}
//当桌面应用crash,并且被三方app所取代,那么需要清空桌面应用的偏爱选项。
final ArrayList<ActivityRecord> activities = app.activities;
if (app == mHomeProcess && activities.size() > 0
&& (mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
if (r.isHomeActivity()) {
//清空偏爱应用
ActivityThread.getPackageManager()
.clearPackagePreferredActivities(r.packageName);
}
}
}
if (!app.isolated) {
//无法记录孤立进程的crash时间点,由于他们并没有一个固定身份
mProcessCrashTimes.put(app.info.processName, app.uid, now);
}
//当app存在crash的handler,那么交给其处理
if (app.crashHandler != null) mHandler.post(app.crashHandler);
return true;
}
当同一进程在时间间隔小于1分钟时连续两次crash,则执行的情况下:
对于非persistent进程:
[9.1] mStackSupervisor.handleAppCrashLocked(app);
[9.2] removeProcessLocked(app, false, false, “crash”);
[9.3] mStackSupervisor.resumeTopActivitiesLocked();
对于persistent进程,则只执行
[9.3] mStackSupervisor.resumeTopActivitiesLocked();
否则执行
[9.4] mStackSupervisor.finishTopRunningActivityLocked(app, reason);
2.9.1 ASS.handleAppCrashLocked
ActivityStackSupervisor.java
void handleAppCrashLocked(ProcessRecord app) {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
int stackNdx = stacks.size() - 1;
while (stackNdx >= 0) {
//调用ActivityStack【见小节9.1.1】
stacks.get(stackNdx).handleAppCrashLocked(app);
stackNdx--;
}
}
}
2.9.1.1 AS.handleAppCrashLocked
ActivityStack.java
void handleAppCrashLocked(ProcessRecord app) {
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
if (r.app == app) {
r.app = null;
//结束当前activity
finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
}
}
}
}
这里的mTaskHistory数据类型为ArrayList,记录着所有先前的后台activities。遍历所有activities,找到位于该ProcessRecord的所有ActivityRecord,并结束该Acitivity。
2.9.2 AMS.removeProcessLocked
ActivityManagerService.java
private final void handleAppDiedLocked(ProcessRecord app, boolean restarting, boolean allowRestart) {
int pid = app.pid;
//清除应用中service/receiver/ContentProvider信息
boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1);
if (!kept && !restarting) {
removeLruProcessLocked(app);
if (pid > 0) {
ProcessList.remove(pid);
}
}
if (mProfileProc == app) {
clearProfilerLocked();
}
//清除应用中activity相关信息
boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app);
app.activities.clear();
...
if (!restarting && hasVisibleActivities && !mStackSupervisor.resumeTopActivitiesLocked()) {
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
}
}
2.9.3 ASS.resumeTopActivitiesLocked
ActivityStackSupervisor.java
boolean resumeTopActivitiesLocked() {
return resumeTopActivitiesLocked(null, null, null);
}
boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target, Bundle targetOptions) {
if (targetStack == null) {
targetStack = mFocusedStack;
}
boolean result = false;
if (isFrontStack(targetStack)) {
//【见小节9.3.1】
result = targetStack.resumeTopActivityLocked(target, targetOptions);
}
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
if (stack == targetStack) {
continue; //已经启动
}
if (isFrontStack(stack)) {
stack.resumeTopActivityLocked(null);
}
}
}
return result;
}
此处mFocusedStack是当前正在等待接收input事件或者正在启动下一个activity的ActivityStack。
2.9.3.1 AS.resumeTopActivityLocked
ActivityStack.java
final boolean .resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
...
result = resumeTopActivityInnerLocked(prev, options);//【见小节9.3.2】
return result;
}
2.9.3.2 AS.resumeTopActivityInnerLocked
ActivityStack.java
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
//找到mTaskHistory栈中第一个未处于finishing状态的Activity
final ActivityRecord next = topRunningActivityLocked(null);
if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
mStackSupervisor.allResumedActivitiesComplete()) {
//当top activity已经处于resume,则无需操作;
return false;
}
if (mService.isSleepingOrShuttingDown()
&& mLastPausedActivity == next
&& mStackSupervisor.allPausedActivitiesComplete()) {
//当正处于sleeping状态,top activity处于paused,则无需操作
return false;
}
//正在启动app的activity,确保app不会被设置为stopped
AppGlobals.getPackageManager().setPackageStoppedState(
next.packageName, false, next.userId);
//回调应用onResume方法
next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
mService.isNextTransitionForward(), resumeAnimOptions);
...
}
该方法代码比较长,这里就简单列举几条比较重要的代码。执行完该方法,应用也便完成了activity的resume过程。