前言
前面说到了权限检查,查找复用task的flag,launch mode条件,寻找到复用task的top Activity(getReusableIntentActivity),从本章开始,从这之后开始进行整理,这也是启动Activity过程中最为关键的部分
复用流程
复用流程-step 1:
if (reusedActivity != null) {
// When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
// still needs to be a lock task mode violation since the task gets cleared out and
// the device would otherwise leave the locked task.
if (mService.getLockTaskController().isLockTaskModeViolation(reusedActivity.getTask(),
(mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
// True if we are clearing top and resetting of a standard (default) launch mode
// ({@code LAUNCH_MULTIPLE}) activity. The existing activity will be finished.
final boolean clearTopAndResetStandardLaunchMode =
(mLaunchFlags & (FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED))
== (FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
&& mLaunchMode == LAUNCH_MULTIPLE;
// If mStartActivity does not have a task associated with it, associate it with the
// reused activity's task. Do not do so if we're clearing top and resetting for a
// standard launchMode activity.
if (mStartActivity.getTask() == null && !clearTopAndResetStandardLaunchMode) {
mStartActivity.setTask(reusedActivity.getTask());
//因为复用了,所以 mStartActivity设置task为reusedActivity.getTask()
}
if (reusedActivity.getTask().intent == null) {
// This task was started because of movement of the activity based on affinity...
// Now that we are actually launching it, we can assign the base intent.
reusedActivity.getTask().setIntent(mStartActivity);
}
// This code path leads to delivering a new intent, we want to make sure we schedule it
// as the first operation, in case the activity will be resumed as a result of later
// operations.
if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| isDocumentLaunchesIntoExisting(mLaunchFlags)
|| isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
final TaskRecord task = reusedActivity.getTask();
// In this situation we want to remove all activities from the task up to the one
// being started. In most cases this means we are resetting the task to its initial
// state.
final ActivityRecord top = task.performClearTaskForReuseLocked(mStartActivity,
mLaunchFlags);
//能否在复用task中找到复用的Activity,如果能找到,为之上的ActivityRecord调用finishActivityLocked;
//如果找不到,直接返回null就行
// The above code can remove {@code reusedActivity} from the task, leading to the
// the {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The
// task reference is needed in the call below to
// {@link setTargetStackAndMoveToFrontIfNeeded}.
if (reusedActivity.getTask() == null) {
reusedActivity.setTask(task);
}
if (top != null) {
if (top.frontOfTask) { //如果该Activity为task的root Activity
// Activity aliases may mean we use different intents for the top activity,
// so make sure the task now has the identity of the new intent.
top.getTask().setIntent(mStartActivity);
}
deliverNewIntent(top); //从AMS端调用客户端onNewintent
}
}
复用流程-step 2:
mSupervisor.sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, reusedActivity);
//第二部分,是否要移动复用的ActivityStack和task
reusedActivity = setTargetStackAndMoveToFrontIfNeeded(reusedActivity);
setTargetStackAndMoveToFrontIfNeeded的逻辑
/**
* Figure out which task and activity to bring to front when we have found an existing matching
* activity record in history. May also clear the task if needed.
* @param intentActivity Existing matching activity.
* @return {@link ActivityRecord} brought to front.
*/
private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity) {
mTargetStack = intentActivity.getStack(); //复用task所在的stack
mTargetStack.mLastPausedActivity = null;
// If the target task is not in the front, then we need to bring it to the front...
// except... well, with SINGLE_TASK_LAUNCH it's not entirely clear. We'd like to have
// the same behavior as if a new instance was being started, which means not bringing it
// to the front if the caller is not itself in the front.
final ActivityStack focusStack = mSupervisor.getFocusedStack();
ActivityRecord curTop = (focusStack == null)
? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
final TaskRecord topTask = curTop != null ? curTop.getTask() : null;
if (topTask != null
&& (topTask != intentActivity.getTask() || topTask != focusStack.topTask())
&& !mAvoidMoveToFront) { //当前topTask 和复用Task不一样
mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
if (mSourceRecord == null || (mSourceStack.getTopActivity() != null &&
mSourceStack.getTopActivity().getTask() == mSourceRecord.getTask())) {
//这里的条件,对P来说很容易满足,因为P会创建多个stack;但是对O呢,感觉就不一定了
//如https://www.jianshu.com/p/1a58b10387fc中的这种情况,我们重点还是放在Android P上
// We really do want to push this one into the user's face, right now.
if (mLaunchTaskBehind && mSourceRecord != null) {
intentActivity.setTaskToAffiliateWith(mSourceRecord.getTask());
}
// If the launch flags carry both NEW_TASK and CLEAR_TASK, the task's activities
// will be cleared soon by ActivityStarter in setTaskFromIntentActivity().
// So no point resuming any of the activities here, it just wastes one extra
// resuming, plus enter AND exit transitions.
// Here we only want to bring the target stack forward. Transition will be applied
// to the new activity that's started after the old ones are gone.
final boolean willClearTask =
(mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
if (!willClearTask) {
final ActivityStack launchStack = getLaunchStack(
mStartActivity, mLaunchFlags, mStartActivity.getTask(), mOptions); //返回startActivity要launch的ActivityStack
final TaskRecord intentTask = intentActivity.getTask();
if (launchStack == null || launchStack == mTargetStack) {
// We only want to move to the front, if we aren't going to launch on a
// different stack. If we launch on a different stack, we will put the
// task on top there.
mTargetStack.moveTaskToFrontLocked(intentTask, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, "bringingFoundTaskToFront"); //如果没准备在其他AtivityStack中启动,那么直接调用moveTaskToFrontLocked即可,将task及对应的ActivityStack放到前台
//同时moveTaskToFrontLocked中包含mStackSupervisor.resumeFocusedStackTopActivityLocked(); 会走一轮pasue,resume的相关流程;
//这也是注释的意思 If the launch flags carry both NEW_TASK and CLEAR_TASK, the task's activities will be cleared soon by ActivityStarter in setTaskFromIntentActivity(). So no point resuming any of the activities here
mMovedToFront = true; //相应的复用task确实走到前台来了
} else if (launchStack.inSplitScreenWindowingMode()) {
if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
// If we want to launch adjacent and mTargetStack is not the computed
// launch stack - move task to top of computed stack.
intentTask.reparent(launchStack, ON_TOP,
REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
"launchToSide");
} else {
// TODO: This should be reevaluated in MW v2.
// We choose to move task to front instead of launching it adjacent
// when specific stack was requested explicitly and it appeared to be
// adjacent stack, but FLAG_ACTIVITY_LAUNCH_ADJACENT was not set.
mTargetStack.moveTaskToFrontLocked(intentTask,
mNoAnimation, mOptions, mStartActivity.appTimeTracker,
"bringToFrontInsteadOfAdjacentLaunch");
//move task,task所在stack到top
}
mMovedToFront = launchStack != launchStack.getDisplay()
.getTopStackInWindowingMode(launchStack.getWindowingMode());
} else if (launchStack.mDisplayId != mTargetStack.mDisplayId) {
// Target and computed stacks are on different displays and we've
// found a matching task - move the existing instance to that display and
// move it to front.
intentActivity.getTask().reparent(launchStack, ON_TOP,
REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
"reparentToDisplay");
mMovedToFront = true;
} else if (launchStack.isActivityTypeHome()
&& !mTargetStack.isActivityTypeHome()) {
// It is possible for the home activity to be in another stack initially.
// For example, the activity may have been initially started with an intent
// which placed it in the fullscreen stack. To ensure the proper handling of
// the activity based on home stack assumptions, we must move it over.
intentActivity.getTask().reparent(launchStack, ON_TOP,
REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
"reparentingHome");
mMovedToFront = true;
mOptions = null;
// We are moving a task to the front, use starting window to hide initial drawn
// delay.
intentActivity.showStartingWindow(null /* prev */, false /* newTask */,
true /* taskSwitch */);
}
}
}
// Need to update mTargetStack because if task was moved out of it, the original stack may
// be destroyed.
mTargetStack = intentActivity.getStack();
if (!mMovedToFront && mDoResume) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + mTargetStack
+ " from " + intentActivity);
mTargetStack.moveToFront("intentActivityFound"); //感觉对于一般情况,复用task就是topTask,且对于Android P一般一个task对应一个stack,那么走到这里就是说task,ActivityStack都在前面,一般这里不会打event log,如果遇到了特殊情况,记得后面看一下是什么情况,补充记录
}
mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(),
WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, mTargetStack);
// If the caller has requested that the target task be reset, then do so.
if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
return mTargetStack.resetTaskIfNeededLocked(intentActivity, mStartActivity);
}
return intentActivity;
}
ActivityStack#moveTaskToFrontLocked
将task及对应的ActivityStack放到前台;并对应task的top Activity走一遍pause,resume的流程
4651 final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, ActivityOptions options,
4652 AppTimeTracker timeTracker, String reason) {
4653 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
4654
4655 final ActivityStack topStack = getDisplay().getTopStack();
4656 final ActivityRecord topActivity = topStack != null ? topStack.getTopActivity() : null;
4657 final int numTasks = mTaskHistory.size();
4658 final int index = mTaskHistory.indexOf(tr);
4659 if (numTasks == 0 || index < 0) {
4660 // nothing to do!
4661 if (noAnimation) {
4662 ActivityOptions.abort(options);
4663 } else {
4664 updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
4665 }
4666 return;
4667 }
4668
4669 if (timeTracker != null) {
4670 // The caller wants a time tracker associated with this task.
4671 for (int i = tr.mActivities.size() - 1; i >= 0; i--) {
4672 tr.mActivities.get(i).appTimeTracker = timeTracker;
4673 }
4674 }
4675
4676 try {
4677 // Defer updating the IME target since the new IME target will try to get computed
4678 // before updating all closing and opening apps, which can cause the ime target to
4679 // get calculated incorrectly.
4680 getDisplay().deferUpdateImeTarget();
4681
4682 // Shift all activities with this task up to the top
4683 // of the stack, keeping them in the same internal order.
4684 insertTaskAtTop(tr, null); //对应event log wm_task_moved: [11,1,2]
4685
4686 // Don't refocus if invisible to current user
4687 final ActivityRecord top = tr.getTopActivity();
4688 if (top == null || !top.okToShowLocked()) {
4689 if (top != null) {
4690 mStackSupervisor.mRecentTasks.add(top.getTask());
4691 }
4692 ActivityOptions.abort(options);
4693 return;
4694 }
4695
4696 // Set focus to the top running activity of this stack.
4697 final ActivityRecord r = topRunningActivityLocked();
4698 mStackSupervisor.moveFocusableActivityStackToFrontLocked(r, reason);
//moveToFront中
// am_focused_stack: [0,1,0,bringingFoundTaskToFront] //mStackSupervisor.setFocusStackUnchecked(reason, this); 这句执行完后打出来(如果真的改了focus Stack的情况)
// wm_task_moved: [11,1,2]
4699
4700 if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
4701 if (noAnimation) {
4702 mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
4703 if (r != null) {
4704 mStackSupervisor.mNoAnimActivities.add(r);
4705 }
4706 ActivityOptions.abort(options);
4707 } else {
4708 updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
4709 }
4710 // If a new task is moved to the front, then mark the existing top activity as
4711 // supporting
4712
4713 // picture-in-picture while paused only if the task would not be considered an oerlay
4714 // on top
4715 // of the current activity (eg. not fullscreen, or the assistant)
4716 if (canEnterPipOnTaskSwitch(topActivity, tr, null /* toFrontActivity */,
4717 options)) {
4718 topActivity.supportsEnterPipOnTaskSwitch = true;
4719 }
4720
4721 mStackSupervisor.resumeFocusedStackTopActivityLocked(); //先将被放到后面的stack中的Activity pause
//对应am_pause_activity: [4117,215638647,com.miui.home/.launcher.Launcher]
4722 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);
//对应 am_task_to_front: [0,11]
4723
4724 mService.mTaskChangeNotificationController.notifyTaskMovedToFront(tr.taskId);
4725 } finally {
4726 getDisplay().continueUpdateImeTarget();
4727 }
4728 }
moveFocusableActivityStackToFrontLocked的逻辑
3411 /** Move activity with its stack to front and make the stack focused. */
3412 boolean moveFocusableActivityStackToFrontLocked(ActivityRecord r, String reason) {
3413 if (r == null || !r.isFocusable()) {
3414 if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
3415 "moveActivityStackToFront: unfocusable r=" + r);
3416 return false;
3417 }
3418
3419 final TaskRecord task = r.getTask();
3420 final ActivityStack stack = r.getStack();
3421 if (stack == null) {
3422 Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: r="
3423 + r + " task=" + task);
3424 return false;
3425 }
3426
3427 if (stack == mFocusedStack && stack.topRunningActivityLocked() == r) {
3428 if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
3429 "moveActivityStackToFront: already on top, r=" + r);
3430 return false;
3431 }
3432
3433 if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
3434 "moveActivityStackToFront: r=" + r);
3435
3436 stack.moveToFront(reason, task); //其实还是调用stack的moveToFront
3437 return true;
3438 }
ActivityStack#moveToFront
1022 /**
1023 * @param reason The reason for moving the stack to the front.
1024 * @param task If non-null, the task will be moved to the top of the stack.
1025 * */
1026 void moveToFront(String reason, TaskRecord task) {
1027 if (!isAttached()) {
1028 return;
1029 }
1030
1031 final ActivityDisplay display = getDisplay();
1032
1033 if (inSplitScreenSecondaryWindowingMode()) {
1034 // If the stack is in split-screen seconardy mode, we need to make sure we move the
1035 // primary split-screen stack forward in the case it is currently behind a fullscreen
1036 // stack so both halves of the split-screen appear on-top and the fullscreen stack isn't
1037 // cutting between them.
1038 // TODO(b/70677280): This is a workaround until we can fix as part of b/70677280.
1039 final ActivityStack topFullScreenStack =
1040 display.getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
1041 if (topFullScreenStack != null) {
1042 final ActivityStack primarySplitScreenStack = display.getSplitScreenPrimaryStack();
1043 if (display.getIndexOf(topFullScreenStack)
1044 > display.getIndexOf(primarySplitScreenStack)) {
1045 primarySplitScreenStack.moveToFront(reason + " splitScreenToTop");
1046 }
1047 }
1048 }
1049
1050 if (!isActivityTypeHome() && returnsToHomeStack()) {
1051 // Make sure the home stack is behind this stack since that is where we should return to
1052 // when this stack is no longer visible.
1053 mStackSupervisor.moveHomeStackToFront(reason + " returnToHome");
1054 }
1055
1056 display.positionChildAtTop(this);
1057 mStackSupervisor.setFocusStackUnchecked(reason, this); // am_focused_stack: [0,1,0,bringingFoundTaskToFront]
1058 if (task != null) {
1059 insertTaskAtTop(task, null); // wm_task_moved: [11,1,2]
1060 return;
1061 }
1062 }
因此moveTaskToFrontLocked是针对task的移动,但是task移动可能就会造成stack的移动(moveToFront),并且走resume的流程,保证正确的task,stack在前台;
而moveToFront是针对stack的移动(如果真的移动了打出event log),可能有task的移动(参数task不为null),保证正确的stack在前台;
可见,这两者是个包含关系
TaskRecord#reparent
主要就是将task从原来的stack前移到现在的stack,包括stack中removeTask,addTask;还有一些WMS的操作
603 /**
604 * Reparents the task into a preferred stack, creating it if necessary.
605 *
606 * @param preferredStack the target stack to move this task
607 * @param position the position to place this task in the new stack
608 * @param animate whether or not we should wait for the new window created as a part of the
609 * reparenting to be drawn and animated in
610 * @param moveStackMode whether or not to move the stack to the front always, only if it was
611 * previously focused & in front, or never
612 * @param deferResume whether or not to update the visibility of other tasks and stacks that may
613 * have changed as a result of this reparenting
614 * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode
615 * change. Callers may set this to false if they are explicitly scheduling PiP mode
616 * changes themselves, like during the PiP animation
617 * @param reason the caller of this reparenting
618 * @return whether the task was reparented
619 */
620 // TODO: Inspect all call sites and change to just changing windowing mode of the stack vs.
621 // re-parenting the task. Can only be done when we are no longer using static stack Ids.
//注释还是比较清楚的,里面有一些WMS相关的代码后续再研究
622 boolean reparent(ActivityStack preferredStack, int position,
623 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
624 boolean schedulePictureInPictureModeChange, String reason) {
625 final ActivityStackSupervisor supervisor = mService.mStackSupervisor;
626 final WindowManagerService windowManager = mService.mWindowManager;
627 final ActivityStack sourceStack = getStack();
628 final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack,
629 position == MAX_VALUE);
/* Returns the reparent target stack, creating the stack if necessary. This call also enforces
* the various checks on tasks that are going to be reparented from one stack to another. */
630 if (toStack == sourceStack) {
631 return false;
632 }
633 if (!canBeLaunchedOnDisplay(toStack.mDisplayId)) {
634 return false;
635 }
636
637 final int toStackWindowingMode = toStack.getWindowingMode();
638 final ActivityRecord topActivity = getTopActivity();
639
640 final boolean mightReplaceWindow = topActivity != null
641 && replaceWindowsOnTaskMove(getWindowingMode(), toStackWindowingMode);
642 if (mightReplaceWindow) {
643 // We are about to relaunch the activity because its configuration changed due to
644 // being maximized, i.e. size change. The activity will first remove the old window
645 // and then add a new one. This call will tell window manager about this, so it can
646 // preserve the old window until the new one is drawn. This prevents having a gap
647 // between the removal and addition, in which no window is visible. We also want the
648 // entrance of the new window to be properly animated.
649 // Note here we always set the replacing window first, as the flags might be needed
650 // during the relaunch. If we end up not doing any relaunch, we clear the flags later.
651 windowManager.setWillReplaceWindow(topActivity.appToken, animate);
652 }
653
654 windowManager.deferSurfaceLayout();
655 boolean kept = true;
656 try {
657 final ActivityRecord r = topRunningActivityLocked();
658 final boolean wasFocused = r != null && supervisor.isFocusedStack(sourceStack)
659 && (topRunningActivityLocked() == r);
660 final boolean wasResumed = r != null && sourceStack.getResumedActivity() == r;
661 final boolean wasPaused = r != null && sourceStack.mPausingActivity == r;
662
663 // In some cases the focused stack isn't the front stack. E.g. pinned stack.
664 // Whenever we are moving the top activity from the front stack we want to make sure to
665 // move the stack to the front.
666 final boolean wasFront = r != null && sourceStack.isTopStackOnDisplay()
667 && (sourceStack.topRunningActivityLocked() == r);
668
669 // Adjust the position for the new parent stack as needed.
670 position = toStack.getAdjustedPositionForTask(this, position, null /* starting */);
671
672 // Must reparent first in window manager to avoid a situation where AM can delete the
673 // we are coming from in WM before we reparent because it became empty.
674 mWindowContainerController.reparent(toStack.getWindowContainerController(), position,
675 moveStackMode == REPARENT_MOVE_STACK_TO_FRONT);
676
677 final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
678 || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront));
679 // Move the task
680 sourceStack.removeTask(this, reason, moveStackToFront
681 ? REMOVE_TASK_MODE_MOVING_TO_TOP : REMOVE_TASK_MODE_MOVING);
682 toStack.addTask(this, position, false /* schedulePictureInPictureModeChange */, reason);
683
684 if (schedulePictureInPictureModeChange) {
685 // Notify of picture-in-picture mode changes
686 supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceStack);
687 }
688
689 // TODO: Ensure that this is actually necessary here
690 // Notify the voice session if required
691 if (voiceSession != null) {
692 try {
693 voiceSession.taskStarted(intent, taskId);
694 } catch (RemoteException e) {
695 }
696 }
697
698 // If the task had focus before (or we're requested to move focus), move focus to the
699 // new stack by moving the stack to the front.
700 if (r != null) {
701 toStack.moveToFrontAndResumeStateIfNeeded(r, moveStackToFront, wasResumed,
702 wasPaused, reason);
703 }
704 if (!animate) {
705 mService.mStackSupervisor.mNoAnimActivities.add(topActivity);
706 }
707
708 // We might trigger a configuration change. Save the current task bounds for freezing.
709 // TODO: Should this call be moved inside the resize method in WM?
710 toStack.prepareFreezingTaskBounds();
711
712 // Make sure the task has the appropriate bounds/size for the stack it is in.
713 final boolean toStackSplitScreenPrimary =
714 toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
715 final Rect configBounds = getOverrideBounds();
716 if ((toStackWindowingMode == WINDOWING_MODE_FULLSCREEN
717 || toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)
718 && !Objects.equals(configBounds, toStack.getOverrideBounds())) {
719 kept = resize(toStack.getOverrideBounds(), RESIZE_MODE_SYSTEM, !mightReplaceWindow,
720 deferResume);
721 } else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) {
722 Rect bounds = getLaunchBounds();
723 if (bounds == null) {
724 mService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
725 bounds = configBounds;
726 }
727 kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
728 } else if (toStackSplitScreenPrimary || toStackWindowingMode == WINDOWING_MODE_PINNED) {
729 if (toStackSplitScreenPrimary && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
730 // Move recents to front so it is not behind home stack when going into docked
731 // mode
732 mService.mStackSupervisor.moveRecentsStackToFront(reason);
733 }
734 kept = resize(toStack.getOverrideBounds(), RESIZE_MODE_SYSTEM, !mightReplaceWindow,
735 deferResume);
736 }
737 } finally {
738 windowManager.continueSurfaceLayout();
739 }
740
741 if (mightReplaceWindow) {
742 // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
743 // window), we need to clear the replace window settings. Otherwise, we schedule a
744 // timeout to remove the old window if the replacing window is not coming in time.
745 windowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept);
746 }
747
748 if (!deferResume) {
749 // The task might have already been running and its visibility needs to be synchronized
750 // with the visibility of the stack / windows.
751 supervisor.ensureActivitiesVisibleLocked(null, 0, !mightReplaceWindow);
752 supervisor.resumeFocusedStackTopActivityLocked();
753 }
754
755 // TODO: Handle incorrect request to move before the actual move, not after.
756 supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(),
757 DEFAULT_DISPLAY, toStack);
758
759 return (preferredStack == toStack);
760 }
ActivityStack#getReparentTargetStack
3261 /**
3262 * Returns the reparent target stack, creating the stack if necessary. This call also enforces
3263 * the various checks on tasks that are going to be reparented from one stack to another.
3264 */
3265 // TODO: Look into changing users to this method to ActivityDisplay.resolveWindowingMode()
3266 ActivityStack getReparentTargetStack(TaskRecord task, ActivityStack stack, boolean toTop) {
3267 final ActivityStack prevStack = task.getStack();
3268 final int stackId = stack.mStackId;
3269 final boolean inMultiWindowMode = stack.inMultiWindowMode();
3270
3271 // Check that we aren't reparenting to the same stack that the task is already in
3272 if (prevStack != null && prevStack.mStackId == stackId) {
3273 Slog.w(TAG, "Can not reparent to same stack, task=" + task
3274 + " already in stackId=" + stackId);
3275 return prevStack;
3276 }
3277
3278 // Ensure that we aren't trying to move into a multi-window stack without multi-window
3279 // support
3280 if (inMultiWindowMode && !mService.mSupportsMultiWindow) {
3281 throw new IllegalArgumentException("Device doesn't support multi-window, can not"
3282 + " reparent task=" + task + " to stack=" + stack);
3283 }
3284
3285 // Ensure that we're not moving a task to a dynamic stack if device doesn't support
3286 // multi-display.
3287 if (stack.mDisplayId != DEFAULT_DISPLAY && !mService.mSupportsMultiDisplay) {
3288 throw new IllegalArgumentException("Device doesn't support multi-display, can not"
3289 + " reparent task=" + task + " to stackId=" + stackId);
3290 }
3291
3292 // Ensure that we aren't trying to move into a freeform stack without freeform support
3293 if (stack.getWindowingMode() == WINDOWING_MODE_FREEFORM
3294 && !mService.mSupportsFreeformWindowManagement) {
3295 throw new IllegalArgumentException("Device doesn't support freeform, can not reparent"
3296 + " task=" + task);
3297 }
3298
3299 // Leave the task in its current stack or a fullscreen stack if it isn't resizeable and the
3300 // preferred stack is in multi-window mode.
3301 if (inMultiWindowMode && !task.isResizeable()) {
3302 Slog.w(TAG, "Can not move unresizeable task=" + task + " to multi-window stack=" + stack
3303 + " Moving to a fullscreen stack instead.");
3304 if (prevStack != null) {
3305 return prevStack;
3306 }
3307 stack = stack.getDisplay().createStack(
3308 WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), toTop);
3309 }
3310 return stack;
3311 }
复用流程-step 3:
1326 final ActivityRecord outResult =
1327 outActivity != null && outActivity.length > 0 ? outActivity[0] : null;
1328
1329 // When there is a reused activity and the current result is a trampoline activity,
1330 // set the reused activity as the result.
1331 if (outResult != null && (outResult.finishing || outResult.noDisplay)) {
1332 outActivity[0] = reusedActivity;
1333 }
1334
1335 if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
1336 // We don't need to start a new activity, and the client said not to do anything
1337 // if that is the case, so this is it! And for paranoia, make sure we have
1338 // correctly resumed the top activity.
1339 resumeTargetStackIfNeeded();
1340 return START_RETURN_INTENT_TO_CALLER;
1341 }
1342
1343 if (reusedActivity != null) {
1344 setTaskFromIntentActivity(reusedActivity);
1345
1346 if (!mAddingToTask && mReuseTask == null) {
1347 // We didn't do anything... but it was needed (a.k.a., client don't use that
1348 // intent!) And for paranoia, make sure we have correctly resumed the top activity.
//如果无需新添加,则复用原来的Activity;按理说前面在moveTaskToFrontLocked应该已经走过resume的流程了
//这里只是以防万一;mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, null, mOptions);
//注意这里第二个参数为null,也就是resume当前top Running Activity,参考https://www.jianshu.com/p/1a58b10387fc
1350 resumeTargetStackIfNeeded();
1351 if (outActivity != null && outActivity.length > 0) {
1352 outActivity[0] = reusedActivity;
1353 }
1354
1355 return mMovedToFront ? START_TASK_TO_FRONT : START_DELIVERED_TO_TOP; //然后根据相应task是否先被移动到前台决定返回值
1356 }
1357 }
1358 }
setTaskFromIntentActivity的逻辑
主要是针对mAddingToTask 和 mSourceRecord
1969 private void setTaskFromIntentActivity(ActivityRecord intentActivity) {
1970 if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
1971 == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
//如果start flag包含FLAG_ACTIVITY_CLEAR_TASK,直接将复用task中的Activity清掉
1972 // The caller has requested to completely replace any existing task with its new
1973 // activity. Well that should not be too hard...
1974 // Note: we must persist the {@link TaskRecord} first as intentActivity could be
1975 // removed from calling performClearTaskLocked (For example, if it is being brought out
1976 // of history or if it is finished immediately), thus disassociating the task. Also note
1977 // that mReuseTask is reset as a result of {@link TaskRecord#performClearTaskLocked}
1978 // launching another activity.
1979 // TODO(b/36119896): We shouldn't trigger activity launches in this path since we are
1980 // already launching one.
1981 final TaskRecord task = intentActivity.getTask();
1982 task.performClearTaskLocked();
1983 mReuseTask = task;
1984 mReuseTask.setIntent(mStartActivity);
1985 } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
1986 || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
1987 ActivityRecord top = intentActivity.getTask().performClearTaskLocked(mStartActivity,
1988 mLaunchFlags);
1989 if (top == null) {
1990 // A special case: we need to start the activity because it is not currently
1991 // running, and the caller has asked to clear the current task to have this
1992 // activity at the top.
1993 mAddingToTask = true; //如果在复用task中没有找到可复用的Activity,将mAddingToTask置为true
1994
1995 // We are no longer placing the activity in the task we previously thought we were.
1996 mStartActivity.setTask(null);
1997 // Now pretend like this activity is being started by the top of its task, so it
1998 // is put in the right place.
1999 mSourceRecord = intentActivity; //并重新定义mSourceRecord ,为了后续调用setTaskFromSourceRecord做准备
2000 final TaskRecord task = mSourceRecord.getTask();
2001 if (task != null && task.getStack() == null) {
2002 // Target stack got cleared when we all activities were removed above.
2003 // Go ahead and reset it.
2004 mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */,
2005 mLaunchFlags, mOptions);
2006 mTargetStack.addTask(task,
2007 !mLaunchTaskBehind /* toTop */, "startActivityUnchecked");
2008 }
2009 }
2010 } else if (mStartActivity.realActivity.equals(intentActivity.getTask().realActivity)) {
2011 // In this case the top activity on the task is the same as the one being launched,
2012 // so we take that as a request to bring the task to the foreground. If the top
2013 // activity in the task is the root activity, deliver this new intent to it if it
2014 // desires.
2015 if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
2016 || LAUNCH_SINGLE_TOP == mLaunchMode)
2017 && intentActivity.realActivity.equals(mStartActivity.realActivity)) {
2018 if (intentActivity.frontOfTask) {
2019 intentActivity.getTask().setIntent(mStartActivity);
2020 }
2021 deliverNewIntent(intentActivity);
2022 } else if (!intentActivity.getTask().isSameIntentFilter(mStartActivity)) {
2023 // In this case we are launching the root activity of the task, but with a
2024 // different intent. We should start a new instance on top.
2025 mAddingToTask = true; //应该是newTask结合normal launch mode的情况
2026 mSourceRecord = intentActivity;
2027 }
2028 } else if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
2029 // In this case an activity is being launched in to an existing task, without
2030 // resetting that task. This is typically the situation of launching an activity
2031 // from a notification or shortcut. We want to place the new activity on top of the
2032 // current task.
//newTask+normal launch mode+指定的task已存在,可能会走到这里
2033 mAddingToTask = true;
2034 mSourceRecord = intentActivity;
2035 } else if (!intentActivity.getTask().rootWasReset) {
2036 // In this case we are launching into an existing task that has not yet been started
2037 // from its front door. The current task has been brought to the front. Ideally,
2038 // we'd probably like to place this new task at the bottom of its stack, but that's
2039 // a little hard to do with the current organization of the code so for now we'll
2040 // just drop it.
2041 intentActivity.getTask().setIntent(mStartActivity);
2042 }
2043 }
startActivity.png
网友评论