设置旧Activity paused状态
上一篇文章中讲到:ActivityManagerNative.getDefault().activityPaused(token)来继续启动TargetActivity的剩余任务。它会跨进程调用到:
com.android.server.am.ActivityStack#activityPaused:
public final void activityPaused(IBinder token) {
final long origId = Binder.clearCallingIdentity();
mMainStack.activityPaused(token, false);
Binder.restoreCallingIdentity(origId);
}
clearCallingIdentity和restoreCallingIdentity作用已经在第二篇文章中讲过。
com.android.server.am.ActivityStack#activityPaused:
final void activityPaused(IBinder token, boolean timeout) {
...
ActivityRecord r = null;
synchronized (mService) {
//获得token对应的ActivityRecord在mHistory中的下标
int index = indexOfTokenLocked(token);
if (index >= 0) {
//获得MainActivity的ActivityRecord
r = mHistory.get(index);
//移除pause超时消息
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
//刚刚pause的就是MainActivity
if (mPausingActivity == r) {
...
//记录状态
r.state = ActivityState.PAUSED;
completePauseLocked();
} else {
...
}
}
}
}
把MainActivity的ActivityRecord找出来,设置一下pause状态,因为进程两侧ActivityRecord和ActivityClientRecord的状态要同步。接下来继续执行:
com.android.server.am.ActivityStack#completePauseLocked:
private final void completePauseLocked() {
ActivityRecord prev = mPausingActivity;
...
if (prev != null) {
//不走这
if (prev.finishing) {
...
} else if (prev.app != null) {//prev.app是ProcessRecord,代表它所属的进程,肯定不是null
//MainActivity的waitingVisible还是false,不走这
if (prev.waitingVisible) {
...
}
//没有设置过,configDestroy是false
if (prev.configDestroy) {
...
} else {//走这里
//MainActivity等待stop
mStoppingActivities.add(prev);
//要等待stop的Activity超过3个了,有一些特殊处理。不走这
if (mStoppingActivities.size() > 3) {
...
} else {
checkReadyForSleepLocked();
}
}
} else {
...
}
//pause完了,状态置null
mPausingActivity = null;
}
//AMS不在休眠状态,走这里
if (!mService.isSleeping()) {
resumeTopActivityLocked(prev);
} else {
//休眠的处理,不走这
...
}
//一堆电池、cpu时间啥的巴拉巴拉的逻辑,场景无关
...
}
再次尝试resume新Activity
先把MainActivity设置为正在stop的状态,再检查AMS是否正在休眠,至于为什么AMS会休眠、休眠了会怎样,这里不关心,只知道正和AMS通讯呢,一定不在休眠状态。继续分析:
com.android.server.am.ActivityStack#resumeTopActivityLocked(com.android.server.am.ActivityRecord):
final boolean resumeTopActivityLocked(ActivityRecord prev) {
return resumeTopActivityLocked(prev, null);
}
是不是有点眼熟?是的,曾经调用过这个函数,TargetActivity尝试resume,但发现需要先pause掉MainActivity的函数就是它。区别是之前传入的参数prev是null,这里传入的是MainActivity。
com.android.server.am.ActivityStack#resumeTopActivityLocked(com.android.server.am.ActivityRecord, android.os.Bundle):
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
// 找到mHistory顶部的Activity,也就是TargetActivity
ActivityRecord next = topRunningActivityLocked(null);
...
//不走这
if (next == null) {
...
}
...
//要resume的已经resuem了,return掉。这里mResumedActivity是null了。
if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
...
return false;
}
//不走这
if ((mService.mSleeping || mService.mShuttingDown)
&& mLastPausedActivity == next
&& (next.state == ActivityState.PAUSED
|| next.state == ActivityState.STOPPED
|| next.state == ActivityState.STOPPING)) {
...
return false;
}
//又把next的相关状态重置了一遍,说实话有点重复
mStoppingActivities.remove(next);
mGoingToSleepActivities.remove(next);
next.sleeping = false;
mWaitingVisibleActivities.remove(next);
...
//上一次调用走这里了,但这一次mResumedActivity是null,不走这
if (mResumedActivity != null) {
...
return true;
}
//最近一次pause的Activity就是MainActivity
final ActivityRecord last = mLastPausedActivity;
//不走这
if (mService.mSleeping && last != null && !last.finishing) {
...
}
//满足条件
if (prev != null && prev != next) {
//waitingVisible代表是否真该等待新的Activity变的可见,nowVisible当前Activity是否可见。MainActivity的waitingVisible还是false,TargetActivity的nowVisible也是false。
if (!prev.waitingVisible && next != null && !next.nowVisible) {
//进入等TargetActivity显示的状态
prev.waitingVisible = true;
mWaitingVisibleActivities.add(prev);
...
}
//一堆和Window有关的逻辑,以为新的Activity要显示了,通知一下WMS(管理Window的服务)
...
//TargetActivity的进程信息还是null,不走这
if (next.app != null && next.app.thread != null) {
} else {
//设置被启动过的标识
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
}
...
//下面继续分析
startSpecificActivityLocked(next, true, true);
}
return true;
}
这个函数之前走过一次,是为了pasue掉MainActivity,这一次是为了真正把TargetActivity resume起来。个人不太理解为什么不把两次调用拆分成两个函数,这样会更清晰。其实这个函数对于当前场景,也没做事情有限,只设置了一些状态。
为resume新Activity准备
下面继续分析:
com.android.server.am.ActivityStack#startSpecificActivityLocked:
private final void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
//根据进程名和uid定位到TargetActivity的进程
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid);
//设置TargetActivity的启动时间
if (r.launchTime == 0) {
r.launchTime = SystemClock.uptimeMillis();
if (mInitialStartTime == 0) {
mInitialStartTime = r.launchTime;
}
} else if (mInitialStartTime == 0) {
mInitialStartTime = SystemClock.uptimeMillis();
}
//进程已经启动了,app和app.thread都不是null。其中Thread是IApplicationThread类型。
if (app != null && app.thread != null) {
try {
//多个包名可以公用一个进程,这里把包名加到进程信息里
app.addPackage(r.info.packageName);
//后面继续分析
realStartActivityLocked(r, app, andResume, checkConfig);
return;
}
...
}
...
}
把TargetActivity所属的进程信息设置好,启动时间设置好,进程信息补充一部分。
通知App进程自己完成Activity启动
继续分析:
com.android.server.am.ActivityStack#realStartActivityLocked:
final boolean realStartActivityLocked(ActivityRecord r,
ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException {
...
r.app = app;
...
int idx = app.activities.indexOf(r);
if (idx < 0) {
app.activities.add(r);
}
...
try {
//走到这里儿,还是null,不异常等什么
if (app.thread == null) {
throw new RemoteException();
}
//准备夸进程参数
List<ResultInfo> results = null;
List<Intent> newIntents = null;
if (andResume) {
results = r.results;
newIntents = r.newIntents;
}
...
//设置一些TargetActivity的状态
r.sleeping = false;
r.forceNewConfig = false;
...
//设置一些进程状态
app.hasShownUi = true;
app.pendingUiClean = true;
...
//通知App进程,要启动Activity了!,正主来了。
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
new Configuration(mService.mConfiguration),
r.compat, r.icicle, results, newIntents, !andResume,
mService.isNextTransitionForward(), profileFile, profileFd,
profileAutoStop);
...
} catch (RemoteException e) {
...
}
r.launchFailed = false;
...
//andResume传入的true
if (andResume) {
//启动完成了,也就是完成了create和resume了。设置好状态。
r.state = ActivityState.RESUMED;
r.stopped = false;
//注意这里,MainActivity启动的时候mResumedActivity是MainActivity。现在启动TargetActivity,mResumedActivity设置成TargetActivity。
mResumedActivity = r;
...
}
...
return true;
}
这个函数里最重要的是通知App去启动Activity,就好比申请了start Activity,AMS通过了,但是真正启动的还是需要App进程自己去完成,毕竟Activity的生命周期方法onCreate、onResume是在App进程里调用的。
准备好了参数,通过app.thread.scheduleLaunchActivity跨进程通知App进程启动Activity。等启动完成后,再设置一些状态AMS的任务就告一段落了。
总结
pause掉旧Activity,准备启动新的Activity,最后却让App进程自行启动Activity。
这是为什么呢?兜兜转一圈不费劲吗?其实这样做是合理的。操作系统的定义:管理计算机硬件与软件资源的计算机程序。如果App进程自己管理Activity,安全性、效率、统一性都会出现问题。而AMS作为系统进程的服务,批准和管理startActivity是再合理不过的了。
由此开始第四次握手。