美文网首页android之AMS学习攻克
Activity相关学习-启动(4)-启动流程总结之复用逻辑

Activity相关学习-启动(4)-启动流程总结之复用逻辑

作者: weiinter105 | 来源:发表于2019-01-13 18:27 被阅读0次

前言

前面说到了权限检查,查找复用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

相关文章

网友评论

    本文标题:Activity相关学习-启动(4)-启动流程总结之复用逻辑

    本文链接:https://www.haomeiwen.com/subject/srbirqtx.html