Android AMS 完全剖析 —— Activity 管理之启动过程情景分析3

本文基于 android-10.0.0_r41 版本讲解

上节分析到 ATMS 中的启动过程会调用到一个很长的 startActivity 重载:

java 复制代码
    // frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
    private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
                ActivityRecord[] outActivity, boolean restrictedBgActivity) {
        
        int result = START_CANCELED;
        final ActivityStack startedActivityStack;
        try {
            
            // wms 推迟布局,或者说暂停布局,这里了解
            mService.mWindowManager.deferSurfaceLayout();
            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity, restrictedBgActivity);
        } finally {
            // 待会儿分析
            // ......
        }

        postStartActivityProcessing(r, result, startedActivityStack);

        return result;
    }
  • 调用 deferSurfaceLayout 方法推迟布局,内部只是简单给一个标记量加 1
  • 接着调用 startActivityUnchecked 方法,finally 中的内容我们待会再来看

startActivityUnchecked 方法非常非常长,我们分步查看

java 复制代码
    // frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity, boolean restrictedBgActivity) {
        
        // 关注点1
        // ActivityStarter 对象内部参数初始化
        setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
                voiceInteractor, restrictedBgActivity);

        final int preferredWindowingMode = mLaunchParams.mWindowingMode;

        // 关注点2
        // 通过 launchmode 和 flag,计算目标 Activity 的启动方式
        computeLaunchingTaskFlags();

        // 关注点3
        //确定发起端的 ActivityStack 情况,也就是 Launcher 所在的 ActivityStack
        computeSourceStack();

        // ......

关注点 1 的 setInitialState 方法对 ActivityStarter 对象中的内部参数做一个初始化操作:

java 复制代码
    // frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
    private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
            boolean doResume, int startFlags, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            boolean restrictedBgActivity) {
        
        //将 ActivityStarter 对象的成员初始化
        reset(false /* clearRequest */);

        // 将目标 ActivityRecord 赋值给成员变量 mStartActivity
        mStartActivity = r;
        mIntent = r.intent;
        mOptions = options;
        mCallingUid = r.launchedFromUid;
        mSourceRecord = sourceRecord; // 启动端的 ActivityRecord,这里就是 Launcher
        mVoiceSession = voiceSession; // null
        mVoiceInteractor = voiceInteractor; // null
        mRestrictedBgActivity = restrictedBgActivity; //false

        // mLaunchParams 的类型是 LaunchParams,用于保存启动相关的参数
        // reset 方法初始化内部参数
        mLaunchParams.reset();

        /*
            static class LaunchParams {
                final Rect mBounds = new Rect();
                int mPreferredDisplayId;
                int mWindowingMode;

                // ......
            }
        */

        // 计算 mLaunchParams 的值
        // Preferred display id is the only state we need for now and it could be updated again
        // after we located a reusable task (which might be resided in another display).
        mSupervisor.getLaunchParamsController().calculate(inTask, r.info.windowLayout, r,
                sourceRecord, options, PHASE_DISPLAY, mLaunchParams);
        mPreferredDisplayId =
                mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
                        : DEFAULT_DISPLAY;

        mLaunchMode = r.launchMode;

        /*
        	FLAG_ACTIVITY_NEW_DOCUMENT flag 处理了解
        */
        mLaunchFlags = adjustLaunchFlagsToDocumentMode(
                r, LAUNCH_SINGLE_INSTANCE == mLaunchMode,
                LAUNCH_SINGLE_TASK == mLaunchMode, mIntent.getFlags());

        // 是否为后台启动任务的标志位
        mLaunchTaskBehind = r.mLaunchTaskBehind
                && !isLaunchModeOneOf(LAUNCH_SINGLE_TASK, LAUNCH_SINGLE_INSTANCE)
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0;

        /* 
           newTask 的启动模式,是无法获取到请求结果的,该方法处理这种情况
        */		
        sendNewTaskResultRequestIfNeeded();

        // 当前情景不进入
        //如果设置了 NEW_DOCUMENT 标志同时此 Activity 不是其他 Activity 启动的
        //则在加上 NEW_TASK 的标志
        if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
            mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
        }

        // If we are actually going to launch in to a new task, there are some cases where
        // we further want to do multiple task.
        if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {

            // 对于后台启动的新任务,可以多任务运行
            if (mLaunchTaskBehind
                    || r.info.documentLaunchMode == DOCUMENT_LAUNCH_ALWAYS) { // 不进入
                mLaunchFlags |= FLAG_ACTIVITY_MULTIPLE_TASK;
            }
        }

        // mUserLeaving 是一个布尔变量用于标识是否离开上一个 Activity
        // 这里计算出 mUserLeaving 值为 true
        // We'll invoke onUserLeaving before onPause only if the launching
        // activity did not explicitly state that this is an automated launch.
        mSupervisor.mUserLeaving = (mLaunchFlags & FLAG_ACTIVITY_NO_USER_ACTION) == 0;
        if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
                "startActivity() => mUserLeaving=" + mSupervisor.mUserLeaving);

        // If the caller has asked not to resume at this point, we make note
        // of this in the record so that we can skip it when trying to find
        // the top running activity.
        mDoResume = doResume; // true
        if (!doResume || !r.okToShowLocked()) { // 不进入
            r.delayedResume = true;
            mDoResume = false;
        }

        if (mOptions != null) {
            // 两个分支条件都不满足,都不进入
            if (mOptions.getLaunchTaskId() != -1 && mOptions.getTaskOverlay()) {
                r.mTaskOverlay = true;
                if (!mOptions.canTaskOverlayResume()) {
                    final TaskRecord task = mRootActivityContainer.anyTaskForId(
                            mOptions.getLaunchTaskId());
                    final ActivityRecord top = task != null ? task.getTopActivity() : null;
                    if (top != null && !top.isState(RESUMED)) {

                        // The caller specifies that we'd like to be avoided to be moved to the
                        // front, so be it!
                        mDoResume = false;
                        mAvoidMoveToFront = true;
                    }
                }
            } else if (mOptions.getAvoidMoveToFront()) { 
                mDoResume = false;
                mAvoidMoveToFront = true;
            }
        }

        /*
        
            FLAG_ACTIVITY_PREVIOUS_IS_TOP flag 处理
            了解即可
		*/

        // 当前场景下 mNotTop 为空
        mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? sourceRecord : null;

        mInTask = inTask; // null
        // In some flows in to this function, we retrieve the task record and hold on to it
        // without a lock before calling back in to here...  so the task at this point may
        // not actually be in recents.  Check for that, and if it isn't in recents just
        // consider it invalid.
        if (inTask != null && !inTask.inRecents) {
            Slog.w(TAG, "Starting activity in task not in recents: " + inTask);
            mInTask = null;
        }

        mStartFlags = startFlags; // 0
        // If the onlyIfNeeded flag is set, then we can do this if the activity being launched
        // is the same as the one making the call...  or, as a special case, if we do not know
        // the caller then we count the current top activity as the caller.
        if ((startFlags & START_FLAG_ONLY_IF_NEEDED) != 0) { //不进入
            ActivityRecord checkedCaller = sourceRecord;
            if (checkedCaller == null) {
                checkedCaller = mRootActivityContainer.getTopDisplayFocusedStack()
                        .topRunningNonDelayedActivityLocked(mNotTop);
            }
            if (!checkedCaller.mActivityComponent.equals(r.mActivityComponent)) {
                // Caller is not the same as launcher, so always needed.
                mStartFlags &= ~START_FLAG_ONLY_IF_NEEDED;
            }
        }

        //是否有动画
        mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0; // false

        if (mRestrictedBgActivity && !mService.isBackgroundActivityStartsEnabled()) { // 不进入
            mAvoidMoveToFront = true;
            mDoResume = false;
        }
    }

setInitialState 主要对以下的变量做了初始化:

  • mStartActivity:ActivityStarter 类的成员变量,待启动目标 Activity 对应的 ActivityRecord 对象
  • mIntent:ActivityStarter 类的成员变量,用于启动目标 Activity
  • mOptions:ActivityStarter 类的成员变量,启动目标 Activity 的额外参数
  • mCallingUid:ActivityStarter 类的成员变量,启动方的 uid
  • mSourceRecord:ActivityStarter 类的成员变量,启动端的 ActivityRecord
  • mVoiceSession:ActivityStarter 类的成员变量,当前情景下为 null,不太清楚作用
  • mVoiceInteractor:ActivityStarter 类的成员变量,当前情景下为 null,不太清楚作用
  • mRestrictedBgActivity:ActivityStarter 类的成员变量,布尔变量,表示是否限制后台启动 Activity
  • mLaunchParams:ActivityStarter 类的成员变量,用于保存启动相关的参数
java 复制代码
static class LaunchParams {
                final Rect mBounds = new Rect();
                int mPreferredDisplayId;
                int mWindowingMode;

                // ......
}
  • mPreferredDisplayId:ActivityStarter 类的成员变量,用于指示优先显示的屏幕
  • mLaunchMode:ActivityStarter 类的成员变量,目标 Activity 的启动模式
  • mLaunchFlags:ActivityStarter 类的成员变量,目标 Activity 的启动 flag
  • mSupervisor.mUserLeaving: ActivityStackSupervisor 类的成员变量,是一个布尔变量用于标识是否离开上一个 Activity
  • mDoResume:ActivityStarter 类的成员变量,布尔变量,用于表示目标 Activity 是否要执行 onResume 生命周期方法
  • mNotTop:ActivityStarter 类的成员变量, FLAG_ACTIVITY_PREVIOUS_IS_TOP flag 相关的变量
  • mInTask:ActivityStarter 类的成员变量,目标 Activity 所在的 TaskRecord
  • mNoAnimation:ActivityStarter 类的成员变量,布尔变量,用于表示目标 Activity 启动是否无动画
  • mAvoidMoveToFront:ActivityStarter 类的成员变量,布尔变量,用于表示目标 Activity 启动是否不移动到前台

关注点 2 ,computeLaunchingTaskFlags 方法根据 launchMode 和 Intent 中的 FLAG_ACTIVITY_NEW_TASK 等 flag 综合计算 activity 的启动模式,

java 复制代码
    // frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java

    /**
	  根据 launchMode 和 Intent 中的 FLAG_ACTIVITY_NEW_TASK 等 flag 综合计算 activity 的启动模式,
	  结果保存在 mLaunchFlags 中。

      计算的过程不仅要考虑目标 activity 的 launchMode,也要考虑原来 activity 的 launchMode 和Intent中所带着的flag
	*/
    private void computeLaunchingTaskFlags() {
        // If the caller is not coming from another activity, but has given us an explicit task into
        // which they would like us to launch the new activity, then let's see about doing that.
        if (mSourceRecord == null && mInTask != null && mInTask.getStack() != null) {
            final Intent baseIntent = mInTask.getBaseIntent();
            final ActivityRecord root = mInTask.getRootActivity();
            if (baseIntent == null) {
                ActivityOptions.abort(mOptions);
                throw new IllegalArgumentException("Launching into task without base intent: "
                        + mInTask);
            }

            // If this task is empty, then we are adding the first activity -- it
            // determines the root, and must be launching as a NEW_TASK.
            if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
                if (!baseIntent.getComponent().equals(mStartActivity.intent.getComponent())) {
                    ActivityOptions.abort(mOptions);
                    throw new IllegalArgumentException("Trying to launch singleInstance/Task "
                            + mStartActivity + " into different task " + mInTask);
                }
                if (root != null) {
                    ActivityOptions.abort(mOptions);
                    throw new IllegalArgumentException("Caller with mInTask " + mInTask
                            + " has root " + root + " but target is singleInstance/Task");
                }
            }

            // If task is empty, then adopt the interesting intent launch flags in to the
            // activity being started.
            if (root == null) {
                final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK
                        | FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS;
                mLaunchFlags = (mLaunchFlags & ~flagsOfInterest)
                        | (baseIntent.getFlags() & flagsOfInterest);
                mIntent.setFlags(mLaunchFlags);
                mInTask.setIntent(mStartActivity);
                mAddingToTask = true;

                // If the task is not empty and the caller is asking to start it as the root of
                // a new task, then we don't actually want to start this on the task. We will
                // bring the task to the front, and possibly give it a new intent.
            } else if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
                mAddingToTask = false;

            } else {
                mAddingToTask = true;
            }

            mReuseTask = mInTask;
        } else {
            mInTask = null;
            // Launch ResolverActivity in the source task, so that it stays in the task bounds
            // when in freeform workspace.
            // Also put noDisplay activities in the source task. These by itself can be placed
            // in any task/stack, however it could launch other activities like ResolverActivity,
            // and we want those to stay in the original task.
            if ((mStartActivity.isResolverOrDelegateActivity() || mStartActivity.noDisplay)
                    && mSourceRecord != null && mSourceRecord.inFreeformWindowingMode()) {
                mAddingToTask = true;
            }
        }

        if (mInTask == null) {
            if (mSourceRecord == null) {
                // This activity is not being started from another...  in this
                // case we -always- start a new task.
                if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
                    Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
                            "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
                    mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
                }
            } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
                // The original activity who is starting us is running as a single
                // instance...  this new activity it is starting must go on its
                // own task.
                mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
            } else if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
                // The activity being started is a single instance...  it always
                // gets launched into its own task.
                mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
            }
        }
    }

根据 launchMode 和 Intent 中的 FLAG_ACTIVITY_NEW_TASK 等 flag 综合计算 activity 的启动模式,结果保存在 mLaunchFlags 中。计算的过程不仅要考虑目标 Activity 的 launchMode,也要考虑原来 Activity 的 launchMode 和 Intent 中所带着的 flag。

细节很多,目前关注主要流程,后面单独一节来讲。这里知道计算出的结果保存在 mLaunchFlags 即可。

我们接着看关注点 3 处的 computeSourceStack 方法:

java 复制代码
    // frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java

    //确定发起端的 ActivityStack
    private void computeSourceStack() {
        if (mSourceRecord == null) {
            mSourceStack = null;
            return;
        }
        if (!mSourceRecord.finishing) { //直接返回
            mSourceStack = mSourceRecord.getActivityStack();
            return;
        }

        //如果调用方已经finish了,那么就无法将其作为我们的源任务栈了,这时候,要强行添加FLAG_ACTIVITY_NEW_TASK标志使activity启动到一个新的task中
        // If the source is finishing, we can't further count it as our source. This is because the
        // task it is associated with may now be empty and on its way out, so we don't want to
        // blindly throw it in to that task.  Instead we will take the NEW_TASK flow and try to find
        // a task for it. But save the task information so it can be used when creating the new task.
        if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
            Slog.w(TAG, "startActivity called from finishing " + mSourceRecord
                    + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
            mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
            mNewTaskInfo = mSourceRecord.info;

            // It is not guaranteed that the source record will have a task associated with it. For,
            // example, if this method is being called for processing a pending activity launch, it
            // is possible that the activity has been removed from the task after the launch was
            // enqueued.
            final TaskRecord sourceTask = mSourceRecord.getTaskRecord();
            mNewTaskIntent = sourceTask != null ? sourceTask.intent : null;
        }
        mSourceRecord = null;
        mSourceStack = null;
    }

这里主要确定发起端的 ActivityStack 对象。一般情况下,直接通过启动端的 mSourceRecord 的 getActivityStack 获取到。如果调用方已经 finish 了,那么就无法将其作为我们的源任务栈了,这时候,要强行添加 FLAG_ACTIVITY_NEW_TASK 标志使 activity 启动到一个新的 task 中。

接下来,回到 startActivityUnchecked 方法中:

java 复制代码
    private int startActivityUnchecked(...) {

        //......

        // 把前面计算出的 mLaunchFlags 设置到 mIntent 中
        mIntent.setFlags(mLaunchFlags);


        // 查找是否有重用的 Activity
        // 当前场景下为 null
        ActivityRecord reusedActivity = getReusableIntentActivity();

        // ......
    }

getReusableIntentActivity 查找可复用的 Activity,当前场景下为 null,巨复杂,单独一节来讲,这里先梳理主干流程。

接着回到 startActivityUnchecked 方法中:

java 复制代码
    private int startActivityUnchecked(...) {
        // ......

        // 用新计算出的参数重新计算一次 mLaunchParams
        mSupervisor.getLaunchParamsController().calculate(
                reusedActivity != null ? reusedActivity.getTaskRecord() : mInTask,
                r.info.windowLayout, r, sourceRecord, options, PHASE_BOUNDS, mLaunchParams);
        // 重新获取 mPreferredDisplayId
        mPreferredDisplayId =
                mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
                        : DEFAULT_DISPLAY;

        // 冻结最近任务列表,单独一节来讲
        // If requested, freeze the task list
        if (mOptions != null && mOptions.freezeRecentTasksReordering()
                && mSupervisor.mRecentTasks.isCallerRecents(r.launchedFromUid)
                && !mSupervisor.mRecentTasks.isFreezeTaskListReorderingSet()) {
            mFrozeTaskList = true;
            mSupervisor.mRecentTasks.setFreezeTaskListReordering();
        }


        // 判断是否是 Launcher 主页面,不要启动 Launcher 主页面
        // Do not start home activity if it cannot be launched on preferred display. We are not
        // doing this in ActivityStackSupervisor#canPlaceEntityOnDisplay because it might
        // fallback to launch on other displays.
        if (r.isActivityTypeHome() && !mRootActivityContainer.canStartHomeOnDisplay(r.info,
                mPreferredDisplayId, true /* allowInstrumenting */)) {
            Slog.w(TAG, "Cannot launch home on display " + mPreferredDisplayId);
            return START_CANCELED;
        }


        // 当前情景下,没有重用,不进入
        if (reusedActivity != null) {
            // ......
        }

        // 不进入
        if (mStartActivity.packageName == null) {
            // ......
        }

        // If the activity being launched is the same as the one currently at the top, then
        // we need to check if it should only be launched once.
        // Launcher 的 ActivityStack
        final ActivityStack topStack = mRootActivityContainer.getTopDisplayFocusedStack();
        // 
        final ActivityRecord topFocused = topStack.getTopActivity();
        final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);

        // false
        final boolean dontStart = top != null && mStartActivity.resultTo == null
                && top.mActivityComponent.equals(mStartActivity.mActivityComponent)
                && top.mUserId == mStartActivity.mUserId
                && top.attachedToProcess()
                && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
                || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK))
                // This allows home activity to automatically launch on secondary display when
                // display added, if home was the top activity on default display, instead of
                // sending new intent to the home activity on default display.
                && (!top.isActivityTypeHome() || top.getDisplayId() == mPreferredDisplayId);
        
        if (dontStart) { // 不进入
            //......
        }

        boolean newTask = false;
        // null
        final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
                ? mSourceRecord.getTaskRecord() : null;

        // Should this be considered a new task?
        int result = START_SUCCESS;
        if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) { // 走这个分支
            newTask = true;
            // 查找/新建管理目标 Activity 的 TaskRecord 任务栈对象
            result = setTaskFromReuseOrCreateNewTask(taskToAffiliate);
        } else if (mSourceRecord != null) {
            result = setTaskFromSourceRecord();
        } else if (mInTask != null) {
            result = setTaskFromInTask();
        } else {
            // This not being started from an existing activity, and not part of a new task...
            // just put it in the top task, though these days this case should never happen.
            result = setTaskToCurrentTopOrCreateNewTask();
        }
        if (result != START_SUCCESS) {
            return result;
        }
  • 用新计算出的参数重新计算一次 mLaunchParams
  • 重新获取 mPreferredDisplayId
  • 冻结最近任务列表
  • 判断是否是 Launcher 主页面,不要启动 Launcher 主页面
  • 处理可重用的 Activity,当前情景下,没有重用
  • 查找/新建管理目标 Activity 的 TaskRecord 任务栈对象

查找/新建管理目标 Activity 的 TaskRecord 任务栈对象通过 setTaskFromReuseOrCreateNewTask 方法实现:

java 复制代码
    // frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
    private int setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
        // 错误情况处理,直接返回
        if (mRestrictedBgActivity && (mReuseTask == null || !mReuseTask.containsAppUid(mCallingUid))
                && handleBackgroundActivityAbort(mStartActivity)) {
            return START_ABORTED;
        }

        // 获取/创建目标 Activity 所在的 ActivityStack 
        // 当前情景下,层层调用,最终实际就是 new 一个 ActivityStack
        mTargetStack = computeStackFocus(mStartActivity, true, mLaunchFlags, mOptions);

        // Do no move the target stack to front yet, as we might bail if
        // isLockTaskModeViolation fails below.

        if (mReuseTask == null) { //没有可复用的任务栈,进入分支
            final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront;
            // 创建新 App 对应的新的任务栈
            // 当前情景下,层层调用,实际也是 new 一个 TaskRecord
            final TaskRecord task = mTargetStack.createTaskRecord(
                    mSupervisor.getNextTaskIdForUserLocked(mStartActivity.mUserId),
                    mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
                    mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
                    mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);

            // 将目标 ActivityRecord 插入新建的 TaskRecord 的栈顶为止
            addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
            updateBounds(mStartActivity.getTaskRecord(), mLaunchParams.mBounds);

            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
                    + " in new task " + mStartActivity.getTaskRecord());
        } else {
            addOrReparentStartingActivity(mReuseTask, "setTaskFromReuseOrCreateNewTask");
        }

        if (taskToAffiliate != null) { // 不进入
            mStartActivity.setTaskToAffiliateWith(taskToAffiliate);
        }

        if (mService.getLockTaskController().isLockTaskModeViolation(
                mStartActivity.getTaskRecord())) {
            Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
            return START_RETURN_LOCK_TASK_MODE_VIOLATION;
        }

        // 将 ActivityStack 设置到栈顶
        // 好像就是调整 ActivityStack 在 ArrayList 中的位置
        if (mDoResume) {
            mTargetStack.moveToFront("reuseOrNewTask");
        }
        return START_SUCCESS;
    }  

我们为启动目标 Activity 完成了一下工作:

  • new 了一个 ActivityStack 对象
  • 在 ActivityStack 中 new 了一个 TaskRecord 对象
  • 将目标 ActivityRecord 插入新建的 TaskRecord 的栈顶为止

注意一点就是新 new 的 TaskRecord 可能不在 ActivityStack 的栈顶位置,后面应该会调整。

java 复制代码
    private int startActivityUnchecked(...) {
        // 给目标 Activity 授权
        // https://juejin.cn/post/7138335779222355975
        mService.mUgmInternal.grantUriPermissionFromIntent(mCallingUid, mStartActivity.packageName,
                mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.mUserId);

        mService.getPackageManagerInternalLocked().grantEphemeralAccess(
                mStartActivity.mUserId, mIntent, UserHandle.getAppId(mStartActivity.appInfo.uid),
                UserHandle.getAppId(mCallingUid));

        if (newTask) {
            EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, mStartActivity.mUserId,
                    mStartActivity.getTaskRecord().taskId);
        }

        ActivityStack.logStartActivity(
                EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.getTaskRecord());

        mTargetStack.mLastPausedActivity = null;

        // PowerHint 设置,用于提升系统性能
        // https://blog.csdn.net/zxfrdas/article/details/118118584
        mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded(
                false /* forceSend */, mStartActivity);

        // mTargetStack 内部数据结构调整
        mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
                mOptions);

        if (mDoResume) {
            // 目标新 ActivityRecord
            final ActivityRecord topTaskActivity =
                    mStartActivity.getTaskRecord().topRunningActivityLocked();
            if (!mTargetStack.isFocusable()
                    || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                    && mStartActivity != topTaskActivity)) { // 不走
                // If the activity is not focusable, we can't resume it, but still would like to
                // make sure it becomes visible as it starts (this will also trigger entry
                // animation). An example of this are PIP activities.
                // Also, we don't want to resume activities in a task that currently has an overlay
                // as the starting activity just needs to be in the visible paused state until the
                // over is removed.
                mTargetStack.ensureActivitiesVisibleLocked(mStartActivity, 0, !PRESERVE_WINDOWS);
                // Go ahead and tell window manager to execute app transition for this activity
                // since the app transition will not be triggered through the resume channel.
                mTargetStack.getDisplay().mDisplayContent.executeAppTransition();
            } else {
                // If the target stack was not previously focusable (previous top running activity
                // on that stack was not visible) then any prior calls to move the stack to the
                // will not update the focused stack.  If starting the new activity now allows the
                // task stack to be focusable, then ensure that we now update the focused stack
                // accordingly.
                // 也不走
                if (mTargetStack.isFocusable()
                        && !mRootActivityContainer.isTopDisplayFocusedStack(mTargetStack)) {
                    mTargetStack.moveToFront("startActivityUnchecked");
                }

                // 走这里
                mRootActivityContainer.resumeFocusedStacksTopActivities(
                        mTargetStack, mStartActivity, mOptions);
            }
        } else if (mStartActivity != null) {
            mSupervisor.mRecentTasks.add(mStartActivity.getTaskRecord());
        }
        mRootActivityContainer.updateUserStack(mStartActivity.mUserId, mTargetStack);

        mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTaskRecord(),
                preferredWindowingMode, mPreferredDisplayId, mTargetStack);

        return START_SUCCESS;
    }
  • 给目标 Activity 进行 Uri 授权
  • PowerHint 设置,用于提升系统性能
  • mTargetStack 内部数据结构调整,前面说过新 new 的 TaskRecord 可能不在 ActivityStack 的栈顶位置,在这里通过调用 mTargetStack.startActivityLocked 做相应的调整
  • 最后调用 mRootActivityContainer.resumeFocusedStacksTopActivities onPause 前一个 Activity,这部分内容我们在下一节来做讲解。

接下来,我们着重看下 mTargetStack.startActivityLocked 的具体实现:

java 复制代码
    // frameworks/base/services/core/java/com/android/server/wm/ActivityStack.java
    void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
            boolean newTask, boolean keepCurTransition, ActivityOptions options) {
        
        TaskRecord rTask = r.getTaskRecord();
        final int taskId = rTask.taskId;
        final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
        // mLaunchTaskBehind tasks get placed at the back of the task stack.
        if (!r.mLaunchTaskBehind && allowMoveToFront
                && (taskForIdLocked(taskId) == null || newTask)) { // 进入分支
            // Last activity in task had been removed or ActivityManagerService is reusing task.
            // Insert or replace.
            // Might not even be in.
            // 将 task 放到栈顶,实际就是调整 taskrecord 在 list 中的位置
            insertTaskAtTop(rTask, r);
        }
        TaskRecord task = null;
        if (!newTask) { //当前情景不进入
           // ......
        }

        // Place a new activity at top of stack, so it is next to interact with the user.

        // If we are not placing the new activity frontmost, we do not want to deliver the
        // onUserLeaving callback to the actual frontmost activity
        final TaskRecord activityTask = r.getTaskRecord();
       
        // ......

        task = activityTask;

        // ......

        if (r.mAppWindowToken == null) {
            // 构建 ActivityRecord 的成员 mAppWindowToken
            r.createAppWindowToken();
        }

         /** Call after activity movement or finish to make sure that frontOfTask is set correctly */
        // 做检查修正,确保内部参数正确
        task.setFrontOfTask();


        // 过渡动画处理
        // The transition animation and starting window are not needed if {@code allowMoveToFront}
        // is false, because the activity won't be visible.
        if ((!isHomeOrRecentsStack() || numActivities() > 0) && allowMoveToFront) { // 进入分支
            final DisplayContent dc = getDisplay().mDisplayContent;
            if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                    "Prepare open transition: starting " + r);
            if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
                dc.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
                mStackSupervisor.mNoAnimActivities.add(r);
            } else { // 走这个分支
                int transit = TRANSIT_ACTIVITY_OPEN;
                if (newTask) {
                    if (r.mLaunchTaskBehind) {
                        transit = TRANSIT_TASK_OPEN_BEHIND;
                    } else if (getDisplay().isSingleTaskInstance()) {
                        transit = TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
                    } else {
                        // If a new task is being launched, then mark the existing top activity as
                        // supporting picture-in-picture while pausing only if the starting activity
                        // would not be considered an overlay on top of the current activity
                        // (eg. not fullscreen, or the assistant)
                        if (canEnterPipOnTaskSwitch(focusedTopActivity,
                                null /* toFrontTask */, r, options)) { //走这个分支
                            focusedTopActivity.supportsEnterPipOnTaskSwitch = true;
                        }
                        transit = TRANSIT_TASK_OPEN;
                    }
                }

                // 过渡动画准备
                dc.prepareAppTransition(transit, keepCurTransition);
                mStackSupervisor.mNoAnimActivities.remove(r);
            }
            boolean doShow = true;
            if (newTask) {
                // Even though this activity is starting fresh, we still need
                // to reset it to make sure we apply affinities to move any
                // existing activities from other tasks in to it.
                // If the caller has requested that the target task be
                // reset, then do so.
                // 进入分支
                if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                    resetTaskIfNeededLocked(r, r);
                    doShow = topRunningNonDelayedActivityLocked(null) == r;
                }
            } else if (options != null && options.getAnimationType()
                    == ActivityOptions.ANIM_SCENE_TRANSITION) {
                doShow = false;
            }
            if (r.mLaunchTaskBehind) {
                // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we
                // tell WindowManager that r is visible even though it is at the back of the stack.
                r.setVisibility(true);
                ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
            } else if (SHOW_APP_STARTING_PREVIEW && doShow) { // 走这个分支
                // Figure out if we are transitioning from another activity that is
                // "has the same starting icon" as the next one.  This allows the
                // window manager to keep the previous window it had previously
                // created, if it still had one.
                TaskRecord prevTask = r.getTaskRecord(); // 新 Activity 对应的 TaskRecord
                ActivityRecord prev = prevTask.topRunningActivityWithStartingWindowLocked(); // null
                if (prev != null) {
                    // We don't want to reuse the previous starting preview if:
                    // (1) The current activity is in a different task.
                    if (prev.getTaskRecord() != prevTask) {
                        prev = null;
                    }
                    // (2) The current activity is already displayed.
                    else if (prev.nowVisible) {
                        prev = null;
                    }
                }
                // 开始 Activity 启动动画
                r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity));
            }
        } else {
            // If this is the first activity, don't do any fancy animations,
            // because there is nothing for it to animate on top of.
            ActivityOptions.abort(options);
        }
    }
  • 调整 taskrecord 在 ActivityStack 中的位置
  • 做检查修正 taskrecord 内部参数
  • 过渡动画处理

参考资料

相关推荐
怪兽20141 小时前
Android View, SurfaceView, GLSurfaceView 的区别
android·面试
龚礼鹏1 小时前
android 图像显示框架二——流程分析
android
消失的旧时光-19431 小时前
kmp需要技能
android·设计模式·kotlin
帅得不敢出门2 小时前
Linux服务器编译android报no space left on device导致失败的定位解决
android·linux·服务器
雨白3 小时前
协程间的通信管道 —— Kotlin Channel 详解
android·kotlin
TimeFine5 小时前
kotlin协程 容易被忽视的CompletableDeferred
android
czhc11400756636 小时前
Linux1023 mysql 修改密码等
android·mysql·adb
GOATLong7 小时前
MySQL内置函数
android·数据库·c++·vscode·mysql
onthewaying8 小时前
Android SurfaceTexture 深度解析
android·opengl
茄子凉心8 小时前
Android Bluetooth 蓝牙通信
android·蓝牙通信·bluetooth通信