9.2.1 app.kill[-> ProcessRecord.java]
void kill(String reason, boolean noisy) {
if (!killedByAm) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill");
if (noisy) {
Slog.i(TAG, "Killing " + toShortString() + " (adj " + setAdj + "): " + reason);
}
EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason);
Process.killProcessQuiet(pid); //杀进程
Process.killProcessGroup(info.uid, pid); //杀进程组,包括native进程
if (!persistent) {
killed = true;
killedByAm = true;
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
此处reason为“crash”,关于杀进程的过程见我的另一篇文章 理解杀进程的实现原理. 9.2.2 handleAppDiedLocked[-> ActivityManagerService.java]
private final void handleAppDiedLocked(ProcessRecordapp,
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);
}
}
9.3 ASS.resumeTopActivitiesLocked[-> ActivityStackSupervisor.java]
boolean resumeTopActivitiesLocked() {
return resumeTopActivitiesLocked(null, null, null);
}
boolean resumeTopActivitiesLocked(ActivityStacktargetStack, ActivityRecordtarget,
BundletargetOptions) {
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 ActivityStackstack = stacks.get(stackNdx);
if (stack == targetStack) {
continue; //已经启动
}
if (isFrontStack(stack)) {
stack.resumeTopActivityLocked(null);
}
}
}
return result;
}
此处 mFocusedStack 是当前正在等待接收input事件或者正在启动下一个activity的 ActivityStack 。 9.3.1 AS.resumeTopActivityLocked[-> ActivityStack.java]
final boolean .resumeTopActivityLocked(ActivityRecordprev, Bundleoptions) {
...
result = resumeTopActivityInnerLocked(prev, options);//【见小节9.3.2】
return result;
}
9.3.2 AS.resumeTopActivityInnerLocked[-> ActivityStack.java]
private boolean resumeTopActivityInnerLocked(ActivityRecordprev, Bundleoptions) {
//找到mTaskHistory栈中第一个未处于finishing状态的Activity
final ActivityRecordnext = 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过程。 9.4 finishTopRunningActivityLocked9.4.1 ASS.finishTopRunningActivityLocked[-> ActivityStackSupervisor.java]
void finishTopRunningActivityLocked(ProcessRecordapp, String reason) {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
final int numStacks = stacks.size();
for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
final ActivityStackstack = stacks.get(stackNdx);
//此处reason= "force-crash"【见小节9.4.2】
stack.finishTopRunningActivityLocked(app, reason);
}
}
}
9.4.2 AS.finishTopRunningActivityLocked
final void finishTopRunningActivityLocked(ProcessRecordapp, String reason) {
//找到栈顶第一个不处于finishing状态的activity
ActivityRecord r = topRunningActivityLocked(null);
if (r != null && r.app == app) {
int taskNdx = mTaskHistory.indexOf(r.task);
int activityNdx = r.task.mActivities.indexOf(r);
//【见小节9.4.3】
finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
--activityNdx;
if (activityNdx < 0) {
do {
--taskNdx;
if (taskNdx < 0) {
break;
}
activityNdx = mTaskHistory.get(taskNdx).mActivities.size() - 1;
} while (activityNdx < 0);
}
if (activityNdx >= 0) {
r = mTaskHistory.get(taskNdx).mActivities.get(activityNdx);
if (r.state == ActivityState.RESUMED
|| r.state == ActivityState.PAUSING
|| r.state == ActivityState.PAUSED) {
if (!r.isHomeActivity() || mService.mHomeProcess != r.app) {
//【见小节9.4.3】
finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
}
}
}
}
}
9.4.3 AS.finishActivityLocked
final boolean finishActivityLocked(ActivityRecord r, int resultCode, IntentresultData,
String reason, boolean oomAdj) {
if (r.finishing) {
return false; //正在finishing则返回
}
//设置finish状态的activity不可见
r.makeFinishingLocked();
//暂停key的分发事件
r.pauseKeyDispatchingLocked();
mWindowManager.prepareAppTransition(endTask
? AppTransition.TRANSIT_TASK_CLOSE
: AppTransition.TRANSIT_ACTIVITY_CLOSE, false);
mWindowManager.setAppVisibility(r.appToken, false);
//回调activity的onPause方法
startPausingLocked(false, false, false, false);
...
}
该方法最终会回调到activity的pause方法。 执行到这,我们还回过来看小节 5.crashApplication 中,处理完makeAppCrashingLocked,则会再发送消息SHOW_ERROR_MSG,弹出提示crash的对话框,接下来再看看该过程。 10. UiHandler通过mUiHandler发送message,且消息的msg.waht=SHOW_ERROR_MSG,接下来进入UiHandler来看看handleMessage的处理过程。 [-> ActivityManagerService.java]
final class UiHandler extends Handler {
public void handleMessage(Messagemsg) {
switch (msg.what) {
case SHOW_ERROR_MSG: {
HashMap<String, Object> data = (HashMap<String, Object>) msg.obj;
synchronized (ActivityManagerService.this) {
ProcessRecordproc = (ProcessRecord)data.get("app");
AppErrorResultres = (AppErrorResult) data.get("result");
、
boolean isBackground = (UserHandle.getAppId(proc.uid)
>= Process.FIRST_APPLICATION_UID
&& proc.pid != MY_PID);
...
if (mShowDialogs && !mSleeping && !mShuttingDown) {
//创建提示crash对话框,等待用户选择,5分钟操作等待。
Dialog d = new AppErrorDialog(mContext,
ActivityManagerService.this, res, proc);
d.show();
proc.crashDialog = d;
} else {
//当处于sleep状态,则默认选择退出。
if (res != null) {
res.set(0);
}
}
}
} break;
...
}
}
在发生crash时,默认系统会弹出提示crash的对话框,并阻塞等待用户选择是“退出”或 “退出并报告”,当用户不做任何选择时5min超时后,默认选择“退出”,当手机休眠时也默认选择“退出”。到这里也并没有真正结束,在小节 2.uncaughtException 中在 finnally 语句块还有一个杀进程的动作。 11. killProcessProcess.killProcess(Process.myPid()); System.exit(10); 通过finnally语句块保证能执行并彻底杀掉Crash进程,关于杀进程的过程见我的另一篇文章 理解杀进程的实现原理 .。当Crash进程被杀后,并没有完全结束,还有Binder死亡通知的流程还没有处理完成。 12. 小结当进程抛出未捕获异常时,则系统会处理该异常并进入crash处理流程。
其中最为核心的工作图中红色部分 AMS.handleAppCrashLocked 的主要功能:
另外, AMS.handleAppCrashLocked ,该方法内部主要调用链,如下: AMS.handleAppCrashLocked ASS.handleAppCrashLocked AS.handleAppCrashLocked AS.finishCurrentActivityLocked AMS.removeProcessLocked ProcessRecord.kill AMS.handleAppDiedLocked ASS.handleAppDiedLocked AMS.cleanUpApplicationRecordLocked AS.handleAppDiedLocked AS.removeHistoryRecordsForAppLocked ASS.resumeTopActivitiesLocked AS.resumeTopActivityLocked AS.resumeTopActivityInnerLocked ASS.finishTopRunningActivityLocked AS.finishTopRunningActivityLocked AS.finishActivityLocked 三、Binder死亡通知进程被杀,如果还记得Binder的死亡回调机制,在应用进程创建的过程中有一个 attachApplicationLocked 方法的过程中便会创建死亡通知。 [-> ActivityManagerService.java]
private final boolean attachApplicationLocked(IApplicationThreadthread,
int pid) {
try {
//创建binder死亡通知
AppDeathRecipientadr = new AppDeathRecipient(
app, pid, thread);
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
} catch (RemoteException e) {
app.resetPackageList(mProcessStats);
startProcessLocked(app, "link fail", processName);
return false;
}
...
}
当binder服务端挂了之后,便会通过binder的DeathRecipient来通知AMS进行相应的清理收尾工作。前面已经降到crash的进程会被kill掉,那么当该进程会杀,则会回调到binderDied()方法。 1. binderDied[-> ActivityManagerService.java]
private final class AppDeathRecipientimplements IBinder.DeathRecipient {
public void binderDied() {
synchronized(ActivityManagerService.this) {
appDiedLocked(mApp, mPid, mAppThread, true);//【见小节2】
}
}
}
2. appDiedLocked
final void appDiedLocked(ProcessRecordapp, int pid, IApplicationThreadthread,
boolean fromBinderDied) {
...
if (!app.killed) {
if (!fromBinderDied) {
Process.killProcessQuiet(pid);
}
killProcessGroup(app.info.uid, pid);
app.killed = true;
}
// Clean up already done if the process has been re-started.
if (app.pid == pid && app.thread != null &&
app.thread.asBinder() == thread.asBinder()) {
boolean doLowMem = app.instrumentationClass == null;
boolean doOomAdj = doLowMem;
if (!app.killedByAm) {
mAllowLowerMemLevel = true;
} else {
mAllowLowerMemLevel = false;
doLowMem = false;
}
//【见小节3】
handleAppDiedLocked(app, false, true);
if (doOomAdj) {
updateOomAdjLocked();
}
if (doLowMem) {
doLowMemReportIfNeededLocked(app);
}
}
...
}
3 handleAppDiedLocked[-> ActivityManagerService.java]
private final void handleAppDiedLocked(ProcessRecordapp,
boolean restarting, boolean allowRestart) {
int pid = app.pid;
//清理应用程序service, BroadcastReceiver, ContentProvider相关信息【见小节4】
boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1);
if (!kept && !restarting) {
removeLruProcessLocked(app);
if (pid > 0) {
ProcessList.remove(pid);
}
}
//清理activity相关信息
boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app);
app.activities.clear();
...
//恢复栈顶第一个非finish的activity
if (!restarting && hasVisibleActivities && !mStackSupervisor.resumeTopActivitiesLocked()) {
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
}
}
4 cleanUpApplicationRecordLocked该方法清理应用程序service, BroadcastReceiver, ContentProvider,process相关信息,为了便于说明将该方法划分为4个部分讲解 4.1 清理service参数restarting = false, allowRestart =true, index =-1
private final boolean cleanUpApplicationRecordLocked(ProcessRecordapp,
boolean restarting, boolean allowRestart, int index) {
...
mProcessesToGc.remove(app);
mPendingPssProcesses.remove(app);
//如果存在,则清除crash/anr/wait对话框
if (app.crashDialog != null && !app.forceCrashReport) {
app.crashDialog.dismiss();
app.crashDialog = null;
}
if (app.anrDialog != null) {
app.anrDialog.dismiss();
app.anrDialog = null;
}
if (app.waitDialog != null) {
app.waitDialog.dismiss();
app.waitDialog = null;
}
app.crashing = false;
app.notResponding = false;
app.resetPackageList(mProcessStats);
app.unlinkDeathRecipient(); //解除app的死亡通告
app.makeInactive(mProcessStats);
app.waitingToKill = null;
app.forcingToForeground = null;
//将app移除前台进程
updateProcessForegroundLocked(app, false, false);
app.foregroundActivities = false;
app.hasShownUi = false;
app.treatLikeActivity = false;
app.hasAboveClient = false;
app.hasClientActivities = false;
//清理service信息,这个过程也比较复杂,后续再展开
mServices.killServicesLocked(app, allowRestart);
boolean restart = false;
}
4.2 清理ContentProvider
private final boolean cleanUpApplicationRecordLocked(...) {
...
for (int i = app.pubProviders.size() - 1; i >= 0; i--) {
//获取该进程已发表的ContentProvider
ContentProviderRecordcpr = app.pubProviders.valueAt(i);
final boolean always = app.bad || !allowRestart;
//ContentProvider服务端被杀,则client端进程也会被杀
boolean inLaunching = removeDyingProviderLocked(app, cpr, always);
if ((inLaunching || always) && cpr.hasConnectionOrHandle()) {
restart = true; //需要重启
}
cpr.provider = null;
cpr.proc = null;
}
app.pubProviders.clear();
//处理正在启动并且是有client端正在等待的ContentProvider
if (cleanupAppInLaunchingProvidersLocked(app, false)) {
restart = true;
}
//取消已连接的ContentProvider的注册
if (!app.conProviders.isEmpty()) {
for (int i = app.conProviders.size() - 1; i >= 0; i--) {
ContentProviderConnectionconn = app.conProviders.get(i);
conn.provider.connections.remove(conn);
stopAssociationLocked(app.uid, app.processName, conn.provider.uid,
conn.provider.name);
}
app.conProviders.clear();
}
4.3 清理BroadcastReceiver
private final boolean cleanUpApplicationRecordLocked(...) {
...
skipCurrentReceiverLocked(app);
// 取消注册的广播接收者
for (int i = app.receivers.size() - 1; i >= 0; i--) {
removeReceiverLocked(app.receivers.valueAt(i));
}
app.receivers.clear();
}
4.4 清理Process
private final boolean cleanUpApplicationRecordLocked(...) {
...
//当app正在备份时的处理方式
if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
...
IBackupManagerbm = IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE));
bm.agentDisconnected(app.info.packageName);
}
for (int i = mPendingProcessChanges.size() - 1; i >= 0; i--) {
ProcessChangeItemitem = mPendingProcessChanges.get(i);
if (item.pid == app.pid) {
mPendingProcessChanges.remove(i);
mAvailProcessChanges.add(item);
}
}
mUiHandler.obtainMessage(DISPATCH_PROCESS_DIED, app.pid, app.info.uid, null).sendToTarget();
if (!app.persistent || app.isolated) {
removeProcessNameLocked(app.processName, app.uid);
if (mHeavyWeightProcess == app) {
mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
mHeavyWeightProcess.userId, 0));
mHeavyWeightProcess = null;
}
} else if (!app.removed) {
//对于persistent应用,则需要重启
if (mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
restart = true;
}
}
//mProcessesOnHold:记录着试图在系统ready之前就启动的进程。
//在那时并不启动这些进程,先记录下来,等系统启动完成则启动这些进程。
mProcessesOnHold.remove(app);
if (app == mHomeProcess) {
mHomeProcess = null;
}
if (app == mPreviousProcess) {
mPreviousProcess = null;
}
if (restart && !app.isolated) {
//仍有组件需要运行在该进程中,因此重启该进程
if (index < 0) {
ProcessList.remove(app.pid);
}
addProcessNameLocked(app);
startProcessLocked(app, "restart", app.processName);
return true;
} else if (app.pid > 0 && app.pid != MY_PID) {
//移除该进程相关信息
boolean removed;
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.remove(app.pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
app.setPid(0);
}
return false;
}
对于需要重启进程的情形有:
5. 小结当crash进程执行kill操作后,进程被杀。此时需要掌握binder 死亡通知原理,由于Crash进程中拥有一个Binder服务端 ApplicationThread ,而应用进程在创建过程调用attachApplicationLocked(),从而attach到system_server进程,在system_server进程内有一个 ApplicationThreadProxy ,这是相对应的Binder客户端。当Binder服务端 ApplicationThread 所在进程(即Crash进程)挂掉后,则Binder客户端能收到相应的死亡通知,从而进入binderDied流程。更多关于bInder原理,这里就不细说,博客中有关于binder系列的专题。
四、 总结本文主要以源码的视角,详细介绍了到应用crash后系统的处理流程:
这基本就是整个应用Crash后系统的执行过程。 (责任编辑:最模板) |



ecshop团购风格模板
人气:1114
ecshop服装批发模板
人气:1389
Neoshop经济型外贸综合类
人气:360
织梦dedecms绿色节能科技公
人气:1349
ecshop易趣英文外贸模板
人气:1288
magento外贸家居商城Toront商
人气:286