Android 系统进程启动Activity方法说明
前面文章Android Activity的启动器ActivityStarter入口说到Activity的恢复执行是由 mRootWindowContainer.resumeFocusedTasksTopActivities(mTargetRootTask, mStartActivity, mOptions, mTransientLaunch)来实现的,下面就看下它的实现。
RootWindowContainer类的resumeFocusedTasksTopActivities方法
它的代码在RootWindowContainer类中,如下:
boolean resumeFocusedTasksTopActivities(
Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,
boolean deferPause) {
if (!mTaskSupervisor.readyToResume()) {
return false;
}
boolean result = false;
if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()
|| getTopDisplayFocusedRootTask() == targetRootTask)) {
result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,
deferPause);
}
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
final boolean curResult = result;
boolean[] resumedOnDisplay = new boolean[1];
display.forAllRootTasks(rootTask -> {
final ActivityRecord topRunningActivity = rootTask.topRunningActivity();
if (!rootTask.isFocusableAndVisible() || topRunningActivity == null) {
return;
}
if (rootTask == targetRootTask) {
// Simply update the result for targetRootTask because the targetRootTask
// had already resumed in above. We don't want to resume it again,
// especially in some cases, it would cause a second launch failure
// if app process was dead.
resumedOnDisplay[0] |= curResult;
return;
}
if (rootTask.getDisplayArea().isTopRootTask(rootTask)
&& topRunningActivity.isState(RESUMED)) {
// Kick off any lingering app transitions form the MoveTaskToFront
// operation, but only consider the top task and root-task on that
// display.
rootTask.executeAppTransition(targetOptions);
} else {
resumedOnDisplay[0] |= topRunningActivity.makeActiveIfNeeded(target);
}
});
result |= resumedOnDisplay[0];
if (!resumedOnDisplay[0]) {
// In cases when there are no valid activities (e.g. device just booted or launcher
// crashed) it's possible that nothing was resumed on a display. Requesting resume
// of top activity in focused root task explicitly will make sure that at least home
// activity is started and resumed, and no recursion occurs.
final Task focusedRoot = display.getFocusedRootTask();
if (focusedRoot != null) {
result |= focusedRoot.resumeTopActivityUncheckedLocked(target, targetOptions);
} else if (targetRootTask == null) {
result |= resumeHomeActivity(null /* prev */, "no-focusable-task",
display.getDefaultTaskDisplayArea());
}
}
}
return result;
}
参数targetRootTask是启动Activity的根Task,target则是待启动的Activity对象,targetOptions则是待启动的参数,deferPause则是延迟暂停当前启动的Activity。
mTaskSupervisor.readyToResume()如果为true,代表ActivityTaskSupervisor类对象没有设置延缓恢复,延缓恢复是由一个int成员变量控制的,设置延缓就加1,取消延缓就减1。如果设置了,这里是不能恢复Activity启动的。
接着就判断根任务是它所属TaskDisplayArea中的最顶层的根任务或者RootWindowContainer中的最顶层的根任务。Android是支持多屏幕的,RootWindowContainer的下一层就对应屏幕,而每个屏幕上是有一个TaskDisplayArea对象。如果是单屏幕这俩条件应该是一致的。下面就是调用目标Task的resumeTopActivityUncheckedLocked()方法,来执行Activity的启动。
上面执行完毕之后,开始从上到下遍历屏幕,屏幕对应DisplayContent对象。
接着DisplayContent对象通过forAllRootTasks遍历每个根任务对象,
如果根任务不是isFocusableAndVisible()或者根任务的最顶层的没有可以运行的Activity的话,直接返回。任务的isFocusableAndVisible()要求可Focusable并且要求Task可见。
如果现在的根任务和上面执行resumeTopActivityUncheckedLocked()方法的根任务一样,这里就不再执行,不过会将resumedOnDisplay[0]赋值为上面执行的结果。
接下来如果根任务是TaskDisplayArea对象中最顶层的并且任务中的最顶层可以运行的Activity是RESUMED状态,这里会执行该根任务的AppTransition。如果不是,则会调用topRunningActivity.makeActiveIfNeeded(target),使topRunningActivity恢复运行,恢复成功返回true,并将结果存在resumedOnDisplay[0]。
遍历完所有根任务之后,就将结果合并到变量result中。只要有恢复运行成功的Activity,这里result都为true。
如果resumedOnDisplay[0]为false,代表当前屏幕没有执行恢复Activity运行,注释里说了两种情况(刚系统启动或者Launcher崩溃)。这样,会得到当前屏幕的可Focusable并且要求Task可见的根任务,让它执行恢复Activity的工作。如果这个条件不满足,并且参数targetRootTask == null,就去恢复HomeActivity。
最后将结果result返回。
Task的resumeTopActivityUncheckedLocked方法
所以看到真正的执行Activity恢复的,是由任务Task类来执行的,接着看下它的实现:
@GuardedBy("mService")
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options,
boolean deferPause) {
if (mInResumeTopActivity) {
// Don't even start recursing.
return false;
}
boolean someActivityResumed = false;
try {
// Protect against recursion.
mInResumeTopActivity = true;
if (isLeafTask()) {
if (isFocusableAndVisible()) {
someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause);
}
} else {
int idx = mChildren.size() - 1;
while (idx >= 0) {
final Task child = (Task) getChildAt(idx--);
if (!child.isTopActivityFocusable()) {
continue;
}
if (child.getVisibility(null /* starting */) != TASK_VISIBILITY_VISIBLE) {
break;
}
someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options,
deferPause);
// Doing so in order to prevent IndexOOB since hierarchy might changes while
// resuming activities, for example dismissing split-screen while starting
// non-resizeable activity.
if (idx >= mChildren.size()) {
idx = mChildren.size() - 1;
}
}
}
// When resuming the top activity, it may be necessary to pause the top activity (for
// example, returning to the lock screen. We suppress the normal pause logic in
// {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the
// end. We call the {@link ActivityTaskSupervisor#checkReadyForSleepLocked} again here
// to ensure any necessary pause logic occurs. In the case where the Activity will be
// shown regardless of the lock screen, the call to
// {@link ActivityTaskSupervisor#checkReadyForSleepLocked} is skipped.
final ActivityRecord next = topRunningActivity(true /* focusableOnly */);
if (next == null || !next.canTurnScreenOn()) {
checkReadyForSleep();
}
} finally {
mInResumeTopActivity = false;
}
return someActivityResumed;
}
Task的成员变量mInResumeTopActivity代表是在恢复Activity的过程中,如果它为true,代表已经在执行,就直接退出。
接下来就将mInResumeTopActivity设置为true,代表进入恢复Activity的过程。
isLeafTask()代表任务是不是叶子任务,Task里面是可以嵌套Task的,只有Task里面没有任何Task的情况下,它为叶子任务。如果为叶子任务,并且它可以Focusable并且可见的情况下,直接调用resumeTopActivityInnerLocked(prev, options, deferPause)方法来执行。
如果不是叶子任务,需要检查它的孩子任务,孩子任务得是它最上面的Activity是Focusable,如果不是,进入下个循环。孩子任务如果不可见,就直接跳出循环了,因为检查孩子任务是从顶层往下层检查的,上层不可见,下面的任务就更不可见了,所以跳出,不再往下执行。可以看到,孩子任务也是递归调用resumeTopActivityUncheckedLocked方法,继续执行。
接下来,这段代码看注释,是处理恢复Activity之后,回到了锁屏状态的情况,需要让当前恢复的Activity暂停。在锁屏状态下,获取任务的topRunningActivity(true)会返回null。所以在next == null时,调用checkReadyForSleep()去处理,该方法里面就有注释里面提到的ActivityTaskSupervisor#checkReadyForSleepLocked。同时,如果next不为null,并且它可以打开屏幕,就可以跳过检查了。
将成员变量mInResumeTopActivity = false,并返回Activity恢复启动的结果。
Task的resumeTopActivityInnerLocked方法
Task的resumeTopActivityInnerLocked方法,该段代码特别长,分段看下。
resumeTopActivityInnerLocked方法分段一
分段一如下:
@GuardedBy("mService")
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options,
boolean deferPause) {
if (!mAtmService.isBooting() && !mAtmService.isBooted()) {
// Not ready yet!
return false;
}
// Find the next top-most activity to resume in this root task that is not finishing and is
// focusable. If it is not focusable, we will fall into the case below to resume the
// top activity in the next focusable task.
ActivityRecord next = topRunningActivity(true /* focusableOnly */);
final boolean hasRunningActivity = next != null;
// TODO: Maybe this entire condition can get removed?
if (hasRunningActivity && !isAttached()) {
return false;
}
mRootWindowContainer.cancelInitializingActivities();
if (!hasRunningActivity) {
// There are no activities left in the root task, let's look somewhere else.
return resumeNextFocusableActivityWhenRootTaskIsEmpty(prev, options);
}
next.delayedResume = false;
final TaskDisplayArea taskDisplayArea = getDisplayArea();
// If the top activity is the resumed one, nothing to do.
if (mResumedActivity == next && next.isState(RESUMED)
&& taskDisplayArea.allResumedActivitiesComplete()) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
// For devices that are not in fullscreen mode (e.g. freeform windows), it's possible
// we still want to check if the visibility of other windows have changed (e.g. bringing
// a fullscreen window forward to cover another freeform activity.)
if (taskDisplayArea.inMultiWindowMode()) {
taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
false /* preserveWindows */, true /* notifyClients */);
}
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Top activity "
+ "resumed %s", next);
return false;
}
if (!next.canResumeByCompat()) {
return false;
}
// If we are currently pausing an activity, then don't do anything until that is done.
final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();
if (!allPausedComplete) {
ProtoLog.v(WM_DEBUG_STATES,
"resumeTopActivityLocked: Skip resume: some activity pausing.");
return false;
}
// If we are sleeping, and there is no resumed activity, and the top activity is paused,
// well that is the state we want.
if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Going to sleep and"
+ " all paused");
return false;
}
// Make sure that the user who owns this activity is started. If not,
// we will just leave it as is because someone should be bringing
// another user's activities to the top of the stack.
if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) {
Slog.w(TAG, "Skipping resume of top activity " + next
+ ": user " + next.mUserId + " is stopped");
return false;
}
mAtmService.isBooting()是在系统启动中,mAtmService.isBooted()是系统启动了,如果不是在这两个状态,直接返回false。
topRunningActivity(true)得到的是任务的最上面可以运行的Activity。它即为需要恢复的Activity。Android Activity的启动器ActivityStarter入口 该篇文章可知,是会将待启动的Activity放在目标任务的最上面。看一下topRunningActivity(true)的相关实现:
ActivityRecord topRunningActivity(boolean focusableOnly) {
// Split into 2 to avoid object creation due to variable capture.
if (focusableOnly) {
return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
} else {
return getActivity(ActivityRecord::canBeTopRunning);
}
}
getActivity是从上到下,检查任务中的Activity,找到的Activity满足canBeTopRunning()和isFocusable()。isFocusable()就是Activity可以获取焦点,canBeTopRunning()看一下它的实现:
boolean canBeTopRunning() {
return !finishing && okToShowLocked();
}
public boolean okToShowLocked() {
// We cannot show activities when the device is locked and the application is not
// encryption aware.
if (!StorageManager.isUserKeyUnlocked(mUserId)
&& !info.applicationInfo.isEncryptionAware()) {
return false;
}
return (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0
|| (mTaskSupervisor.isCurrentProfileLocked(mUserId)
&& mAtmService.mAmInternal.isUserRunning(mUserId, 0 /* flags */));
}
要求Activity不能是finishing ,并且设备不是被锁、应用不是encryption aware的。所以如果设备被锁定,获取到的topRunningActivity()可能会为null(如果应用没有配置EncryptionAware)。接着okToShowLocked() 要想返回为true,要么配置FLAG_SHOW_FOR_ALL_USERS标识,要么检查该Activity运行在的用户是和当前系统用户一致或者它是Profile用户,并且该用户的状态是运行状态。
!isAttached()代表任务没加到TaskDisplayArea对象中,如果存在待启动的Activity,但是任务没有添加进TaskDisplayArea对象中,返回false。
mRootWindowContainer.cancelInitializingActivities(),它是处理RootWindowContainer类对象里所有不可见任务里的和被遮挡的Activity的starting window,如果它有,将它去除。
如果任务里不存在可以运行的Activity,它会调用resumeNextFocusableActivityWhenRootTaskIsEmpty方法找到下一个可以Focusable,并且可见的Task,调用它的里面的Activity的恢复执行。
接着将待启动的Activity next的delayedResume = false,它代表延迟恢复启动,这里不需要。
mResumedActivity代表任务中目前恢复启动的Activity,如果它和待启动的Activity一样,并且它已经是RESUMED状态了,并且taskDisplayArea中所有的任务的mResumedActivity都为RESUMED状态(如果存在),则调用executeAppTransition(options)执行等待的过渡。如果taskDisplayArea的窗口模式为多窗口模式,则taskDisplayArea.ensureActivitiesVisible方法处理它里面的Activity的可见性。如果属于这种情况,这里直接返回false。
next.canResumeByCompat()代表可以Resume。如果不可以,直接返回false。
mRootWindowContainer.allPausedActivitiesComplete()是检查RootWindowContainer对象中所有Task中的mPausingActivity如果有PAUSED、 STOPPED,、STOPPING,、FINISHING这四种状态之外的其他状态,代表没有全部完成,这个时候,也是直接返回false,等待着Activity暂停完成。
如果待启动的Activity和最后暂停的Activity相同,并且系统正在睡眠,这种情况下,什么也不做,返回false。
如果拥有这个Activity的用户不是启动状态,也是返回false,将该Activity遗放在任务上面。
resumeTopActivityInnerLocked方法分段二
分段二代码:
// The activity may be waiting for stop, but that is no longer
// appropriate for it.
mTaskSupervisor.mStoppingActivities.remove(next);
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
mTaskSupervisor.setLaunchSource(next.info.applicationInfo.uid);
ActivityRecord lastResumed = null;
final Task lastFocusedRootTask = taskDisplayArea.getLastFocusedRootTask();
if (lastFocusedRootTask != null && lastFocusedRootTask != getRootTask()) {
// So, why aren't we using prev here??? See the param comment on the method. prev
// doesn't represent the last resumed activity. However, the last focus stack does if
// it isn't null.
lastResumed = lastFocusedRootTask.getResumedActivity();
}
boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);
if (mResumedActivity != null) {
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Pausing %s", mResumedActivity);
pausing |= startPausingLocked(false /* uiSleeping */, next,
"resumeTopActivityInnerLocked");
}
if (pausing) {
ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivityLocked: Skip resume: need to"
+ " start pausing");
// At this point we want to put the upcoming activity's process
// at the top of the LRU list, since we know we will be needing it
// very soon and it would be a waste to let it get killed if it
// happens to be sitting towards the end.
if (next.attachedToProcess()) {
next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
true /* activityChange */, false /* updateOomAdj */,
false /* addPendingTopUid */);
} else if (!next.isProcessRunning()) {
// Since the start-process is asynchronous, if we already know the process of next
// activity isn't running, we can start the process earlier to save the time to wait
// for the current activity to be paused.
final boolean isTop = this == taskDisplayArea.getFocusedRootTask();
mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,
isTop ? "pre-top-activity" : "pre-activity");
}
if (lastResumed != null) {
lastResumed.setWillCloseOrEnterPip(true);
}
return true;
} else if (mResumedActivity == next && next.isState(RESUMED)
&& taskDisplayArea.allResumedActivitiesComplete()) {
// It is possible for the activity to be resumed when we paused back stacks above if the
// next activity doesn't have to wait for pause to complete.
// So, nothing else to-do except:
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Top activity resumed "
+ "(dontWaitForPause) %s", next);
return true;
}
mTaskSupervisor.mStoppingActivities里面是等待需要执行Stop操作的Activity。这里将next如果在里面,就把它删除。
next.info.applicationInfo.uid是应用的Uid,这里将它设置到mTaskSupervisor中。
taskDisplayArea.getLastFocusedRootTask()得到的是上一次获得焦点的根Task。如果它存在并且和当前任务的根任务不一样,这样,会把上一次获得焦点的根Task的ResumedActivity赋值给变量lastResumed。
deferPause是参数,如果它被设置true,这里就不执行taskDisplayArea.pauseBackTasks(next)。taskDisplayArea.pauseBackTasks(next)它是用来暂停TaskDisplayArea对象中,所有根任务中ResumedActivity不为null,并且任务不可见的Task,执行它的startPausingLocked方法,它用来让ResumedActivity暂停。如果存在执行暂停成功的,taskDisplayArea.pauseBackTasks(next)会返回true。
接着检查该Task的mResumedActivity != null,代表该任务目前存在正在运行的Activity。所以调用startPausingLocked()来暂停它的执行。同样把运行结果并到变量pausing中。前面那个步骤不是调用taskDisplayArea.pauseBackTasks(next)暂停所有根任务的运行Activity了吗,这里怎么还调用呢,这是因为前面的那个暂停的是不可见任务的,而当前任务是可见的。并且方法参数deferPause也可能设置为true,会影响前面的那个执行。
重点看一下下面的两种情况。
1、pausing为true,代表是暂停中,还没有完成暂停操作。
接着看代码,如果next的进程已经存在,调用了next.app.updateProcessInfo方法,看注释是要将待启动的Activity的进程放到LRU list的顶端,以免它在最尾端,被杀掉,还得花时间启动它。
如果next的进程不存在,那就需要调用mAtmService.startProcessAsync方法,先启动进程之后,再启动对应Activity。
如果在暂停Activity过程中,如果lastResumed != null,会调用它的setWillCloseOrEnterPip方法,设置它是在关闭或者进入PIP的过程中。最后,是返回true,代码不再往下执行。
2、pausing为false,不是在暂停Activity过程中。可以分为条件不满足,未执行暂停Activity的过程或者已经执行完Activity暂停的过程。这两种情况pausing都为false。
下面的代码是待启动的Activity和目前已经在运行的Activity一样,并且TaskDisplayArea对象中所有Activity都已经完成启动了。这种情况,是什么也不做了。直接返回true。
resumeTopActivityInnerLocked方法分段三
分段三代码:
// If the most recent activity was noHistory but was only stopped rather
// than stopped+finished because the device went to sleep, we need to make
// sure to finish it as we're making a new activity topmost.
if (shouldSleepActivities()) {
mTaskSupervisor.finishNoHistoryActivitiesIfNeeded(next);
}
if (prev != null && prev != next && next.nowVisible) {
// The next activity is already visible, so hide the previous
// activity's windows right now so we can show the new one ASAP.
// We only do this if the previous is finishing, which should mean
// it is on top of the one being resumed so hiding it quickly
// is good. Otherwise, we want to do the normal route of allowing
// the resumed activity to be shown so we can decide if the
// previous should actually be hidden depending on whether the
// new one is found to be full-screen or not.
if (prev.finishing) {
prev.setVisibility(false);
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Not waiting for visible to hide: " + prev
+ ", nowVisible=" + next.nowVisible);
} else {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Previous already visible but still waiting to hide: " + prev
+ ", nowVisible=" + next.nowVisible);
}
}
// Launching this app's activity, make sure the app is no longer
// considered stopped.
try {
mTaskSupervisor.getActivityMetricsLogger()
.notifyBeforePackageUnstopped(next.packageName);
mAtmService.getPackageManager().setPackageStoppedState(
next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */
} catch (RemoteException e1) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ next.packageName + ": " + e);
}
// We are starting up the next activity, so tell the window manager
// that the previous one will be hidden soon. This way it can know
// to ignore it when computing the desired screen orientation.
boolean anim = true;
final DisplayContent dc = taskDisplayArea.mDisplayContent;
if (prev != null) {
if (prev.finishing) {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare close transition: prev=" + prev);
if (mTaskSupervisor.mNoAnimActivities.contains(prev)) {
anim = false;
dc.prepareAppTransition(TRANSIT_NONE);
} else {
dc.prepareAppTransition(TRANSIT_CLOSE);
}
prev.setVisibility(false);
} else {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: prev=" + prev);
if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
anim = false;
dc.prepareAppTransition(TRANSIT_NONE);
} else {
dc.prepareAppTransition(TRANSIT_OPEN,
next.mLaunchTaskBehind ? TRANSIT_FLAG_OPEN_BEHIND : 0);
}
}
} else {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
anim = false;
dc.prepareAppTransition(TRANSIT_NONE);
} else {
dc.prepareAppTransition(TRANSIT_OPEN);
}
}
if (anim) {
next.applyOptionsAnimation();
} else {
next.abortAndClearOptionsAnimation();
}
mTaskSupervisor.mNoAnimActivities.clear();
代码走到这里,有可能Activity在这里未执行暂停,也有可能已经执行暂停完毕。
像这个Activity在这里未执行暂停的一种情况是,暂停Activity的流程已经执行完,所以在这个resumeTopActivityInnerLocked方法里面就不会再执行startPausingLocked方法了。这样说有点绕,其实普通Activity的启动这个方法resumeTopActivityInnerLocked是需要执行两次的,第一次,就是上面的第一种情况,pausing为true,就返回true,方法不再向下执行了。等待应用程序端告诉system进程,应用端pause完毕,system进程会再调用一次这个resumeTopActivityInnerLocked方法,这个时候,Task对象的mResumedActivity已经为null,所以不会再去执行startPausingLocked方法。
已经执行暂停完毕的情况,是待启动的Activity带FLAG_RESUME_WHILE_PAUSING标识,可能导致暂停的Activity进入PIP模式或者不再等待应用端,直接完成暂停。像这种情况,就直接调用一次resumeTopActivityInnerLocked方法,接着往下执行代码。
这段代码开始,是设备将要睡眠,对于那些noHistory的Activity,如果仅是停止状态,没有finished,在这里就将调用mTaskSupervisor.finishNoHistoryActivitiesIfNeeded(next)处理它们完成finished。
prev != next && next.nowVisible,如果是第二次调用resumeTopActivityInnerLocked方法时,prev为已经暂停的Activity,next 则是待启动的Activity,满足prev != next。这时,如果next已经可见,这里是检查prev 的finishing状态,如果它为true,将prev的可见状态设置为不可见。
接下来就是通知一些状态。让包的Stopped状态设置为false。
再接下来是处理Activity的打开或关闭过渡效果。是否应用动画。如果prev已经是finishing,是采用关闭的过渡动画。其他情形,则采用打开的过渡动画。
最后,会将mTaskSupervisor.mNoAnimActivities里的值清空。
resumeTopActivityInnerLocked方法分段四
分段四代码:
if (next.attachedToProcess()) {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next
+ " stopped=" + next.stopped
+ " visibleRequested=" + next.mVisibleRequested);
// If the previous activity is translucent, force a visibility update of
// the next activity, so that it's added to WM's opening app list, and
// transition animation can be set up properly.
// For example, pressing Home button with a translucent activity in focus.
// Launcher is already visible in this case. If we don't add it to opening
// apps, maybeUpdateTransitToWallpaper() will fail to identify this as a
// TRANSIT_WALLPAPER_OPEN animation, and run some funny animation.
final boolean lastActivityTranslucent = lastFocusedRootTask != null
&& (lastFocusedRootTask.inMultiWindowMode()
|| (lastFocusedRootTask.mLastPausedActivity != null
&& !lastFocusedRootTask.mLastPausedActivity.occludesParent()));
// This activity is now becoming visible.
if (!next.mVisibleRequested || next.stopped || lastActivityTranslucent) {
next.setVisibility(true);
}
// schedule launch ticks to collect information about slow apps.
next.startLaunchTickingLocked();
ActivityRecord lastResumedActivity =
lastFocusedRootTask == null ? null : lastFocusedRootTask.getResumedActivity();
final ActivityState lastState = next.getState();
mAtmService.updateCpuStats();
ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (in existing)", next);
next.setState(RESUMED, "resumeTopActivityInnerLocked");
// Have the window manager re-evaluate the orientation of
// the screen based on the new activity order.
boolean notUpdated = true;
// Activity should also be visible if set mLaunchTaskBehind to true (see
// ActivityRecord#shouldBeVisibleIgnoringKeyguard()).
if (shouldBeVisible(next)) {
// We have special rotation behavior when here is some active activity that
// requests specific orientation or Keyguard is locked. Make sure all activity
// visibilities are set correctly as well as the transition is updated if needed
// to get the correct rotation behavior. Otherwise the following call to update
// the orientation may cause incorrect configurations delivered to client as a
// result of invisible window resize.
// TODO: Remove this once visibilities are set correctly immediately when
// starting an activity.
notUpdated = !mRootWindowContainer.ensureVisibilityAndConfig(next, getDisplayId(),
true /* markFrozenIfConfigChanged */, false /* deferResume */);
}
if (notUpdated) {
// The configuration update wasn't able to keep the existing
// instance of the activity, and instead started a new one.
// We should be all done, but let's just make sure our activity
// is still at the top and schedule another run if something
// weird happened.
ActivityRecord nextNext = topRunningActivity();
ProtoLog.i(WM_DEBUG_STATES, "Activity config changed during resume: "
+ "%s, new next: %s", next, nextNext);
if (nextNext != next) {
// Do over!
mTaskSupervisor.scheduleResumeTopActivities();
}
if (!next.mVisibleRequested || next.stopped) {
next.setVisibility(true);
}
next.completeResumeLocked();
return true;
}
try {
final ClientTransaction transaction =
ClientTransaction.obtain(next.app.getThread(), next.appToken);
// Deliver all pending results.
ArrayList<ResultInfo> a = next.results;
if (a != null) {
final int N = a.size();
if (!next.finishing && N > 0) {
if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
"Delivering results to " + next + ": " + a);
transaction.addCallback(ActivityResultItem.obtain(a));
}
}
if (next.newIntents != null) {
transaction.addCallback(
NewIntentItem.obtain(next.newIntents, true /* resume */));
}
// Well the app will no longer be stopped.
// Clear app token stopped state in window manager if needed.
next.notifyAppResumed(next.stopped);
EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next),
next.getTask().mTaskId, next.shortComponentName);
mAtmService.getAppWarningsLocked().onResumeActivity(next);
next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState);
next.abortAndClearOptionsAnimation();
transaction.setLifecycleStateRequest(
ResumeActivityItem.obtain(next.app.getReportedProcState(),
dc.isNextTransitionForward()));
mAtmService.getLifecycleManager().scheduleTransaction(transaction);
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Resumed %s", next);
} catch (Exception e) {
// Whoops, need to restart this activity!
ProtoLog.v(WM_DEBUG_STATES, "Resume failed; resetting state to %s: "
+ "%s", lastState, next);
next.setState(lastState, "resumeTopActivityInnerLocked");
// lastResumedActivity being non-null implies there is a lastStack present.
if (lastResumedActivity != null) {
lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked");
}
Slog.i(TAG, "Restarting because process died: " + next);
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else if (SHOW_APP_STARTING_PREVIEW && lastFocusedRootTask != null
&& lastFocusedRootTask.isTopRootTaskInDisplayArea()) {
next.showStartingWindow(false /* taskSwitch */);
}
mTaskSupervisor.startSpecificActivity(next, true, false);
return true;
}
// From this point on, if something goes wrong there is no way
// to recover the activity.
try {
next.completeResumeLocked();
} catch (Exception e) {
// If any exception gets thrown, toss away this
// activity and try the next one.
Slog.w(TAG, "Exception thrown during resume of " + next, e);
next.finishIfPossible("resume-exception", true /* oomAdj */);
return true;
}
} else {
// Whoops, need to restart this activity!
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else {
if (SHOW_APP_STARTING_PREVIEW) {
next.showStartingWindow(false /* taskSwich */);
}
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
}
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Restarting %s", next);
mTaskSupervisor.startSpecificActivity(next, true, true);
}
return true;
待启动Activity已经绑定进程了,下面这一长段代码都是这种情况下的处理。
如果next是不可见或者stopped状态,将它变成可见。lastActivityTranslucent代表上一个获取焦点的任务如果处于多窗口或者它的Activity不遮挡,处于透明状态,这种情况下,也将next变成可见。
next.startLaunchTickingLocked()则启动计时,后面可以检测它的启动时间。
接着调用mAtmService.updateCpuStats()更新CPU状态。
下面调用next.setState(RESUMED, “resumeTopActivityInnerLocked”),将Activity对应的状态设置为RESUMED。在这个方法里,它会更新它所属Task的成员mResumedActivity,将它设置为next。
现在next应该是可见的,进入到if (shouldBeVisible(next))中,mRootWindowContainer.ensureVisibilityAndConfig是确保所有的Activity可见性设置正确,过渡被更新得到正确的旋转行为。同时它可能处理Activity因为配置发生变化导致重新启动。它的返回值,就代表是否重启Activity。返回false,代表重启Activity;返回true,代表不需要重启。
接下来,如果notUpdated为true,代表因为配置更新导致重启了一个新的。接着,它重新获得任务上的Activity,如果它和next不一样,调用mTaskSupervisor.scheduleResumeTopActivities()重新调度另一个运行。
如果next还不可见,或者是stopped,就设置它可见。
再调用next的completeResumeLocked()方法,完成它的Resume。最后返回true,不再向下执行。
如果notUpdated为false,代码会继续向下执行。
构建一个ClientTransaction对象,两个成员变量,next.app.getThread()是在系统进程中应用进程的Binder代理,next.appToken是系统进程中的Activity的Binder对象。这俩都是用来实现Binder通信。
next.results是应答结果,这里它不为null,并且next不是finishing,将它封装成ActivityResultItem,添加到ClientTransaction对象的回调接口中。
如果next.newIntents != null,也添加到ClientTransaction对象的回调接口中。
next.notifyAppResumed(next.stopped)通知Activity恢复启动了。
mAtmService.getAppWarningsLocked().onResumeActivity(next)则是检查一些警告。
next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState)设置进程的状态。
next.abortAndClearOptionsAnimation()用来清除参数。
接下来,就是将ClientTransaction对象调用setLifecycleStateRequest,将ResumeActivityItem对象设置到它的成员变量mLifecycleStateRequest中。
mAtmService.getLifecycleManager()是ClientLifecycleManager对象,调用它的scheduleTransaction方法,来执行Activity的生命周期。
最后也是调用next的completeResumeLocked()方法,完成它的Resume。返回true。
上面的这种情况都是next已经存在进程的情况下,若进程还不存在呢,它主要是调用mTaskSupervisor.startSpecificActivity(next, true, true)来重新启动Activity,它的实现里面有如果进程不存在,先调用ActivityTaskManagerService对象的startProcessAsync方法,先启动进程,再恢复Activity。
总结
这里将RootWindowContainer类的resumeFocusedTasksTopActivities方法的执行过程说了一遍,它是通过调用目标任务的resumeTopActivityUncheckedLocked方法来实现。它又是主要通过resumeTopActivityInnerLocked方法来实现的。
我们理解的时候,需要考虑清楚它调用的情况。像普通Activity启动的时候,它们会在暂停之前Activity完成后,还会再调用一遍该方法启动待启动Activity。还有待启动的Activity的进程还没启动的情况,需要先启动进程,才启动Activity。