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)来处理。
mTaskSupervisor是ActivityTaskSupervisor类对象,看下它的startSpecificActivity方法实现:
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {// Is this activity's application already running?final WindowProcessController wpc =mService.getProcessController(r.processName, r.info.applicationInfo.uid);boolean knownToBeDead = false;if (wpc != null && wpc.hasThread()) {try {realStartActivityLocked(r, wpc, andResume, checkConfig);return;} catch (RemoteException e) {Slog.w(TAG, "Exception when starting activity "+ r.intent.getComponent().flattenToShortString(), e);}// If a dead object exception was thrown -- fall through to// restart the application.knownToBeDead = true;}r.notifyUnknownVisibilityLaunchedForKeyguardTransition();final boolean isTop = andResume && r.isTopRunningActivity();mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");}
根据Activity类对象的包名和应用uid,得到进程对应的WindowProcessController类对象wpc。
如果wpc存在,并且和应用进程已经绑定,则直接调用realStartActivityLocked(r, wpc, andResume, checkConfig)启动Activity。
如果不是,则需要调用ActivityTaskManagerService类对象的startProcessAsync方法,先启动进程,之后再启动Activity。
总结
这里将RootWindowContainer类的resumeFocusedTasksTopActivities方法的执行过程说了一遍,它是通过调用目标任务的resumeTopActivityUncheckedLocked方法来实现。它又是主要通过resumeTopActivityInnerLocked方法来实现的。
我们理解的时候,需要考虑清楚它调用的情况。像普通Activity启动的时候,它们会在暂停之前Activity完成后,还会再调用一遍该方法启动待启动Activity。还有待启动的Activity的进程还没启动的情况,需要先启动进程,才启动Activity。