Android V app 冷启动 (1) Activity 启动

1,370 阅读22分钟

分析案例

竖屏下,从 Launcher 启动一个横屏 app。

app 很简单,直接从 Android Studio 创建一个 project,然后在 AndroidManifest.xml 中,把 MainActivity 的方向声明为横屏,如下

<activity
    android:name=".MainActivity"
    // 声明为横屏方向
    android:screenOrientation="landscape">
    
</activity>

第一阶段启动

Launcher

第一阶段启动,从 Launcher 点击 app 图标开始。 本人并不擅长 Launcher 开发,因此这里简单展示下代码逻辑,如下

// QuickStepLauncher.java

// 点击 workspace 图标,执行如下这个 View.OnClickListener
public View.OnClickListener getItemOnClickListener() {
    return this::onItemClicked;
}

protected void onItemClicked(View view) {
    if (!mSplitToWorkspaceController.handleSecondAppSelectionForSplit(view)) {
        // 调用到 ItemClickHandler#onClick()
        QuickstepLauncher.super.getItemOnClickListener().onClick(view);
    }
}
// ItemClickHandler.java

private static void onClick(View v) {
    // ...
    
    // 通过 View 的 Context, 强转 Launcher
    Launcher launcher = Launcher.getLauncher(v.getContext());
    if (!launcher.getWorkspace().isFinishedSwitchingState()) return;

    Object tag = v.getTag();
    if (tag instanceof WorkspaceItemInfo) { // 点击 workspace 区域图标
        onClickAppShortcut(v, (WorkspaceItemInfo) tag, launcher);
    } // ...
}

public static void onClickAppShortcut(View v, WorkspaceItemInfo shortcut, Launcher launcher) {
    // ...

    startAppShortcutOrInfoActivity(v, shortcut, launcher);
}

private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {

    Intent intent;
    if (item instanceof ItemInfoWithIcon
            && (((ItemInfoWithIcon) item).runtimeStatusFlags
            & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {

    } else {
        // WorkspaceItemInfo 获取启动 app 的 Intent
        intent = item.getIntent();
    }
    
    // ...
    
    // 由 Launcher 执行启动
    // 子类 QuickStepLauncher 有复写,但是最终由基类 ActivityContext 实现核心逻辑
    launcher.startActivitySafely(v, intent, item);
}
// ActivityContext.java

default RunnableList startActivitySafely(
        View v, Intent intent, @Nullable ItemInfo item) {
    
    Context context = (Context) this;
    
    // ..
    
    // 构建启动 Activity 时附带的参数
    // Launcher 的子类 QuickstepLauncher 复写了 getActivityLaunchOptions()
    ActivityOptionsWrapper options = v != null ? getActivityLaunchOptions(v, item)
            : makeDefaultActivityOptions(item != null && item.animationType == DEFAULT_NO_ICON
                    ? SPLASH_SCREEN_STYLE_SOLID_COLOR : -1 /* SPLASH_SCREEN_STYLE_UNDEFINED */);
    UserHandle user = item == null ? null : item.user;
    Bundle optsBundle = options.toBundle();
    
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    if (v != null) {
        // intent 保存了 view bounds
        intent.setSourceBounds(Utilities.getViewBounds(v));
    }
    
    
    try {
    
        // item.itemt.Type 为 ITEM_TYPE_APPLICATION
        boolean isShortcut = (item instanceof WorkspaceItemInfo)
                && (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
                || item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)
                && !((WorkspaceItemInfo) item).isPromise();
        if (isShortcut) {
            
        } else if (user == null || user.equals(Process.myUserHandle())) {
            // 由 Context 启动 activity
            context.startActivity(intent, optsBundle);
        } else {
            
        }
        
        // ...
        
        return options.onEndCallback;
    } catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
        // ...
    }
    return null;
}

Launcher 启动 app 的原理,就是通过 Context#startActivity() 启动指定 Activity。

很多人可能关心,启动 Activity 时传入的 Bundle 参数,包含哪些数据?简单来说,这些数据定义了 Launcher 如何执行远程动画,读者大致看下即可,如下

// QuickStepLauncher.java

public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) {
    // 创建 ActivityOptionsWrapper
    ActivityOptionsWrapper activityOptions =
            mAppTransitionManager.hasControlRemoteAppTransitionPermission()
                    ? mAppTransitionManager.getActivityLaunchOptions(v)
                    : super.getActivityLaunchOptions(v, item);
    
    // ...
    
    
    if (item != null && (item.animationType == DEFAULT_NO_ICON
            || item.animationType == VIEW_BACKGROUND)) {
        // ...
    } else {
        // 启动窗口使用 icon
        activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
    }
    
    // ...
    
    return activityOptions;
}
// QuickstepTransitionManager.java

public ActivityOptionsWrapper getActivityLaunchOptions(View v) {
    boolean fromRecents = isLaunchingFromRecents(v, null /* targets */);
    RunnableList onEndCallback = new RunnableList();

    // Handle the case where an already visible task is launched which results in no transition
    TaskRestartedDuringLaunchListener restartedListener =
            new TaskRestartedDuringLaunchListener();
    restartedListener.register(onEndCallback::executeAllAndDestroy);
    onEndCallback.add(restartedListener::unregister);

    // 远程动画的真正执行者
    mAppLaunchRunner = new AppLaunchAnimationRunner(v, onEndCallback);
    ItemInfo tag = (ItemInfo) v.getTag();
    if (tag != null && tag.shouldUseBackgroundAnimation()) {
       
    }
    
    // RemoteAnimationRunnerCompat 是为了兼容新旧两种动画而设计的类
    // 它把远程动画交给 mAppLaunchRunner 去执行
    RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(
            mHandler, mAppLaunchRunner, true /* startAtFrontOfQueue */);

    // Note that this duration is a guess as we do not know if the animation will be a
    // recents launch or not for sure until we know the opening app targets.
    long duration = fromRecents
            ? RECENTS_LAUNCH_DURATION
            : APP_LAUNCH_DURATION;

    long statusBarTransitionDelay = duration - STATUS_BAR_TRANSITION_DURATION
            - STATUS_BAR_TRANSITION_PRE_DELAY;
    ActivityOptions options = ActivityOptions.makeRemoteAnimation(
            new RemoteAnimationAdapter(runner, duration, statusBarTransitionDelay),
            new RemoteTransition(runner.toRemoteTransition(),
                    mLauncher.getIApplicationThread(), "QuickstepLaunch"));
    return new ActivityOptionsWrapper(options, onEndCallback);
}

ATMS

Context#startActivity() 调用到服务端的 ActivityTaskManagerService#startActivity()

// ActivityTaskManagerService.java

    public final int startActivity(IApplicationThread caller, String callingPackage,
            String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
            String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
            Bundle bOptions) {
        // 增加了最后一个参数 userId
        return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
                resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }
    
    public int startActivityAsUser(IApplicationThread caller, String callingPackage,
            String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
            String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
            Bundle bOptions, int userId) {
        // 增加了最后一个参数 validateIncomingUser,值为 true
        return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
                resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
                true /*validateIncomingUser*/);
    }
    
    private int startActivityAsUser(IApplicationThread caller, String callingPackage,
            @Nullable String callingFeatureId, Intent intent, String resolvedType,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {

        // app 端传过来的参数是 Bundle 类型,并且是序列化的,因此无法打印
        // 在服务端,需要把它转换为 ActivityOptions 才能打印 app 端传入的数据
        // 这里更进一步,把 ActivityOptions 包装成 SafeActivityOptions,为的是检测调用方的权限
        final SafeActivityOptions opts = SafeActivityOptions.fromBundle(bOptions);

        // ...
        
        // 把启动参数包装成 ActivityStart#mRequest ,并通过 ActivityStarter 来启动 activity
        return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage) // com.android.launcher
                .setCallingFeatureId(callingFeatureId) // null
                .setResolvedType(resolvedType) // 这是 MIME type,这里为 null
                .setResultTo(resultTo) // 指向 launcher
                .setResultWho(resultWho) // null 
                // requestCode 是 -1,也就是说 launcher 不需要知道启动结果
                .setRequestCode(requestCode) 
                .setStartFlags(startFlags) // 0
                .setProfilerInfo(profilerInfo) // null
                .setActivityOptions(opts) // 这个是启动 Activity 传入的数据,不为 null
                .setUserId(userId)
                .execute();

    }    

ATMS 把启动 Activity 的参数保存到了 ActivityStart#mRequest,然后把它交给 ActivityStarter 去执行启动 Activity 的任务。

ActivityStarter

// ActivityStarter.java

    /**
     * Resolve necessary information according the request parameters provided earlier, and execute
     * the request which begin the journey of starting an activity.
     * @return The starter result.
     */
    int execute() {
        try {
            // ...
            
            // 1.解析 Activity 信息,并保存到 mRequest.activityInfo
            if (mRequest.activityInfo == null) {
                mRequest.resolveActivity(mSupervisor);
            }

            // ...

            int res;
            synchronized (mService.mGlobalLock) {
                // ...

                try {
                    // 2.执行activity启动请求
                    res = executeRequest(mRequest);
                } finally {
                    mRequest.logMessage.append(" result code=").append(res);
                    // 执行完启动 Activity 的请求后,就会输出著名的 START u0 的 log
                    Slog.i(TAG, mRequest.logMessage.toString());
                    mRequest.logMessage.setLength(0);
                }

                // ...

                return getExternalResult(res);
            }
        } finally {
            onExecutionComplete();
        }
    }

根据注释所说,这一步主要就是解析一些必要信息,例如 Activity 信息,然后执行请求。

// ActivityStarter.java

/**
 * Executing activity start request and starts the journey of starting an activity. Here
 * begins with performing several preliminary checks. The normally activity launch flow will
 * go through {@link #startActivityUnchecked} to {@link #startActivityInner}.
 */
private int executeRequest(Request request) {

    // ...

    // 构造 START u0 的 log
    if (err == ActivityManager.START_SUCCESS) {
        request.logMessage.append("START u").append(userId).append(" {")
                .append(intent.toShortString(true, true, true, false))
                .append("} with ").append(launchModeToString(launchMode))
                .append(" from uid ").append(callingUid);
        if (callingUid != realCallingUid
                && realCallingUid != Request.DEFAULT_REAL_CALLING_UID) {
            request.logMessage.append(" (realCallingUid=").append(realCallingUid).append(")");
        }
    }   

    // ...


    // 创建 ActivityRecord
    final ActivityRecord r = new ActivityRecord.Builder(mService)
            .setCaller(callerApp) // 指向 launcher 进程
            .setLaunchedFromPid(callingPid)
            .setLaunchedFromUid(callingUid)
            .setLaunchedFromPackage(callingPackage) // com.android.launcher
            .setLaunchedFromFeature(callingFeatureId) // null
            .setIntent(intent)
            .setResolvedType(resolvedType) // null
            .setActivityInfo(aInfo)
            .setConfiguration(mService.getGlobalConfiguration()) // 使用 global config
            .setResultTo(resultRecord) // null
            .setResultWho(resultWho) // null
            .setRequestCode(requestCode) // -1
            .setComponentSpecified(request.componentSpecified) // false
            .setRootVoiceInteraction(voiceSession != null) // false
            .setActivityOptions(checkedOptions) // 这个就是启动 Activity 传入的 Bundle 参数
            .setSourceRecord(sourceRecord) // launcher
            .build();

    // mLastStartActivityRecord 保存最近一次启动的activity
    mLastStartActivityRecord = r;

    // ...

    // 以 ActivityRecord 为参数,继续执行启动
    mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
            request.voiceInteractor, startFlags, checkedOptions,
            inTask, inTaskFragment, balCode, intentGrants, realCallingUid);

    // ...

    return mLastStartActivityResult;
}

这一步做了启动前的检查,然后创建 ActivityRecord,最后以 ActivityRecord 为参数,继续执行 Activity 启动。

// ActivityStarter.java

/**
 * Start an activity while most of preliminary checks has been done and caller has been
 * confirmed that holds necessary permissions to do so.
 * Here also ensures that the starting activity is removed if the start wasn't successful.
 */
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, ActivityOptions options, Task inTask,
        TaskFragment inTaskFragment, @BalCode int balCode,
        NeededUriGrants intentGrants, int realCallingUid) {
    int result = START_CANCELED;
    final Task startedActivityRootTask;

    final TransitionController transitionController = r.mTransitionController;
    // 参加并启动 Transition
    Transition newTransition = transitionController.isShellTransitionsEnabled()
            ? transitionController.createAndStartCollecting(TRANSIT_OPEN) : null;
    
    // 从 launcher 启动 app 时,会携带一个 RemoteTranstion 数据,与桌面的远程动画相关
    RemoteTransition remoteTransition = r.takeRemoteTransition();
    
    try {
        mService.deferWindowLayout();
        
        // Transition 收集 ActivityRecord
        transitionController.collect(r);
        
        try {
            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
            
            // 执行下一步启动
            result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, options, inTask, inTaskFragment, balCode,
                    intentGrants, realCallingUid);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
            
            // 如果成功启动,会向 Wm-Shell 发起 transition 请求
            startedActivityRootTask = handleStartResult(r, options, result, newTransition,
                    remoteTransition);
        }
    } finally {
        mService.continueWindowLayout();
    }

    // 注意这段代码中关于 START_TASK_TO_FRONT 和  START_DELIVERED_TO_TOP 结果的处理,与PIP等功能有关
    postStartActivityProcessing(r, result, startedActivityRootTask);
    
    return result;
}

Transition 代表窗口动画,本文不分析,继续看 Activity 启动

// ActivityStarter.java

/**
 * Start an activity and determine if the activity should be adding to the top of an existing
 * task or delivered new intent to an existing activity. Also manipulating the activity task
 * onto requested or valid root-task/display.
 *
 * Note: This method should only be called from {@link #startActivityUnchecked}.
 */
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, ActivityOptions options, Task inTask,
        TaskFragment inTaskFragment, @BalCode int balCode,
        NeededUriGrants intentGrants, int realCallingUid) {
    // 解析并保存一些初始状态,例如, mStartActivity 保存要启动的 Activity,mDoResume 解析为 true
    setInitialState(r, options, inTask, inTaskFragment, startFlags, sourceRecord,
            voiceSession, voiceInteractor, balCode, realCallingUid);
    
    // ...
    
    // app 冷启动,是需要新建 Task,所以这里是找不到可以直接使用的 Task
    // null
    final Task reusedTask = resolveReusableTask(includeLaunchedFromBubble);
    // ...
    // null
    final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
    // true
    final boolean newTask = targetTask == null;
    // null
    mTargetTask = targetTask;
    // ...
    // null
    final ActivityRecord targetTaskTop = newTask
            ? null : targetTask.getTopNonFinishingActivity();
    if (targetTaskTop != null) {
        // ...
    } else {
        // 需要把 ActivityRecord 添加到 Task
        mAddingToTask = true;
    }
    
    // ...
    
    if (mTargetRootTask == null) {
        // 1. 创建 root task ,并且作为 top child 保存到 TaskDisplayArea 下
        mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, targetTask,
                mOptions);
    }
    
    if (newTask) {
        // null
        final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
                ? mSourceRecord.getTask() : null;
        // 2. root task 作为 leaf task,把 ActivityRecord 当做 top child 保存
        setNewTask(taskToAffiliate);
    } else if (mAddingToTask) {
        // ...
    }
    
    // ...
    
    final Task startedTask = mStartActivity.getTask();
    if (newTask) {
        // 创建 task 的 event log : wm_create_task
        EventLogTags.writeWmCreateTask(mStartActivity.mUserId, startedTask.mTaskId,
                startedTask.getRootTaskId(), startedTask.getDisplayId());
    }
    
    // 启动 Activity 的 event log : wm_create_activity
    mStartActivity.logStartActivity(EventLogTags.WM_CREATE_ACTIVITY, startedTask);
    
    // ...
    
    // true
    final boolean isTaskSwitch = startedTask != prevTopTask;
    // 3. 调度添加启动窗口
    mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch,
            mOptions, sourceRecord);
    
    // 前面解析了 mDoResume 为 true
    if (mDoResume) {
        // 这个就是要启动的 Activity
        final ActivityRecord topTaskActivity = startedTask.topRunningActivityLocked();
        if (!mTargetRootTask.isTopActivityFocusable()
                || (topTaskActivity != null && topTaskActivity.isTaskOverlay()
                && mStartActivity != topTaskActivity)) {
            // ...
        } else {
            // mTargetRootTask 目前已经是 top focused task
            if (!mAvoidMoveToFront && mTargetRootTask.isTopActivityFocusable()
                    && !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {
                // ... 
            }
            // 4. ActivityRecord 的窗口层级已经构建成功,现在由 RWC 来执行下一步启动
            // 最后一个参数 mTransientLaunch 来自于 mOptions 的解析 KEY_TRANSIENT_LAUNCH,
            // 这里它的值为 false,表示需要等待后台 Tasks 暂停完成后,才能执行 Activity 的启动。
            mRootWindowContainer.resumeFocusedTasksTopActivities(
                    mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
        }
    }
    
    
    // ...
    return START_SUCCESS;
}

这一步主要是为了构建窗口层级树,首先介绍下窗口层级树

graph TD
RootWindowContainer --> DisplayContent
DisplayContent --> DislayArea1
DisplayContent --> DislayArea
DisplayContent --> DislayArea2
DislayArea --> TaskDisplayArea
TaskDisplayArea --> Task
Task --> ActivityRecord
ActivityRecord --> WindowState

RootWindowContainer 是树的根,DisplayContent 代表一个屏幕,DisplayArea 管理 DisplayContent 下某些层级的区域,TaskDisplayArea 用来管理 Task,Task 保存代表 Activity 的 ActivityRecord,ActivityRecord 保存代表窗口的 WindowState。

这一步构建窗口层级的过程如下

  1. 创建 root Task,并以 top child 保存到 TaskDisplayArea 下。什么是 root Task ? 它的 parent 不是 Task,那么它就是 root task。
  2. root Task 作为 leaf Task,把 ActivityRecord 作为 top child 进行保存。什么是 leaf Task ? 其实 Task 下面也可以保存子 Task,子 Task 下面如果没有 Task,那么子 Task 就是 leaf Task。
  3. 调度添加启动窗口。对于 app 冷启动来说,我们经常会看到一个只显示 app 图标的页面,它就是启动窗口。
  4. 窗口层级构建完成后,通过层级树的根 RootWindowContainer 来执行下一步的 Activity 启动。

经过这一步之后,窗口层级树如下

graph TD
RootWindowContainer --> DisplayContent
DisplayContent --> DislayArea1
DisplayContent --> DislayArea
DisplayContent --> DislayArea2
DislayArea --> TaskDisplayArea
TaskDisplayArea --> Task
Task --> ActivityRecord
ActivityRecord --> WindowState
TaskDisplayArea --> Task1
Task1 --> ActivityRecord1

其中,Task1 是新建的 Task,ActivityRecord1 就是要启动的 Activity。注意,ActivityRecord1 下还没有 WindowState,因为现在还没有创建窗口。

RootWindowContainer

窗口层级构建完成后,现在由 RootWindowContainer 来启动 Activity

// RootWindowContainer.java

// targetRootTask 就是要启动 activity 的 root task
// target 就是要启动的 activity
// targetOptions 是 start activity 的参数
// deferPause 为 false
boolean resumeFocusedTasksTopActivities(
        Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,
        boolean deferPause) {
    if (!mTaskSupervisor.readyToResume()) {
        return false;
    }
    boolean result = false;
    
    // targetRootTask 是作为 top child 保存在 TDA 下,因此它现在就是 top root task
    if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()
            || getTopDisplayFocusedRootTask() == targetRootTask)) {
        // 由 root task resume top activity
        result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,
                deferPause);
    }

    // ...
}

RootWindowContainer 让 top root task 来 resume top activity

// Task.java

/**
 * Ensure that the top activity in the root task is resumed.
 *
 * @param prev The previously resumed activity, for when in the process
 * of pausing; can be null to call from elsewhere.
 * @param options Activity options.
 * @param deferPause When {@code true}, this will not pause back tasks.
 *
 */
// 参数 prev 此时就是要启动的 activity
// 参数 deferPause 为 false
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options,
        boolean deferPause) {

    // ...

    boolean someActivityResumed = false;
    try {
        // Protect against recursion.
        mInResumeTopActivity = true;

        if (isLeafTask()) { // leaf Task
            if (isFocusableAndVisible()) { // top activity 可以获焦,并且 task 处于 top,需要可见
                // root task 作为 leaf Task 来 resume top activity
                someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause);
            }
        } else {
            // ... 
        }

        // ...
    } finally {
        mInResumeTopActivity = false;
    }
    return someActivityResumed;
}

对于本案例来说,要启动的 Activity 的 leaf task 就是 root task。所以,这里 root task 可以作为 leaf task 来 resume top activity。

// Task.java

// prev 是要启动的 activity
// options 是启动 activity 的参数
// deferPause 为 false
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options,
        boolean deferPause) {
    if (!mAtmService.isBooting() && !mAtmService.isBooted()) {
        return false;
    }
    
    //获取 Task 的 top-focusable-non-finishing-activty
    final ActivityRecord topActivity = topRunningActivity(true /* focusableOnly */);

    if (topActivity == null) {
        // ...
    }

    final boolean[] resumed = new boolean[1];

    final TaskFragment topFragment = topActivity.getTaskFragment();
    // 由 top activity 的 TaskFragment 来启动 top activity
    resumed[0] = topFragment.resumeTopActivity(prev, options, deferPause);
    
    // 看看其他 TaskFragment 是否能 resume top activity
    forAllLeafTaskFragments(f -> {
        // ...
    }, true);
    return resumed[0];
}

Task 本身就是继承自 TaskFragment,因此 TaskFragment 可以作为 Task 的 child。对于本案例来说,leaf task 下是没有子 TaskFragment 的,因此 ActivityRecord 的 TaskFragment 就是 leaf task ,也是 root task。

现在,leaf task 交给 ActivityRecord 的 TaskFragment 来 resume top activity。

// TaskFragment.java

// prev 就是要启动的 activity
// deferPause 为 false
final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,
        boolean deferPause) {
    // 获取 top-focusable-non-finishing-activity,其实就是要启动的 activity
    ActivityRecord next = topRunningActivity(true /* focusableOnly */);
    
    // ...

    // 如果当前有 Actvity 正在暂停,那么不启动 Activity 了
    // If we are currently pausing an activity, then don't do anything until that is done.
    final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();
    if (!allPausedComplete) {
        ProtoLog.v(WM_DEBUG_STATES,
                "resumeTopActivity: Skip resume: some activity pausing.");
        return false;
    }

    final TaskDisplayArea taskDisplayArea = getDisplayArea();

    // Task 才刚刚创建,mResumedActivity 和 mLastPausedActivity 都为 null
    if (mResumedActivity == next && next.isState(RESUMED)
            && taskDisplayArea.allResumedActivitiesComplete()) {
        // ....
        return false;
    }
    if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) {
        // ...
        return false;
    }

    // ...

    // 1.暂停后台 Task
    // 此时 deferPause 为 false,表示不能推迟暂停后台 tasks
    // 只要有一个后台 Task 正在暂停,那么返回 true
    boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);

    if (mResumedActivity != null) {
        // ...
    }

    if (pausing) { // 有后台 Task 正在暂停
        ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: need to"
                + " start pausing");
                
        if (next.attachedToProcess()) { // 此时还没有进程
            // ...
        } else if (!next.isProcessRunning()) {
            // Since the start-process is asynchronous, if we already know the process of next
            // activity isn't running, we can start the process earlier to save the time to wait
            // for the current activity to be paused.
            final boolean isTop = this == taskDisplayArea.getFocusedRootTask();
            // 2. 由于有后台 Task 正在暂停,因此不能立即 start activity,但是可以先拉起进程
            mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,
                    isTop ? HostingRecord.HOSTING_TYPE_NEXT_TOP_ACTIVITY
                            : HostingRecord.HOSTING_TYPE_NEXT_ACTIVITY);
        }
        
        // 注意,这里就结束了
        return true;
    } else if (mResumedActivity == next && next.isState(RESUMED)
            && taskDisplayArea.allResumedActivitiesComplete()) {
        // ...
    }
    
    // ...
}

TaskFragment 先暂停后台 Tasks,如果有 Task 正在被暂停,那么不能启动 Activity,但是可以先拉起 app 进程。

暂停后台 Tasks

所有的 Task 都由 TaskDisplayArea 管理,因此暂停后台 Tasks 的任务,当然是交给 TaskDisplayArea 来处理。对于本文分析的案例,此时需要暂停的后台 Tasks 只有 Launcher Task。

// TaskDisplayArea.java

boolean pauseBackTasks(ActivityRecord resuming) {
    final int[] someActivityPaused = {0};
    
    // 由 leaf task 来暂停 activity
    forAllLeafTasks(leafTask -> {
        if (leafTask.pauseActivityIfNeeded(resuming, "pauseBackTasks")) {
            someActivityPaused[0]++;
        }
    }, true /* traverseTopToBottom */);
    
    return someActivityPaused[0] > 0;
}
// Task.java

boolean pauseActivityIfNeeded(@Nullable ActivityRecord resuming, @NonNull String reason) {
    if (!isLeafTask()) {
        return false;
    }

    final int[] someActivityPaused = {0};

    if (!isLeafTaskFragment()) {
        
    }

    // 遍历所有的 leaf TaskFragment
    forAllLeafTaskFragments((taskFrag) -> {
        // 获取 resumed activity
        final ActivityRecord resumedActivity = taskFrag.getResumedActivity();
        
        // TaskFragment 暂停后台 Task,是有条件的
        // 一是它必须有一个 resumed activity,二是要启动的 ActivityRecord 不属于它
        if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) {
        
            // 由 TaskFragment 来处理暂停
            if (taskFrag.startPausing(false /* uiSleeping*/, resuming, reason)) {
                someActivityPaused[0]++;
            }
        }
    }, true /* traverseTopToBottom */);

    return someActivityPaused[0] > 0;
}

TaskDisplayArea 把暂停后台 Tasks 的任务,交给所有的 leaf task,而 leaf task 把任务交给所有的 leaf TaskFragment。

// TaskFragment.java

final boolean startPausing(boolean uiSleeping, ActivityRecord resuming, String reason) {
    return startPausing(mTaskSupervisor.mUserLeaving, uiSleeping, resuming, reason);
}

// userLeaving 为 true
// uiSleeping 为 false
// resuming 就是要启动的 activity
// reason 为 pauseBackTasks
boolean startPausing(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming,
        String reason) {
    if (!hasDirectChildActivities()) {
        return false;
    }

    ProtoLog.d(WM_DEBUG_STATES, "startPausing: taskFrag =%s " + "mResumedActivity=%s", this,
            mResumedActivity);

    if (mPausingActivity != null) {
        
    }
    
    ActivityRecord prev = mResumedActivity;

    if (prev == null) {
        
    }

    if (prev == resuming) {
        
    }

    ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSING: %s", prev);
    
    // 标记正在暂停的 activity
    // 这个就是 TaskFragment 当前的 resumed activity
    mPausingActivity = prev;
    
    // Activity还没有完成暂停呢,此时就标记为已暂停 Activity ???
    mLastPausedActivity = prev;
    
    if (!prev.finishing && prev.isNoHistory()
            && !mTaskSupervisor.mNoHistoryActivities.contains(prev)) {
        
    }
    
    // 1. resumed ActivityRecord 生命周期切换到 PAUSING 状态
    // 与此同时, TaskFragment 还会清空 mResumedActivity
    prev.setState(PAUSING, "startPausingLocked");
    
    // ...

    boolean pauseImmediately = false;
    boolean shouldAutoPip = false;
    if (resuming != null) {
        // ...
        
        if (prev.supportsEnterPipOnTaskSwitch && userLeaving
                && resumingOccludesParent && lastResumedCanPip
                && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
            // ...
        } else if (!lastResumedCanPip) {
            // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous
            // activity to be paused.
            // FLAG_RESUME_WHILE_PAUSING 表示不用等到 app 暂停完成,就可以继续启动 activity
            // 此时不涉及
            pauseImmediately = (resuming.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
        } else {
            
        }
    }

    if (prev.attachedToProcess()) {
        if (shouldAutoPip && ActivityTaskManagerService.isPip2ExperimentEnabled()) {
            // ...
        } else if (shouldAutoPip) {
            // ...
        } else {
            // 2.通知 app 端暂停 activity
            schedulePauseActivity(prev, userLeaving, pauseImmediately,
                    false /* autoEnteringPip */, reason);
        }
    } else {
        // ...
    }

    // ...

    // If already entered PIP mode, no need to keep pausing.
    if (mPausingActivity != null) {
        if (!uiSleeping) {
            // 暂停事件分发
            prev.pauseKeyDispatchingLocked();
        } else {
            // ...
        }

        
        if (pauseImmediately) { // 本案例不走这里
            // If the caller said they don't want to wait for the pause, then complete
            // the pause now.
            completePause(false, resuming);
            // 注意,这里返回 false,代表即使有 Task 正在暂停,也可以继续启动 Activity
            return false;

        } else {
            // app 反馈暂停完成也有超时时间限制
            prev.schedulePauseTimeout();
            
            // All activities will be stopped when sleeping, don't need to wait for pause.
            if (!uiSleeping) {
                // 强制设置 transition ready 为 false
                // Unset readiness since we now need to wait until this pause is complete.
                mTransitionController.setReady(this, false /* ready */);
            }
            return true;
        }

    } else {
        // ...
    }
}

暂停后台 Task,最终由 TaskFragment 来完成,它把其下状态为 RESUMED 的 ActivityRecord 的生命周期状态切换到 PAUSING,然后通知 app 端去 pause activity,最后它会等待 app 端反馈 activity paused 完成。

小结

第一阶段启动,主要做了如下事情

  1. 创建 ActivityRecord 和 Task,并构建窗口层级。
  2. 创建 OPEN Transition,收集了存在性改变的 ActivityRecord 和 Task。
  3. 暂停后台 Tasks。
  4. 拉起 app 进程。
  5. 向 WMShell 发起 transition request。

第二阶段启动

app 端完成 activity paused 后,会通知服务端,服务端会再尝试启动 Activity,我称之为第二阶段启动

// ActivityClientController.java

public void activityPaused(IBinder token) {
    final long origId = Binder.clearCallingIdentity();
    synchronized (mGlobalLock) {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityPaused");
        
        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
        if (r != null) {
            // 由对应的 ActvityRecord 处理 activity paused
            r.activityPaused(false);
        }
        
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }
    Binder.restoreCallingIdentity(origId);
}
// ActivityRecord.java

void activityPaused(boolean timeout) {
    ProtoLog.v(WM_DEBUG_STATES, "Activity paused: token=%s, timeout=%b", token,
            timeout);

    final TaskFragment taskFragment = getTaskFragment();
    if (taskFragment != null) {
        removePauseTimeout();

        final ActivityRecord pausingActivity = taskFragment.getPausingActivity();
        if (pausingActivity == this) {
            ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSED: %s %s", this,
                    (timeout ? "(due to timeout)" : " (pause complete)"));
                    
            mAtmService.deferWindowLayout();
            
            try {
                // taskFragment 执行 complete pause
                // 第一个参数 resumeNext 为 true,表示需要继续执行 activity 启动
                taskFragment.completePause(true /* resumeNext */, null /* resumingActivity */);
            } finally {
                // 由于有 activity 可见性更新,因此 continue layout 会发起窗口刷新
                mAtmService.continueWindowLayout();
            }
            
            return;
        } else {
            // ...
        }
    }

    // ...
}
// TaskFragment.java

// resumeNext 为 true
// resuming 为 null
void completePause(boolean resumeNext, ActivityRecord resuming) {

    ActivityRecord prev = mPausingActivity;
    ProtoLog.v(WM_DEBUG_STATES, "Complete pause: %s", prev);

    if (prev != null) {
        prev.setWillCloseOrEnterPip(false);
        prev.supportsEnterPipOnTaskSwitch = false;
        final boolean wasStopping = prev.isState(STOPPING);
        // 1. 更新 pausing activity 的声明周期状态为 PAUSED
        prev.setState(PAUSED, "completePausedLocked");
        mPausingActivity = null;
        // ...
    }

    if (resumeNext) {
        final Task topRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
        if (topRootTask != null && !topRootTask.shouldSleepOrShutDownActivities()) {
            // 2. RWC resume top activity of top roo task
            mRootWindowContainer.resumeFocusedTasksTopActivities(topRootTask, prev);
        } else {
            // ...
        }
    }

    // ...

    // 3. 更新 Activity 可见性
    // 参数 resuming 为 null
    mRootWindowContainer.ensureActivitiesVisible(resuming);

    // ...
}

TaskFragment 处理 activity paused

  1. 把暂停的 ActivityRecord 状态,切换到 PAUSED。
  2. 由 RootWindowContainer resume top activity of top root task,也就是继续启动 activity。
  3. 更新所有 Activity 的可见性。这里涉及到 stop activity 生命周期流程。

RootWindowContainer 启动 activity

后台 Task 暂停完成后,由 RootWindowContainer 对 top task 执行 resume top activity,即继续执行未完成的 Activity 启动。根据前面的分析,最终是由 TaskFragment 来处理,如下

// TaskFragment.java

// prev 此时是已经完成暂停的 Launcher
// options 此时为 null
// skipPause 此时为 false
final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,
        boolean skipPause) {
    
    // 简单来说,就是获取 top-non-finishing ActivityReocrd
    ActivityRecord next = topRunningActivity(true /* focusableOnly */);
    
    // ...

    // 根据 next 是否绑定到进程,决定启动方式
    if (next.attachedToProcess()) {
        //  ...
    } else {
        // ...
        
        ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Restarting %s", next);
        mTaskSupervisor.startSpecificActivity(next, true, true);
    }

    return true;
}

fork app 进程并启动 app,是一个比较耗时的过程,它所需的时间,是大于暂停 activity 的时间的。

因此,此次由 activity paused 触发的 Activity 启动,不得不继续拉起进程,即使拉起进程正在进行中,如下

// ActivityTaskSupervisor.java

void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
    // Is this activity's application already running?
    // 进程还没有起来呢
    final WindowProcessController wpc =
            mService.getProcessController(r.processName, r.info.applicationInfo.uid);

    boolean knownToBeDead = false;
    if (wpc != null && wpc.hasThread()) {
        // ...
    }

    r.notifyUnknownVisibilityLaunchedForKeyguardTransition();

    final boolean isTop = andResume && r.isTopRunningActivity();
    // 继续拉起进程
    mService.startProcessAsync(r, knownToBeDead, isTop,
            isTop ? HostingRecord.HOSTING_TYPE_TOP_ACTIVITY
                    : HostingRecord.HOSTING_TYPE_ACTIVITY);
}

很不幸,由于 app 进程还在启动中,第二阶段启动,仍然无法真正启动 Activity。

更新 ActivityRecord 可见性

在处理 Launcher Activity paused 时,RWC 执行完 resume top activity 后,会更新 activity 可见性,如下

// TaskFragment.java

// resumeNext 为 true
// resuming 为 null
void completePause(boolean resumeNext, ActivityRecord resuming) {

    ActivityRecord prev = mPausingActivity;
    ProtoLog.v(WM_DEBUG_STATES, "Complete pause: %s", prev);

    if (prev != null) {
        prev.setWillCloseOrEnterPip(false);
        prev.supportsEnterPipOnTaskSwitch = false;
        final boolean wasStopping = prev.isState(STOPPING);
        // 1. 更新 pausing activity 的声明周期状态为 PAUSED
        prev.setState(PAUSED, "completePausedLocked");
        mPausingActivity = null;
        // ...
    }

    if (resumeNext) {
        final Task topRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
        if (topRootTask != null && !topRootTask.shouldSleepOrShutDownActivities()) {
            // 2. RWC resume top activity of top roo task
            mRootWindowContainer.resumeFocusedTasksTopActivities(topRootTask, prev);
        } else {
            // ...
        }
    }

    // ...

    // 3. 更新 Activity 可见性
    // 参数 resuming 为 null
    mRootWindowContainer.ensureActivitiesVisible(resuming);

    // ...
}

为何要更新 Activity 可见性?有2个原因

  1. 此时 Launcher ActivityRecord 已经完成暂停,它即将不可见,因此需要更新它的不可见性。
  2. 要启动的 ActivityRecord,即将可见,因此需要更新它的可见性。

RWC 更新 Activity 可见性的调用链很长,它的原理是遍历所有 leaf task,让其完成可见性更新,如下

// TaskFragment.java

final void updateActivityVisibilities(@Nullable ActivityRecord starting,
        boolean notifyClients) {
    mTaskSupervisor.beginActivityVisibilityUpdate();
    try {
        mEnsureActivitiesVisibleHelper.process(starting, notifyClients);
    } finally {
        mTaskSupervisor.endActivityVisibilityUpdate();
    }
}
// EnsureActivitiesVisibleHelper.java

// starting 为 null
// notifyClients 为 true
void process(@Nullable ActivityRecord starting, boolean notifyClients) {
    reset(starting, notifyClients);

    if (DEBUG_VISIBILITY) {
        Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + mTopRunningActivity);
    }
    
    // ...

    final boolean resumeTopActivity = mTopRunningActivity != null
            && !mTopRunningActivity.mLaunchTaskBehind
            && mTaskFragment.canBeResumed(starting)
            && (starting == null || !starting.isDescendantOf(mTaskFragment));

    ArrayList<TaskFragment> adjacentTaskFragments = null;
    // 从上到下遍历 TaskFragment 的 children
    for (int i = mTaskFragment.mChildren.size() - 1; i >= 0; --i) {
        final WindowContainer child = mTaskFragment.mChildren.get(i);
        final TaskFragment childTaskFragment = child.asTaskFragment();
        if (childTaskFragment != null
                && childTaskFragment.getTopNonFinishingActivity() != null) {
            // ..
        } else if (child.asActivityRecord() != null) {
            // 设置 ActivityRecord 可见性
            setActivityVisibilityState(child.asActivityRecord(), starting, resumeTopActivity);
        }
    }
}

EnsureActivitiesVisibleHelper 会针对 Task 的 ActivityRecord ,设置可见性

// EnsureActivitiesVisibleHelper.java

private void setActivityVisibilityState(ActivityRecord r, ActivityRecord starting,
        final boolean resumeTopActivity) {
    // ...

    if (reallyVisible) { // 一般来说,只有 top task 的 top activity 才需要可见
        if (r.finishing) {
            return;
        }
        if (DEBUG_VISIBILITY) {
            Slog.v(TAG_VISIBILITY, "Make visible? " + r
                    + " finishing=" + r.finishing + " state=" + r.getState());
        }
        
        // 当前要启动的 ActivityRecord 还处于 INITIALING 状态,因此这里不会更新配置
        if (r != mStarting && mNotifyClients) {
            r.ensureActivityConfiguration(true /* ignoreVisibility */);
        }

        if (!r.attachedToProcess()) { // ActivityRecord 没有绑定到进程的情况
            // 1. ActivityRecord设置可见,并且尝试拉起进程
            makeVisibleAndRestartIfNeeded(mStarting, resumeTopActivity && isTop, r);
        } else if (r.isVisibleRequested()) { // ActivityRecord 已经请求可见
            
        } else { // ActivityRecord 绑定到进程,并且请求可见为 false
            r.makeVisibleIfNeeded(mStarting, mNotifyClients);
        }
    } else { // 一般来说,top task 之下的 task 的 activity 都不可见
        if (DEBUG_VISIBILITY) {
            Slog.v(TAG_VISIBILITY, "Make invisible? " + r
                    + " finishing=" + r.finishing + " state=" + r.getState()
                    + " containerShouldBeVisible=" + mContainerShouldBeVisible
                    + " behindFullyOccludedContainer=" + mBehindFullyOccludedContainer
                    + " mLaunchTaskBehind=" + r.mLaunchTaskBehind);
        }
        // 2. 设置不可见
        r.makeInvisible();
    }

    // ...
}

如何判断 ActivityRecord 是否可见,有点复杂,本文不展示。简单来说,top task 下的 non-finishing ActivityRecord 是需要可见,top task 下的 task 的 AcivityRecord 都不可见。

对于本案例来说,app task 的 ActivityRecord 要更新可见,Launcher ActivityRecord 要更新不可见。

ActivityRecord 的可见性更新,涉及到窗口动画,这里提前展示这一部分代码,是因为 launcher ActivityRecord 更新不可见,有生命周期的调度,来看下

// ActivityRecord.java

void makeInvisible() {
    if (!mVisibleRequested) {
        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + this);
        return;
    }
    // Now for any activities that aren't visible to the user, make sure they no longer are
    // keeping the screen frozen.
    if (DEBUG_VISIBILITY) {
        Slog.v(TAG_VISIBILITY, "Making invisible: " + this + ", state=" + getState());
    }
    try {
        final boolean canEnterPictureInPicture = checkEnterPictureInPictureState(
                "makeInvisible", true /* beforeStopping */);
        // Defer telling the client it is hidden if it can enter Pip and isn't current paused,
        // stopped or stopping. This gives it a chance to enter Pip in onPause().
        final boolean deferHidingClient = canEnterPictureInPicture
                && !isState(STARTED, STOPPING, STOPPED, PAUSED);
        setDeferHidingClient(deferHidingClient);
        
        // 1. 设置可见性为 false
        setVisibility(false);

        switch (getState()) {
            // ...
            case PAUSED:
            // ...
            case STARTED:
                // 2. 保存到 stopping list,并调度执行 stopping 生命周期流程
                addToStopping(true /* scheduleIdle */,
                        canEnterPictureInPicture /* idleDelayed */, "makeInvisible");
                break;

            default:
                break;
        }
    } // ...
}

Launcher ActivityRecord 此时的生命周期状态为 PAUSED,现在要把它加入到 stopping list 中,为后续执行 stopping activity 做准备,如下

// ActivityRecord.java

// scheduleIdle 为 true
// idleDelayed 为 false
// reason 为 makeInvisible
void addToStopping(boolean scheduleIdle, boolean idleDelayed, String reason) {

    // 1. 加入到 mTaskSupervisor.mStoppingActivities 列表中
    if (!mTaskSupervisor.mStoppingActivities.contains(this)) {
        EventLogTags.writeWmAddToStopping(mUserId, System.identityHashCode(this),
                shortComponentName, reason);
        mTaskSupervisor.mStoppingActivities.add(this);
    }

    final Task rootTask = getRootTask();
    boolean forceIdle = mTaskSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE
            || (isRootOfTask() && rootTask.getChildCount() <= 1);
    
    // scheduleIdle 此时为 true
    if (scheduleIdle || forceIdle) {
        ProtoLog.v(WM_DEBUG_STATES,
                "Scheduling idle now: forceIdle=%b immediate=%b", forceIdle, !idleDelayed);
        
        // idleDelayed 此时为 false
        if (!idleDelayed) {
            // 2.调度 idle
            // 会执行 ActivityTaskSupervisor#activityIdleInterna()
            mTaskSupervisor.scheduleIdle();
        } else {
            // ...
        }
    } else {
        // ...
    }
}

此时进入把 launcher ActivityRecord 加入到 stopping list ,并没有直接执行 stopping activity 流程,而是通过 Handler 发送 idle 消息去执行,Google 这样设计是有一定的考量的。

当 idle 消息被执行时,会先检测状态,如果满足,才能真正执行 stopping activity 流程,如下

// ActivityTaskSupervisor.java

void activityIdleInternal(ActivityRecord r, boolean fromTimeout,
        boolean processPausingActivities, Configuration config) {
    if (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + r);

    if (r != null) {
        // ...
    }

    // 所有 resumed activity 必须处于 idle 状态
    if (mRootWindowContainer.allResumedActivitiesIdle()) {
        // ...
    }

    // 处理 stopping activity 或者 finishing activity
    processStoppingAndFinishingActivities(r, processPausingActivities, "idle");

    if (DEBUG_IDLE) {
        Slogf.i(TAG, "activityIdleInternal(): r=%s, mStartingUsers=%s", r, mStartingUsers);
    }

    // ...
}
// ActivityRecord.java

void processStoppingAndFinishingActivities(ActivityRecord launchedActivity,
        boolean processPausingActivities, String reason) {

    boolean displaySwapping = false;
    // 处理 stopping activity
    ArrayList<ActivityRecord> readyToStopActivities = null;
    for (int i = 0; i < mStoppingActivities.size(); i++) {
        final ActivityRecord s = mStoppingActivities.get(i);
        
        
        // 是否处于 transition 动画
        final boolean animating = s.isInTransition()
                && s.getTask() != null && !s.getTask().isForceHidden();
                
        displaySwapping |= s.isDisplaySleepingAndSwapping();
        
        ProtoLog.v(WM_DEBUG_STATES, "Stopping %s: nowVisible=%b animating=%b "
                + "finishing=%s", s, s.nowVisible, animating, s.finishing);
                
        // 不处于 transition 动画,才可以把 ActivityRecord 从 mStoppingActivities 移除
        // 并保存到 readyToStopActivities
        if ((!animating && !displaySwapping) || mService.mShuttingDown
                || s.getRootTask().isForceHiddenForPinnedTask()) {
            if (!processPausingActivities && s.isState(PAUSING)) {

            }

            ProtoLog.v(WM_DEBUG_STATES, "Ready to stop: %s", s);
            
            if (readyToStopActivities == null) {
                readyToStopActivities = new ArrayList<>();
            }
            readyToStopActivities.add(s);

            mStoppingActivities.remove(i);
            i--;
        }
    }


    if (displaySwapping) {
       
    }

    // 让 readyToStopActivities 中的 Actvity 进入 stop 流程
    final int numReadyStops = readyToStopActivities == null ? 0 : readyToStopActivities.size();
    for (int i = 0; i < numReadyStops; i++) {
        final ActivityRecord r = readyToStopActivities.get(i);
        if (r.isInHistory()) {
            if (r.finishing) {
                
            } else {
                // 通知 app stop activity
                r.stopIfPossible();
            }
        }
    }

    // 省略处理 finishing activity 代码 ...
}

可以看出,要想真正执行 launcher activity 的 stopping activity 生命周期流程,至少要满足两个条件

  1. 要启动的 Activity,生命周期必须走到 RESUMED 状态,并且 app 端还要发送 idle 状态。
  2. 窗口的 Transition 动画必须结束。

小结

第二阶段启动,始于 app 端通知服务端 activity paused 完成。但是,由于 app 进程还在启动中,因此仍然无法完成 activity 的启动。

但是,对于 Transition 动画来说,第二阶段启动还包含 ActivityRecord 可见性更新,其中 app ActivityRecord 可见性被更新为 true,Launcher ActivityRecord 的可见性被更新为 false。

第三阶段启动

当 app 进程起来后,它与服务端交互时,也会让服务端再去启动还未完成启动的 Activity。

由于 app 进程的启动,是一个异步过程,因此,我称之为第三阶段启动。

// ActivityThread.java

public static void main(String[] args) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
    // ...
    Looper.prepareMainLooper();
    // ...
    // 创建 ActivityThread,并调用它的 attach() 
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
    // ...
    
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

private void attach(boolean system, long startSeq) {
    // ..

    if (!system) {
        final IActivityManager mgr = ActivityManager.getService();
        try {
            // 1. attach application
            // mAppThread 是一个 binder 回调,在服务端代表 app 进程
            mgr.attachApplication(mAppThread, startSeq);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }

        // ...
    } else {
        // ...
    }

    // ...
}    

ActivityThreaad#main() 最终就是向服务端注册一个 Binder 回调,这就是所谓的 attach application。

// ActivityManagerService.java

public final void attachApplication(IApplicationThread thread, long startSeq) {
    if (thread == null) {
        throw new SecurityException("Invalid application interface");
    }
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid, callingUid, startSeq);
        Binder.restoreCallingIdentity(origId);
    }
}

private void attachApplicationLocked(@NonNull IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
    // ...

    if (pid != MY_PID && pid >= 0) {
        synchronized (mPidsSelfLocked) {
            // 进程创建的时候,会保存到 mPidsSelfLocked
            app = mPidsSelfLocked.get(pid);
        }
        if (app != null && (app.getStartUid() != callingUid || app.getStartSeq() != startSeq)) {
            // ...
        }
    } else {
        // ...
    }

    // ...

    EventLogTags.writeAmProcBound(app.userId, pid, app.processName);

    // ...

    try {
        // ...

        if (app.getIsolatedEntryPoint() != null) {
            // ....
        } else if (instr2 != null) {
            // ...
        } else {
            // 1. 通知 app 进行 bind application
            thread.bindApplication(processName, appInfo,
                    app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
                    providerList, null, profilerInfo, null, null, null, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.isPersistent(),
                    new Configuration(app.getWindowProcessController().getConfiguration()),
                    app.getCompat(), getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial, autofillOptions, contentCaptureOptions,
                    app.getDisabledCompatChanges(), serializedSystemFontMap,
                    app.getStartElapsedTime(), app.getStartUptime());
        }
        
        // ...

        synchronized (mProcLock) {
            // 2. 进程与 app 端绑定
            // 进程实例 ProcessRecord 保存 app 端传入的回调 IApplicationThread 对象
            app.makeActive(thread, mProcessStats);
            checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
        }
        
        // ... 

        // mConstants.mEnableWaitForFinishAttachApplication 默认为 false
        // 如果为 true,表示需要等待 app 完成 bind application 之后,才执行 finish attach application 操作
        if (!mConstants.mEnableWaitForFinishAttachApplication) {
            // 3. finish attach app
            // 四大组件中如果有等待进程启动的,此时就可以启动组件
            finishAttachApplicationInner(startSeq, callingUid, pid);
        } else {
            // ...
        }
    } catch (Exception e) {
        // ...
    }
}

attach application 会执行 finish attach application,而这个过程会再次启动未完成启动的 Activity。

// ActivityManagerService.java

private void finishAttachApplicationInner(long startSeq, int uid, int pid) {
    final ProcessRecord app;
    synchronized (mPidsSelfLocked) {
        // 获取进程实例 ProcessRecord
        app = mPidsSelfLocked.get(pid);
    }
    // ...
    synchronized (this) {
        // ...

        // See if the top visible activity is waiting to run in this process...
        if (normalMode) {
            try {
                didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
            } catch (Exception e) {
                // ...
            }
        }
        // ...
    }
}
// ActivityTaskManagerService.java

public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
    synchronized (mGlobalLockWithoutBoost) {
        // attach app 的 trace
        if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "attachApplication:" + wpc.mName);
        }
        try {
            return mRootWindowContainer.attachApplication(wpc);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }
}
// RootWindowContainer.java

boolean attachApplication(WindowProcessController app) throws RemoteException {
    // 拉起app进程调用的 startProcessAsync() 中,会把要启动的 activity 保存到 mService.mStartingProcessActivities
    final ArrayList<ActivityRecord> activities = mService.mStartingProcessActivities;
    RemoteException remoteException = null;
    boolean hasActivityStarted = false;
    for (int i = activities.size() - 1; i >= 0; i--) {
        final ActivityRecord r = activities.get(i);
        
        // 省略检测是否要启动 activity 的代码 ...
        
        try {
            final boolean canResume = r.isFocusable() && r == tf.topRunningActivity();
            
            // 真正启动 activity 来了
            if (mTaskSupervisor.realStartActivityLocked(r, app, canResume,
                    true /* checkConfig */)) {
                hasActivityStarted = true;
            }
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception in new process when starting " + r, e);
            remoteException = e;
        }
    }
    if (remoteException != null) {
        throw remoteException;
    }
    return hasActivityStarted;
}
// ActivityTaskSupervisor.java

boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
        boolean andResume, boolean checkConfig) throws RemoteException {

    // ...

    try {

        // ...
        
        // checkConfig 此时为 true
        if (checkConfig) {
            // 更新 activity 可见性,以及确保 activity 能正确处理配置
            // 可见性更新,在前面执行过
            // 至于配置,ActivityRecord 还处于 INITIALING 状态,无需考虑
            mRootWindowContainer.ensureVisibilityAndConfig(r, r.mDisplayContent,
                    true /* deferResume */);
        }

        // 再次检测是否更新可见性,前面其实已经更新过可见
        if (mKeyguardController.checkKeyguardVisibility(r) && r.allowMoveToFront()) {
            // We only set the visibility to true if the activity is not being launched in
            // background, and is allowed to be visible based on keyguard state. This avoids
            // setting this into motion in window manager that is later cancelled due to later
            // calls to ensure visible activities that set visibility back to false.
            r.setVisibility(true);
        }

        // ...
        
        // 这个 binder 会发送给 app 端,app 端会利用它与服务端沟通 activity 状态
        final IActivityClientController activityClientController =
                proc.hasEverLaunchedActivity() ? null : mService.mActivityClientController;
        r.launchCount++;

        if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);

        // ...

        try {
            // ...
            
            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                    "Launching: " + r + " savedState=" + r.getSavedState()
                            + " with results=" + results + " newIntents=" + newIntents
                            + " andResume=" + andResume);
                            
            // 真正启动 activity 的 event log : wm_restart_activity
            EventLogTags.writeWmRestartActivity(r.mUserId, System.identityHashCode(r),
                    task.mTaskId, r.shortComponentName);
            
            // ...
            
            // 创建 Launch activity callback
            final LaunchActivityItem launchActivityItem = LaunchActivityItem.obtain(r.token,
                    r.intent, System.identityHashCode(r), r.info,
                    procConfig, overrideConfig, deviceId,
                    r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
                    proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
                    results, newIntents, r.takeSceneTransitionInfo(), isTransitionForward,
                    proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
                    r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken,
                    r.initialCallerInfoAccessToken, activityWindowInfo);

            // Set desired final state.
            final ActivityLifecycleItem lifecycleItem;
            if (andResume) {
                // 创建 resume 生命周期请求
                lifecycleItem = ResumeActivityItem.obtain(r.token, isTransitionForward,
                        r.shouldSendCompatFakeFocus());
            } else if (r.isVisibleRequested()) {
                
            } else {
                
            }

            // ...
            
            // 通知 app 端启动 activity,并把生命周期执行到 resume
            mService.getLifecycleManager().scheduleTransactionAndLifecycleItems(
                    proc.getThread(), launchActivityItem, lifecycleItem,
                    // Immediately dispatch the transaction, so that if it fails, the server can
                    // restart the process and retry now.
                    true /* shouldDispatchImmediately */);

            // ...

        } catch (RemoteException e) {
            
        }
    } finally {
        // ...
    }

    r.launchFailed = false;

    if (andResume && readyToResume()) {
        // 服务端执行一小部分的 resumed activity 流程
        // 剩下的流程,是在 app 端通知 activity resumed 后执行
        r.setState(RESUMED, "realStartActivityLocked");
        r.completeResumeLocked();
    } else if (r.isVisibleRequested()) {
        
    } else {
        
    }
    
    // ...

    return true;
}

ActivityTaskSupervisor#realStartActivityLocked() 正如函数名一样,真正用来启动 Activity, 其实就是通知 app 端启动 activity,并把生命周期执行到 resume,最后把要启动的 ActivityRecord 的生命周期状态执行到 RESUMED。