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 内部参数
  • 过渡动画处理

参考资料

相关推荐
落落落sss6 分钟前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
代码敲上天.27 分钟前
数据库语句优化
android·数据库·adb
GEEKVIP3 小时前
手机使用技巧:8 个 Android 锁屏移除工具 [解锁 Android]
android·macos·ios·智能手机·电脑·手机·iphone
model20054 小时前
android + tflite 分类APP开发-2
android·分类·tflite
彭于晏6895 小时前
Android广播
android·java·开发语言
与衫6 小时前
掌握嵌套子查询:复杂 SQL 中 * 列的准确表列关系
android·javascript·sql
500了12 小时前
Kotlin基本知识
android·开发语言·kotlin
人工智能的苟富贵13 小时前
Android Debug Bridge(ADB)完全指南
android·adb
小雨cc5566ru18 小时前
uniapp+Android面向网络学习的时间管理工具软件 微信小程序
android·微信小程序·uni-app
bianshaopeng19 小时前
android 原生加载pdf
android·pdf