Activity startup process (under update)

Brief description of process

key class

Activity: An activity entrance of the application
ActivityManagerService: Coordinates and manages the four major components of Android; uniformly schedules each application process
ActivityTaskManagerService: Newly introduced in Android R, specially used to manage Activity startup, scheduling and other functions
ActivityStarter: Specially used to handle activity new Start
ActivityStartController: Based on the factory design pattern, ActivityStarter's application launcher
Task: a collection of related activities, but activities do not necessarily have to be related.
RootWindowContainer: The root container of the window container, directly manages DisplayContent
TaskDisplayArea: The parent node of all application tasks in the system, used to manage Task
ActivityTaskSupervisor: Most of the control logic during the Task startup process is completed in this class
LaunchActivityItem: Based on ClientLifecycleManager, used for proxying Passed to the application onCreate, onStart
ResumeActivityItem: Based on ClientLifecycleManager, used to proxy passed to the application onResumed
ActivityThread: manages the execution of the main thread of the application process, running in the application side process
Code location
sys/frameworks/base/services/core/java/com /android/server/am/
sys/frameworks/base/services/core/java/com/android/server/wm/

Overall process

Insert image description here

code flow

1.Launcher click the application icon

Starting from the launcher's startActivitySafely() method, various startActivity() calls in the Activity will be called , and eventually they will reach the code path
in the startActivityForResult() method : frameworks/base/core/java/android/app
/Activity.java

    @Override
    public void startActivity(Intent intent) {
    
    
        this.startActivity(intent, null);
    }

    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
    
    
        getAutofillClientController().onStartActivity(intent, mIntent);
        if (options != null) {
    
    
            startActivityForResult(intent, -1, options);
        } else {
    
    
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

Finally, the startActivityForResult method is called. Passing in -1 indicates that there is no need to obtain the result of startActivity.

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
    
    
        startActivityForResult(intent, requestCode, null);
    }

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
    
    
        if (mParent == null) {
    
    
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
    
    
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
    
    
                // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.
                mStartedActivity = true;
            }

            cancelInputsAndStartExitTransition(options);
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
    
    
            if (options != null) {
    
    
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
    
    
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

The calling mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options);method is handled by Instrumentation.
1. The Instrumentation class is mainly used to monitor the interaction between the application and the system
. 2. mMainThread, mInstrumentation, and mToken are all assigned in attach().
3. The mMainThread in the code is ActivityThread and can be understood as a process. This is the main process of the Launcher.
4. mToken is an IBinder object, a Binder agent, and an important part
of IPC in Android. 5. Obtain a reference to ApplicationThread through mMainThread. This reference is used to implement inter-process communication. Specifically, the system process where ATMS is located notifies the application process. A series of operations performed.
Code path: frameworks/base/core/java/android/app/Instrumentation.java

    @UnsupportedAppUsage
    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
    
    
        ......
        try {
    
    
            intent.migrateExtraStreamToClipData(who);
            intent.prepareToLeaveProcess(who);
            int result = ActivityTaskManager.getService().startActivity(whoThread,
                    who.getOpPackageName(), who.getAttributionTag(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()), token,
                    target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
    
    
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }

1. ActivityTaskManager.getService()Return IActivityTaskManager
2. The declaration of ActivityTaskManagerService is ActivityTaskManagerService extends IActivityTaskManager.Stub
3. So by ActivityTaskManager.getService()obtaining the ActivityTaskManagerService service agent Context.ACTIVITY_TASK_SERVICE, use Binder to call the startActivity() method of ActivityTaskManagerService. The next step is handled by the startActivityAsUser() method inside ActivityTaskManagerService.

2. Enter ActivityTaskManagerService

Through the binder mechanism, the launcher process enters ATMS. Call startActivity() code path in ActivityTaskManagerService
: frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java

    @Override
    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) {
    
    
        return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
                resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }
    
    @Override
    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) {
    
    
        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) {
    
    
        //检查包名与CallingUid是否一致
        assertPackageMatchesCallingUid(callingPackage);
        enforceNotIsolatedCaller("startActivityAsUser");
        if (Process.isSdkSandboxUid(Binder.getCallingUid())) {
    
    
            SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
                    SdkSandboxManagerLocal.class);
            if (sdkSandboxManagerLocal == null) {
    
    
                throw new IllegalStateException("SdkSandboxManagerLocal not found when starting"
                        + " an activity from an SDK sandbox uid.");
            }
            sdkSandboxManagerLocal.enforceAllowedToStartActivity(intent);
        }

        userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
                Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

        // TODO: Switch to user app stacks here.
        return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setCallingFeatureId(callingFeatureId)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setUserId(userId)
                .execute();

    }

Here we mainly look at the last sentence return
1.ActivityStartController obtains it through the getActivityStartController() method
2.ActivityStartController.obtainStarter() returns the ActivityStarter object
3. Then set the data. What is actually called is the set data method in ActivityStarter, and the data will be stored In the object mRequest of its internal class Request, the execute() method of ActivityStarter is finally called.
Code path: frameworks/base/services/core/java/com/android/server/wm/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 {
    
    
        	......

            // Add checkpoint for this shutdown or reboot attempt, so we can record the original
            // intent action and package name.
            if (mRequest.intent != null) {
    
    
                String intentAction = mRequest.intent.getAction();
                String callingPackage = mRequest.callingPackage;
                if (intentAction != null && callingPackage != null
                        && (Intent.ACTION_REQUEST_SHUTDOWN.equals(intentAction)
                                || Intent.ACTION_SHUTDOWN.equals(intentAction)
                                || Intent.ACTION_REBOOT.equals(intentAction))) {
    
    
                    ShutdownCheckPoints.recordCheckPoint(intentAction, callingPackage, null);
                }
            }

            int res;
            synchronized (mService.mGlobalLock) {
    
    
                final boolean globalConfigWillChange = mRequest.globalConfig != null
                        && mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;
                final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
            	......

                res = resolveToHeavyWeightSwitcherIfNeeded();
                if (res != START_SUCCESS) {
    
    
                    return res;
                }
                res = executeRequest(mRequest);
                ......

        } finally {
    
    
            onExecutionComplete();
        }
    }

res = executeRequest(mRequest);Create the ActivityRecord object of the first activity of the application, call startActivityUnchecked(), and then go to startActivityInner()

   /**
     * 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) {
    
    
        if (TextUtils.isEmpty(request.reason)) {
    
    
            throw new IllegalArgumentException("Need to specify a reason.");
        }
        mLastStartReason = request.reason;
        mLastStartActivityTimeMs = System.currentTimeMillis();
        mLastStartActivityRecord = null;

        final IApplicationThread caller = request.caller;
        Intent intent = request.intent;
        NeededUriGrants intentGrants = request.intentGrants;
        String resolvedType = request.resolvedType;
        ActivityInfo aInfo = request.activityInfo;
        ResolveInfo rInfo = request.resolveInfo;
        final IVoiceInteractionSession voiceSession = request.voiceSession;
        final IBinder resultTo = request.resultTo;
        String resultWho = request.resultWho;
        int requestCode = request.requestCode;
        int callingPid = request.callingPid;
        int callingUid = request.callingUid;
        String callingPackage = request.callingPackage;
        String callingFeatureId = request.callingFeatureId;
        final int realCallingPid = request.realCallingPid;
        final int realCallingUid = request.realCallingUid;
        final int startFlags = request.startFlags;
        final SafeActivityOptions options = request.activityOptions;
        Task inTask = request.inTask;
        TaskFragment inTaskFragment = request.inTaskFragment;

        int err = ActivityManager.START_SUCCESS;
        // Pull the optional Ephemeral Installer-only bundle out of the options early.
        final Bundle verificationBundle =
                options != null ? options.popAppVerificationBundle() : null;
        ......
        final ActivityRecord r = new ActivityRecord.Builder(mService)
                .setCaller(callerApp)
                .setLaunchedFromPid(callingPid)
                .setLaunchedFromUid(callingUid)
                .setLaunchedFromPackage(callingPackage)
                .setLaunchedFromFeature(callingFeatureId)
                .setIntent(intent)
                .setResolvedType(resolvedType)
                .setActivityInfo(aInfo)
                .setConfiguration(mService.getGlobalConfiguration())
                .setResultTo(resultRecord)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setComponentSpecified(request.componentSpecified)
                .setRootVoiceInteraction(voiceSession != null)
                .setActivityOptions(checkedOptions)
                .setSourceRecord(sourceRecord)
                .build();

        mLastStartActivityRecord = r;
        ......
        mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
                request.voiceInteractor, startFlags, true /* doResume */, checkedOptions,
                inTask, inTaskFragment, restrictedBgActivity, intentGrants);

        if (request.outActivity != null) {
    
    
            request.outActivity[0] = mLastStartActivityRecord;
        }

        return mLastStartActivityResult;
    }

mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,request.voiceInteractor, startFlags, true /* doResume */, checkedOptions,inTask, inTaskFragment, restrictedBgActivity, intentGrants);
Call startActivityUnchecked() method

    /**
     * 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, boolean doResume, ActivityOptions options, Task inTask,
            TaskFragment inTaskFragment, boolean restrictedBgActivity,
            NeededUriGrants intentGrants) {
    
    
        int result = START_CANCELED;
        final Task startedActivityRootTask;

        // Create a transition now to record the original intent of actions taken within
        // startActivityInner. Otherwise, logic in startActivityInner could start a different
        // transition based on a sub-action.
        // Only do the create here (and defer requestStart) since startActivityInner might abort.
        final TransitionController transitionController = r.mTransitionController;
        Transition newTransition = (!transitionController.isCollecting()
                && transitionController.getTransitionPlayer() != null)
                ? transitionController.createTransition(TRANSIT_OPEN) : null;
        RemoteTransition remoteTransition = r.takeRemoteTransition();
        if (newTransition != null && remoteTransition != null) {
    
    
            newTransition.setRemoteTransition(remoteTransition);
        }
        transitionController.collect(r);
        try {
    
    
            mService.deferWindowLayout();
            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
            result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, inTaskFragment, restrictedBgActivity,
                    intentGrants);
        } finally {
    
    
            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
            startedActivityRootTask = handleStartResult(r, options, result, newTransition,
                    remoteTransition);
            mService.continueWindowLayout();
        }
        postStartActivityProcessing(r, result, startedActivityRootTask);

        return result;
    }

result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,startFlags, doResume, options, inTask,inTaskFragment, restrictedBgActivity,intentGrants);Call startActivityInner() method

    /**
     * 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}.
     */
    // TODO(b/152429287): Make it easier to exercise code paths through startActivityInner
    @VisibleForTesting
    int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, Task inTask,
            TaskFragment inTaskFragment, boolean restrictedBgActivity,
            NeededUriGrants intentGrants) {
    
    
        setInitialState(r, options, inTask, inTaskFragment, doResume, startFlags, sourceRecord,
                voiceSession, voiceInteractor, restrictedBgActivity);

        computeLaunchingTaskFlags();

        computeSourceRootTask();
        ......
        if (mTargetRootTask == null) {
    
    
        	//找到目标Task
            mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, targetTask,
                    mOptions);
        }   
        ......
        final Task startedTask = mStartActivity.getTask();
        if (newTask) {
    
    
            EventLogTags.writeWmCreateTask(mStartActivity.mUserId, startedTask.mTaskId);
        }
        //此处打印wm_create_activity日志
        mStartActivity.logStartActivity(EventLogTags.WM_CREATE_ACTIVITY, startedTask);

        mStartActivity.getTaskFragment().clearLastPausedActivity();

        mRootWindowContainer.startPowerModeLaunchIfNeeded(
                false /* forceSend */, mStartActivity);

        final boolean isTaskSwitch = startedTask != prevTopTask && !startedTask.isEmbedded();
        //处理Task和Activity进栈操作
        mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch,
                mOptions, sourceRecord);
        if (mDoResume) {
    
    
            final ActivityRecord topTaskActivity = startedTask.topRunningActivityLocked();
            if (!mTargetRootTask.isTopActivityFocusable()
                    || (topTaskActivity != null && topTaskActivity.isTaskOverlay()
                    && 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.
                // Passing {@code null} as the start parameter ensures all activities are made
                // visible.
                mTargetRootTask.ensureActivitiesVisible(null /* starting */,
                        0 /* configChanges */, !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.
                mTargetRootTask.mDisplayContent.executeAppTransition();
            } else {
    
    
                // If the target root-task was not previously focusable (previous top running
                // activity on that root-task was not visible) then any prior calls to move the
                // root-task to the will not update the focused root-task.  If starting the new
                // activity now allows the task root-task to be focusable, then ensure that we
                // now update the focused root-task accordingly.
                if (mTargetRootTask.isTopActivityFocusable()
                        && !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {
    
    
                    mTargetRootTask.moveToFront("startActivityInner");
                }
                //启动栈顶的Activity
                mRootWindowContainer.resumeFocusedTasksTopActivities(
                        mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
            }
        }
        mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask);

       ......

        return START_SUCCESS;
    }

This method mainly does the following things:
1. computeLaunchingTaskFlags();
computeLaunchingTaskFlags() method calculates the Flag value of starting Activity
2. mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch,mOptions, sourceRecord);
startActivityLocked() handles Task and Activity push operations
3. mRootWindowContainer.resumeFocusedTasksTopActivities(mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
resumeFocusedTasksTopActivities() obtains the top activity of the stack and resumes it, which will be set to resume state

2.1 Calculate the Flag value of starting Activity

computeLaunchingTaskFlags();
Code path: frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java

   private void computeLaunchingTaskFlags() {
    
    
        ......

		//mInTask是Task类型,此处为null,代表Activity要加入的栈不存在,因此需要判断是否需要新Task
        if (mInTask == null) {
    
    
        //mSourceRecord是ActivityRecord类型,它是用来描述“初始Activity”
        //“初始Activity”:比如,ActivityA启动到了ActivityB,ActivityA就是初始Activity
        //当我们使用Context或者Application启动Activity时,此时mSourceRecord为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;
                }
            //初始Activity 如果是在singleInstance栈(LAUNCH_SINGLE_INSTANCE)中的Activity,就需要添加FLAG_ACTIVITY_NEW_TASK的标识
            //因为singleInstance只允许保存一个Activity
            } 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;
            //如果Launch Mode 设置了singleInstance(LAUNCH_SINGLE_INSTANCE) 和singleTask (LAUNCH_SINGLE_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;
            }
        }
    }

2.2 Processing Task and Activity push operations

mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch,mOptions, sourceRecord);
The startActivityLocked() method will call the positionChildAtTop() method to try to push the Task and Activity onto the stack. If the Activity is started in new Task mode or the Task id does not exist in the Task stack, the Task will be pushed back onto the stack and placed at the top of the stack.
Note: Task is pushed into the stack first, then Activity is pushed into the stack. They are included. Code
path: frameworks/base/services/core/java/com/android/server/wm/Task.java

    void startActivityLocked(ActivityRecord r, @Nullable Task topTask, boolean newTask,
            boolean isTaskSwitch, ActivityOptions options, @Nullable ActivityRecord sourceRecord) {
    
    
        final ActivityRecord pipCandidate = findEnterPipOnTaskSwitchCandidate(topTask);
        Task rTask = r.getTask();
        final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
        final boolean isOrhasTask = rTask == this || hasChild(rTask);
        // mLaunchTaskBehind tasks get placed at the back of the task stack.
        if (!r.mLaunchTaskBehind && allowMoveToFront && (!isOrhasTask || newTask)) {
    
    
            // Last activity in task had been removed or ActivityManagerService is reusing task.
            // Insert or replace.
            // Might not even be in.
            positionChildAtTop(rTask);
        }
        ......
    }

At this point, the ActivityRecord of the first Activity of the application has been created, its Task has been found, and finally the ActivityRecord is inserted into the appropriate position in the Task.

2.3 Get the top activity on the stack and resume it, which will be set to resume state

mRootWindowContainer.resumeFocusedTasksTopActivities(mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
Code path: frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

    boolean resumeFocusedTasksTopActivities(
            Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,
            boolean deferPause) {
    
    
        if (!mTaskSupervisor.readyToResume()) {
    
    
            return false;
        }

        boolean result = false;
        if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()
                || getTopDisplayFocusedRootTask() == targetRootTask)) {
    
    
            result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,
                    deferPause);
        }
        ......

        return result;
    }

result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,deferPause);Code path for calling resumeTopActivityUncheckedLocked
: frameworks/base/services/core/java/com/android/server/wm/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.
     *
     * @return Returns true if something is being resumed, or false if
     * nothing happened.
     *
     * NOTE: It is not safe to call this method directly as it can cause an activity in a
     *       non-focused root task to be resumed.
     *       Use {@link RootWindowContainer#resumeFocusedTasksTopActivities} to resume the
     *       right activity for the current system state.
     */
    @GuardedBy("mService")
    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options,
            boolean deferPause) {
    
    
        if (mInResumeTopActivity) {
    
    
            // Don't even start recursing.
            return false;
        }

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

            if (isLeafTask()) {
    
    
                if (isFocusableAndVisible()) {
    
    
                    someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause);
                }
            } else {
    
    
                int idx = mChildren.size() - 1;
                while (idx >= 0) {
    
    
                    final Task child = (Task) getChildAt(idx--);
                    if (!child.isTopActivityFocusable()) {
    
    
                        continue;
                    }
                    if (child.getVisibility(null /* starting */)
                            != TASK_FRAGMENT_VISIBILITY_VISIBLE) {
    
    
                        break;
                    }

                    someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options,
                            deferPause);
                    // Doing so in order to prevent IndexOOB since hierarchy might changes while
                    // resuming activities, for example dismissing split-screen while starting
                    // non-resizeable activity.
                    if (idx >= mChildren.size()) {
    
    
                        idx = mChildren.size() - 1;
                    }
                }
            }

            // When resuming the top activity, it may be necessary to pause the top activity (for
            // example, returning to the lock screen. We suppress the normal pause logic in
            // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the
            // end. We call the {@link ActivityTaskSupervisor#checkReadyForSleepLocked} again here
            // to ensure any necessary pause logic occurs. In the case where the Activity will be
            // shown regardless of the lock screen, the call to
            // {@link ActivityTaskSupervisor#checkReadyForSleepLocked} is skipped.
            final ActivityRecord next = topRunningActivity(true /* focusableOnly */);
            if (next == null || !next.canTurnScreenOn()) {
    
    
                checkReadyForSleep();
            }
        } finally {
    
    
            mInResumeTopActivity = false;
        }

        return someActivityResumed;
    }

someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause);Call resumeTopActivityInnerLocked

    @GuardedBy("mService")
    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options,
            boolean deferPause) {
    
    
        if (!mAtmService.isBooting() && !mAtmService.isBooted()) {
    
    
            // Not ready yet!
            return false;
        }

        final ActivityRecord topActivity = topRunningActivity(true /* focusableOnly */);
        if (topActivity == null) {
    
    
            // There are no activities left in this task, let's look somewhere else.
            return resumeNextFocusableActivityWhenRootTaskIsEmpty(prev, options);
        }

        final boolean[] resumed = new boolean[1];
        final TaskFragment topFragment = topActivity.getTaskFragment();
        resumed[0] = topFragment.resumeTopActivity(prev, options, deferPause);
        forAllLeafTaskFragments(f -> {
    
    
            if (topFragment == f) {
    
    
                return;
            }
            if (!f.canBeResumed(null /* starting */)) {
    
    
                return;
            }
            resumed[0] |= f.resumeTopActivity(prev, options, deferPause);
        }, true);
        return resumed[0];
    }

resumed[0] = topFragment.resumeTopActivity(prev, options, deferPause);Code path for calling resumeTopActivity
: frameworks/base/services/core/java/com/android/server/wm/TaskFragment.java

    final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,
            boolean deferPause) {
    
    
        ActivityRecord next = topRunningActivity(true /* focusableOnly */);
        if (next == null || !next.canResumeByCompat()) {
    
    
            return false;
        }

        next.delayedResume = false;
        final TaskDisplayArea taskDisplayArea = getDisplayArea();

        // If the top activity is the resumed one, nothing to do.
        if (mResumedActivity == next && next.isState(RESUMED)
                && taskDisplayArea.allResumedActivitiesComplete()) {
    
    
            // Ensure the visibility gets updated before execute app transition.
            taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
                    false /* preserveWindows */, true /* notifyClients */);
            // Make sure we have executed any pending transitions, since there
            // should be nothing left to do at this point.
            executeAppTransition(options);

            // In a multi-resumed environment, like in a freeform device, the top
            // activity can be resumed, but it might not be the focused app.
            // Set focused app when top activity is resumed
            if (taskDisplayArea.inMultiWindowMode() && taskDisplayArea.mDisplayContent != null
                    && taskDisplayArea.mDisplayContent.mFocusedApp != next) {
    
    
                taskDisplayArea.mDisplayContent.setFocusedApp(next);
            }
            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity "
                    + "resumed %s", next);
            return false;
        }

        // 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;
        }

        // If we are sleeping, and there is no resumed activity, and the top activity is paused,
        // well that is the state we want.
        if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) {
    
    
            // Make sure we have executed any pending transitions, since there
            // should be nothing left to do at this point.
            executeAppTransition(options);
            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Going to sleep and"
                    + " all paused");
            return false;
        }

        // Make sure that the user who owns this activity is started.  If not,
        // we will just leave it as is because someone should be bringing
        // another user's activities to the top of the stack.
        if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) {
    
    
            Slog.w(TAG, "Skipping resume of top activity " + next
                    + ": user " + next.mUserId + " is stopped");
            return false;
        }

        // The activity may be waiting for stop, but that is no longer
        // appropriate for it.
        mTaskSupervisor.mStoppingActivities.remove(next);

        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);

        mTaskSupervisor.setLaunchSource(next.info.applicationInfo.uid);

        ActivityRecord lastResumed = null;
        final Task lastFocusedRootTask = taskDisplayArea.getLastFocusedRootTask();
        if (lastFocusedRootTask != null && lastFocusedRootTask != getRootTaskFragment().asTask()) {
    
    
            // So, why aren't we using prev here??? See the param comment on the method. prev
            // doesn't represent the last resumed activity. However, the last focus stack does if
            // it isn't null.
            lastResumed = lastFocusedRootTask.getTopResumedActivity();
        }

        boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);
        if (mResumedActivity != null) {
    
    
            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Pausing %s", mResumedActivity);
            pausing |= startPausing(mTaskSupervisor.mUserLeaving, false /* uiSleeping */,
                    next, "resumeTopActivity");
        }
        if (pausing) {
    
    
            ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: need to"
                    + " start pausing");
            // At this point we want to put the upcoming activity's process
            // at the top of the LRU list, since we know we will be needing it
            // very soon and it would be a waste to let it get killed if it
            // happens to be sitting towards the end.
            if (next.attachedToProcess()) {
    
    
                next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
                        true /* activityChange */, false /* updateOomAdj */,
                        false /* addPendingTopUid */);
            } 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();
                mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,
                        isTop ? HostingRecord.HOSTING_TYPE_NEXT_TOP_ACTIVITY
                                : HostingRecord.HOSTING_TYPE_NEXT_ACTIVITY);
            }
            if (lastResumed != null) {
    
    
                lastResumed.setWillCloseOrEnterPip(true);
            }
            return true;
        } else if (mResumedActivity == next && next.isState(RESUMED)
                && taskDisplayArea.allResumedActivitiesComplete()) {
    
    
            // It is possible for the activity to be resumed when we paused back stacks above if the
            // next activity doesn't have to wait for pause to complete.
            // So, nothing else to-do except:
            // Make sure we have executed any pending transitions, since there
            // should be nothing left to do at this point.
            executeAppTransition(options);
            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity resumed "
                    + "(dontWaitForPause) %s", next);
            return true;
        }

        // If the most recent activity was noHistory but was only stopped rather
        // than stopped+finished because the device went to sleep, we need to make
        // sure to finish it as we're making a new activity topmost.
        if (shouldSleepActivities()) {
    
    
            mTaskSupervisor.finishNoHistoryActivitiesIfNeeded(next);
        }

        if (prev != null && prev != next && next.nowVisible) {
    
    
            // The next activity is already visible, so hide the previous
            // activity's windows right now so we can show the new one ASAP.
            // We only do this if the previous is finishing, which should mean
            // it is on top of the one being resumed so hiding it quickly
            // is good.  Otherwise, we want to do the normal route of allowing
            // the resumed activity to be shown so we can decide if the
            // previous should actually be hidden depending on whether the
            // new one is found to be full-screen or not.
            if (prev.finishing) {
    
    
                prev.setVisibility(false);
                if (DEBUG_SWITCH) {
    
    
                    Slog.v(TAG_SWITCH, "Not waiting for visible to hide: " + prev
                            + ", nowVisible=" + next.nowVisible);
                }
            } else {
    
    
                if (DEBUG_SWITCH) {
    
    
                    Slog.v(TAG_SWITCH, "Previous already visible but still waiting to hide: " + prev
                            + ", nowVisible=" + next.nowVisible);
                }
            }
        }

        // Launching this app's activity, make sure the app is no longer
        // considered stopped.
        try {
    
    
            mTaskSupervisor.getActivityMetricsLogger()
                    .notifyBeforePackageUnstopped(next.packageName);
            mAtmService.getPackageManager().setPackageStoppedState(
                    next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */
        } catch (RemoteException e1) {
    
    
        } catch (IllegalArgumentException e) {
    
    
            Slog.w(TAG, "Failed trying to unstop package "
                    + next.packageName + ": " + e);
        }

        // We are starting up the next activity, so tell the window manager
        // that the previous one will be hidden soon.  This way it can know
        // to ignore it when computing the desired screen orientation.
        boolean anim = true;
        final DisplayContent dc = taskDisplayArea.mDisplayContent;
        if (prev != null) {
    
    
            if (prev.finishing) {
    
    
                if (DEBUG_TRANSITION) {
    
    
                    Slog.v(TAG_TRANSITION, "Prepare close transition: prev=" + prev);
                }
                if (mTaskSupervisor.mNoAnimActivities.contains(prev)) {
    
    
                    anim = false;
                    dc.prepareAppTransition(TRANSIT_NONE);
                } else {
    
    
                    dc.prepareAppTransition(TRANSIT_CLOSE);
                }
                prev.setVisibility(false);
            } else {
    
    
                if (DEBUG_TRANSITION) {
    
    
                    Slog.v(TAG_TRANSITION, "Prepare open transition: prev=" + prev);
                }
                if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
    
    
                    anim = false;
                    dc.prepareAppTransition(TRANSIT_NONE);
                } else {
    
    
                    dc.prepareAppTransition(TRANSIT_OPEN,
                            next.mLaunchTaskBehind ? TRANSIT_FLAG_OPEN_BEHIND : 0);
                }
            }
        } else {
    
    
            if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
            if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
    
    
                anim = false;
                dc.prepareAppTransition(TRANSIT_NONE);
            } else {
    
    
                dc.prepareAppTransition(TRANSIT_OPEN);
            }
        }

        if (anim) {
    
    
            next.applyOptionsAnimation();
        } else {
    
    
            next.abortAndClearOptionsAnimation();
        }

        mTaskSupervisor.mNoAnimActivities.clear();

        if (next.attachedToProcess()) {
    
    
            if (DEBUG_SWITCH) {
    
    
                Slog.v(TAG_SWITCH, "Resume running: " + next + " stopped=" + next.stopped
                        + " visibleRequested=" + next.mVisibleRequested);
            }

            // If the previous activity is translucent, force a visibility update of
            // the next activity, so that it's added to WM's opening app list, and
            // transition animation can be set up properly.
            // For example, pressing Home button with a translucent activity in focus.
            // Launcher is already visible in this case. If we don't add it to opening
            // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a
            // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation.
            final boolean lastActivityTranslucent = inMultiWindowMode()
                    || mLastPausedActivity != null && !mLastPausedActivity.occludesParent();

            // This activity is now becoming visible.
            if (!next.mVisibleRequested || next.stopped || lastActivityTranslucent) {
    
    
                next.app.addToPendingTop();
                next.setVisibility(true);
            }

            // schedule launch ticks to collect information about slow apps.
            next.startLaunchTickingLocked();

            ActivityRecord lastResumedActivity =
                    lastFocusedRootTask == null ? null
                            : lastFocusedRootTask.getTopResumedActivity();
            final ActivityRecord.State lastState = next.getState();

            mAtmService.updateCpuStats();

            ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (in existing)", next);

            next.setState(RESUMED, "resumeTopActivity");

            // Have the window manager re-evaluate the orientation of
            // the screen based on the new activity order.
            boolean notUpdated = true;

            // Activity should also be visible if set mLaunchTaskBehind to true (see
            // ActivityRecord#shouldBeVisibleIgnoringKeyguard()).
            if (shouldBeVisible(next)) {
    
    
                // We have special rotation behavior when here is some active activity that
                // requests specific orientation or Keyguard is locked. Make sure all activity
                // visibilities are set correctly as well as the transition is updated if needed
                // to get the correct rotation behavior. Otherwise the following call to update
                // the orientation may cause incorrect configurations delivered to client as a
                // result of invisible window resize.
                // TODO: Remove this once visibilities are set correctly immediately when
                // starting an activity.
                notUpdated = !mRootWindowContainer.ensureVisibilityAndConfig(next, getDisplayId(),
                        true /* markFrozenIfConfigChanged */, false /* deferResume */);
            }

            if (notUpdated) {
    
    
                // The configuration update wasn't able to keep the existing
                // instance of the activity, and instead started a new one.
                // We should be all done, but let's just make sure our activity
                // is still at the top and schedule another run if something
                // weird happened.
                ActivityRecord nextNext = topRunningActivity();
                ProtoLog.i(WM_DEBUG_STATES, "Activity config changed during resume: "
                        + "%s, new next: %s", next, nextNext);
                if (nextNext != next) {
    
    
                    // Do over!
                    mTaskSupervisor.scheduleResumeTopActivities();
                }
                if (!next.mVisibleRequested || next.stopped) {
    
    
                    next.setVisibility(true);
                }
                next.completeResumeLocked();
                return true;
            }

            try {
    
    
                final ClientTransaction transaction =
                        ClientTransaction.obtain(next.app.getThread(), next.token);
                // Deliver all pending results.
                ArrayList<ResultInfo> a = next.results;
                if (a != null) {
    
    
                    final int size = a.size();
                    if (!next.finishing && size > 0) {
    
    
                        if (DEBUG_RESULTS) {
    
    
                            Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a);
                        }
                        transaction.addCallback(ActivityResultItem.obtain(a));
                    }
                }

                if (next.newIntents != null) {
    
    
                    transaction.addCallback(
                            NewIntentItem.obtain(next.newIntents, true /* resume */));
                }

                // Well the app will no longer be stopped.
                // Clear app token stopped state in window manager if needed.
                next.notifyAppResumed(next.stopped);

                EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next),
                        next.getTask().mTaskId, next.shortComponentName);

                mAtmService.getAppWarningsLocked().onResumeActivity(next);
                next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState);
                next.abortAndClearOptionsAnimation();
                transaction.setLifecycleStateRequest(
                        ResumeActivityItem.obtain(next.app.getReportedProcState(),
                                dc.isNextTransitionForward()));
                mAtmService.getLifecycleManager().scheduleTransaction(transaction);

                ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Resumed %s", next);
            } catch (Exception e) {
    
    
                // Whoops, need to restart this activity!
                ProtoLog.v(WM_DEBUG_STATES, "Resume failed; resetting state to %s: "
                        + "%s", lastState, next);
                next.setState(lastState, "resumeTopActivityInnerLocked");

                // lastResumedActivity being non-null implies there is a lastStack present.
                if (lastResumedActivity != null) {
    
    
                    lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked");
                }

                Slog.i(TAG, "Restarting because process died: " + next);
                if (!next.hasBeenLaunched) {
    
    
                    next.hasBeenLaunched = true;
                } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedRootTask != null
                        && lastFocusedRootTask.isTopRootTaskInDisplayArea()) {
    
    
                    next.showStartingWindow(false /* taskSwitch */);
                }
                mTaskSupervisor.startSpecificActivity(next, true, false);
                return true;
            }

            // From this point on, if something goes wrong there is no way
            // to recover the activity.
            try {
    
    
                next.completeResumeLocked();
            } catch (Exception e) {
    
    
                // If any exception gets thrown, toss away this
                // activity and try the next one.
                Slog.w(TAG, "Exception thrown during resume of " + next, e);
                next.finishIfPossible("resume-exception", true /* oomAdj */);
                return true;
            }
        } else {
    
    
            // Whoops, need to restart this activity!
            if (!next.hasBeenLaunched) {
    
    
                next.hasBeenLaunched = true;
            } else {
    
    
                if (SHOW_APP_STARTING_PREVIEW) {
    
    
                    next.showStartingWindow(false /* taskSwich */);
                }
                if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
            }
            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Restarting %s", next);
            mTaskSupervisor.startSpecificActivity(next, true, true);
        }

        return true;
    }

Guess you like

Origin blog.csdn.net/yimelancholy/article/details/130515992