Activitymanagement

Activity is the most complex component, responsible for displaying the UI and handling various input events. Activity provides Windows in which to draw interfaces, as well as a variety of controls for easy development. The Activity official website portal

In addition, Android does not provide external interface to start the process, only when the Activity or Service is started, the system starts the process as required.

ActivityLife cycle of

aboutActivityLet’s take a look at the official illustration:

The life cycle diagram of an Activity implies three states when an Activity is running, which are:

  • Active state: newly startedActivityLocated at the very front of the screen, it accepts state input from the user
  • Pause state: whenActivityBeing a transparent or translucentActivityOverlay, at this pointActivityAlthough it cannot accept user input, it is still visible
  • Stop state: when aActivityTotally by anotherActivityOverwrite, cannot accept user input and is not visible

When the state of an Activity object changes, it calls the abstract interface defined in the figure above to notify the application. Related descriptions are as follows:

  • onCreate(): whenActivityCalled when the object is created
  • onStart(): whenActivityinFrameworkCalled when the data structure in
  • onResume(): whenActivityCalled when it reaches the top of the stack and becomes active
  • onPause(): whenActivityWhen switching from the front end of the stack to the back end, the method is paused and called
  • onStop(): whenActivityCalled when it is completely invisible
  • onDestroy(): in the destruction ofActivityBefore, the system invokes this method first

Intents, Tasks, LaunchMode, etc. (Intent, Task, LaunchMode

Intent,TaskwithLaunchMode

understandIntent

An Intent is an abstract description of an action that is requested to be performed. It is usually used as a parameter to complete the messaging between components. For more detailed postures, please refer to the official website description: official portal

The Intent class is defined as follows:

public class Intent implements Parcelable.Cloneable {
    private String mAction;
    private Uri mData;
    private String mType;
    private String mPackage;
    private ComponentName mComponent;
    private int mFlags;
    private ArraySet<String> mCategories;
    private Bundle mExtras;
    private Rect mSourceBounds;
    private Intent mSelector;
    private ClipData mClipData;
}
Copy the code

The common parameter meanings are as follows:

  • mActionIs a string specifying what operation to perform.
    • inIntentClass defines a large number ofAction, e.g.ACTION_VIEW,ACTION_SENDAnd so on.
    • theseActionThe function of is related to specific functional modules and expresses the intention to be implemented
  • mDataStore data that needs to be passed, of typeURI.
    • URIIs the Uniform Resource Identifier (Uniform Resources IdentifierShort for)
    • Originally used to denoteWebResources such as HTML documents, images, files, etc
    • URL(Uniform Resource Locator)isURIA kind of
  • mTypeisMIMEFormat string representing the data type.
    • MIMEIs a multifunctionalInternetMail Extension Service (Multipurpose Internet Mail ExtensionsThe abbreviation of)
    • The earliest English email system, later applied to the browser. Format for example:text/plain``application/x-gzipEtc.
    • Normally this data type does not need to be specified and can be sped up if this field is setIntentMatching speed of
  • mComponentUsed to specify receivingIntentIs the name of the target component
    • mComponentIs of typeComponentName, it contains two strings:mPackageandmClass, the former is used to specify the package name and the latter is used to specify the class name
    • IntentIf is definedmComponenttheIntentWill be sent directly to the specified component and will not be looked up through other property combinations
  • mFlagsIt’s called the logo, in theIntentThere are many definitions in the classflagRelative constants of. There are two main types
    • In order toFLAG_ACTIVITY_...At the beginning, for controlActivityParameters related to startup, such asFLAG_ACTIVITY_NEW_TASK
    • In order toFLAG_RECEIVER_...The parameter used to broadcast
  • mCategoriesA contain should be handledIntentA string of additional information about the component type. There are two common categories:
    • CATEGORY_BROWSABLEGoal:ActivityAllows itself to be launched through a web browser to display the data referenced by the link
    • CATEGORY_LAUNCHER: theActivityIs the beginning of the taskActivity
    • You can put any number of category descriptions into oneIntentIn, but mostlyIntentNo category is required
  • mExtrasRepresents a collection of all additional information.
    • mExtrasThe data type isBundle
    • You can use a variety ofputExtra()Method to addExtra data, each method accepts two parameters:keyandvalue

Task

A Task is a collection of activities. Android stores the activities used by the user during a related operation in Task in sequence, so that when the back key is pressed, it can be rolled back in reverse order.

Tasks manage activities in a last-in, first-out manner, like a stack. When you press recent, a selection list pops up. This list is a collection of existing tasks in the system. Selecting a Task brings the Activity as a whole to the foreground. The order of activities in a Task usually cannot be changed, but can only be added or removed from the stack.

AMS uses ActivityStack to manage tasks. The tasks managed by ActivityStack are stored in the member variable mTaskHistory, as defined below:

class ActivityStack{
    private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
}
Copy the code

MTaskHistory is a list of TaskRecord objects. The TaskRecord object represents a Task, and its member variable mActivities is also a list of all ActivityRecord objects in that Task. MActivities are defined as follows:

class TaskRecord{
    final ArrayList<ActivityRecord> mActivities;
}
Copy the code

So how do you start a new oneTask?

  • IntentA flag is defined inFLAG_ACTIVITY_NEW_TASKIn thestartActivity()theIntentAdding this flag to the parameter opens a new oneTask
  • But if the system already has the sameaffinitytheTaskIt exists. It doesn’t start another oneTask, but will be the oldTaskTo the front desk

So,affinityWhere is it defined?

  • affinityIt means affinity, is through<activity>Of the labelandroid:taskAffinityProperty
  • When using flagsFLAG_ACTIVITY_NEW_TASKStart aActivityWhen theActivitythetaskAffinityThe string in the property becomesTasktheaffinity
  • I’ll add this laterTasktheActivityEven theirtaskAffinityProperty defines a different string and does not changeTaskThe existingaffinity
  • if<activity>Not specified in the tagandroid:taskAffinityProperty, this oneActivityWill inherit<application>Of the labelandroid:taskAffinityattribute
  • if<application>Of the labelandroid:taskAffinityProperty is also undefined and the application package name will be used as the default value
    • Because of this, if you start another application in your applicationActivityEven if usedFLAG_ACTIVITY_NEW_TASKThe logo also does not necessarily launch a new oneTask
    • Unless theActivityIt’s defined differentlytaskAffinityattribute

LaunchMode

The startup mode of an Activity implies the reuse of Activity objects. The official portal is also described in detail on the official website of the startup mode

When you start aActivityWhen, if the system backgroundTaskThere is already one of theActivityThe instance exists and the system is created with a new oneActivityOr will it already existActivitySwitch to the foreground?

The answer is both. There are a number of factors that can affect the outcome. This includes Activity property values and flags specified in the Intent

Let’s take a look at the impact of the Activity attribute launchMode:

  • standardMode: Default.
    • standardMode ofActivityThis is created on each startupActivityInstance object of
    • The sameTaskCan exist simultaneously inActivityMultiple instances of
    • aActivityMultiple instances of can appear in multipleTaskThe stack
  • singleTopmodel
    • If the targetTaskThe top of the existingActivityInstance, the system will call the instanceonNewIntent()Method to itIntentInstead of creating a new oneActivityInstance.
    • If it’s not at the top of the stack, thisstandardCreate a new instance object as usual
  • singleTaskmodel
    • Set up thesingleTaskPatterns ofActivityIt is system unique and can only be created in the systemActivityAn instance object of
    • Boot set tosingleTaskPatterns ofActivityIf this parameter already exists in the systemActivityThe instance object of theTaskThe one in front of itActivityAll pop-ups on the stack will beActivityBring it to the top of the stack and call itonNewIntent()Method pass newIntentobject
    • If it does not exist in the systemActivityWill create an instance object ofActivityInstance object of
      • If theActivitythetaskAffinityProperty value and currentTasktheaffinityIf the value is the same, it will join the currentTaskIn the
      • Otherwise, even if theActivitytheIntentIs not specified inFLAG_ACTIVITY_NEW_TASKFlags will also launch new onesTaskAnd willActivityAs for the
  • singleInstancemodel
    • Set tosingleInstanceModal activities are also system-unique in that there is only one instance object of the Activity in the system
    • At the same time the system will not be any otherActivityStart to include theActivityThe instanceTaskIn the
    • theActivityIs always theTaskThe onlyActivity

Usually, oneActivityOnce created, it will stay at a certainTaskUntil it is destroyed

  • However, ifActivitytheallowTaskReparentingProperty set totruetheActivityCan be in differentTaskTransfer between
  • However, this property is only enabledActivitytheIntentSet in theFLAG_ACTIVITY_RESET_TASK_IF_NEEDEDIt only works when it’s marked

In addition to the above information, the Activity and Task logic can be found on the official website: Tasks and Return stack

For example, the following tips are important (excerpted from the official website) :

Use the “singleTask” and “singleInstance” startup modes only if your Activity has ACTION_MAIN and CATEGORY_LAUNCHER filters. They mark the Activity as always starting the task. For example, imagine what would happen without this filter: The intent starts the “singleTask” Activity, which then starts a new task that the user has spent some time on. The user then presses the home screen button. At this point, the task is moved to the background and is no longer visible. Now, the user cannot return to the task because it does not show up in the application launcher.

To understandClientTransactionHandlerThe role of

ClientTransactionHandler is an important class that appears on Android 9.0 and is used to concatenate the entire lifecycle management of AMS and activities

We already know that the entry point for the application is the Main () function of the ActivityThread class. A closer look at the class structure shows that the ActivityThread inherits a special class. Are defined as follows

public final class ActivityThread extends ClientTransactionHandler {... }Copy the code

You can see that ActivityThread inherits the ClientTransactionHandler class. This class was added in Android 9.0 and the key definitions are as follows:

public abstract class ClientTransactionHandler {
    void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this); sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction); }...public abstract void handleDestroyActivity(...).;
    public abstract void handlePauseActivity(...).;
    public abstract void handleResumeActivity(...).;
    public abstract void handleStopActivity(...).; .public abstract Activity handleLaunchActivity(...).;
    public abstract void handleStartActivity(...).; .public abstract void handleNewIntent(...).; . }Copy the code

Class defines methods related to the declaration cycle, and as we can tactfully guess,AMSCallback control for later life cycles should be implemented through this, and the related class inheritance is as follows:

Android abstracts the activities associated with the lifecycle. In the class defined above, the real business implementation includes:

  • LaunchActivityItemIs to executelaunch activitytask
  • resume activitybyResumeActivityItemimplementation
  • pause activitybyPauseActivityItemimplementation
  • stop activitybyStopActivityItemimplementation
  • destroy activitybyDestoryActivityItemimplementation

ClientTransactionCall logic of

Take a look at the call flow: The ApplicationThread class in ActivityThread has a scheduleTransaction() method,

The ApplicationThread class is a Binder service class that AMS calls as a client, as well as its scheduleTransaction() method

The scheduleTransaction() method is as follows:

@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    ActivityThread.this.scheduleTransaction(transaction);
}
Copy the code

The scheduleTransaction() method of ActivityThread, also known as ClientTransactionHandler, is called as follows:

    void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);
        sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
    }
Copy the code

An EXECUTE_TRANSACTION message is sent to the Handler implementation class H of ActivityThread. The message is handled as follows:

case EXECUTE_TRANSACTION:
    final ClientTransaction transaction = (ClientTransaction) msg.obj;
    mTransactionExecutor.execute(transaction);
    if (isSystem()) {
        transaction.recycle();
    }
    break;
Copy the code

Message processing were used in the mTransactionExecutor. The execute (), not surprisingly, will in TransactionExecutor execution logic, we look at:

    public void execute(ClientTransaction transaction) {
        final IBinder token = transaction.getActivityToken();
        executeCallbacks(transaction);
        executeLifecycleState(transaction);
        mPendingActions.clear();
    }
    public void executeCallbacks(ClientTransaction transaction) {
        final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
        if (callbacks == null) {
            return; }...final int size = callbacks.size();
        for (int i = 0; i < size; ++i) { ...... item.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions); . }}private void executeLifecycleState(ClientTransaction transaction) {
        final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
        if (lifecycleItem == null) {
            // No lifecycle request, return early.
            return; }...// A very important method
        cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */);
        // Execute the final transition with proper parameters.
        lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
        lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
    }
Copy the code

As you can see, the item.execute() and LifecycleItem.execute () methods were finally executed on the executeCallbacks() and executeLifecycleState() sides, respectively

What are the purposes of executeCallbacks() and executeLifecycleState()? Based on the class diagram, we can infer as follows:

  • executeCallbacks()Traversal performsClientTransactionIn the classList<ClientTransactionItem> mActivityCallbacksElements of a set
    • ClientTransactionItemThe direct subclass implementation of the class onlyLaunchActivityItemclass
    • That is to say,executeCallbacks()The main implementation islaunch activityNotification operation of
  • executeLifecycleState()Execution isClientTransactionIn the classActivityLifecycleItem mLifecycleStateRequest
    • mLifecycleStateRequestReferred to asfinal state
    • As you can see from the inheritance relationship,resume activity,pasue activity,stop activity,destory activityAre all here

Once you look at the call flow, you’ll notice that there is no StartActivityItem in the implementation class. Why? So how do I call onStart()? The core lies in the cycleToPath() function

TransactionExecutor.cycleToPath()

Android does not define all *ActivityItem classes for the Activity lifecycle. For example, StartActivityItem does not exist.

Note the constant definition of the ActivityLifecycleItem in the class diagram. Android uses cycleToPath() to take a more subtle approach. The core logic is:

  • To specify aActivitythefinal state
  • According to theActivityTo calculate the required state during the process and save it in the collection
  • Finally, the states in the collection are executed sequentially

Take the realStartActivityLocked() method later in this article

  • willLaunchActivityItemObject of type added tocallbackIn the
    • TransactionExecutorWill be performedLaunchActivityItemclass
    • After the executionActivityInto theON_CREATEstate
  • Method specified infinal stateforResumeActivityItem
    • TransactionExecutorthroughcycleToPath()Calculates the current state andfinal stateThe difference of
    • The current status isON_CREATEState,final stateforON_RESUME
    • TransactionExecutorThrough the help classgetLifecyclePathMethod to collate the missing state between the two into a collection
    • And then callperformLifecycleSequence()Circulation processing

PerformLifecycleSequence () :

    private void performLifecycleSequence(ActivityClientRecord r, IntArray path) {
        final int size = path.size();
        for (int i = 0, state; i < size; i++) {
            state = path.get(i);
            switch (state) {
                caseON_CREATE: mTransactionHandler.handleLaunchActivity(...) ;break;
                case ON_START:
                    mTransactionHandler.handleStartActivity(r, mPendingActions);
                    break;
                caseON_RESUME: mTransactionHandler.handleResumeActivity(...) ;break;
                caseON_PAUSE: mTransactionHandler.handlePauseActivity(...) ;break;
                caseON_STOP: mTransactionHandler.handleStopActivity(...) ;break;
                caseON_DESTROY: mTransactionHandler.handleDestroyActivity(...) ;break;
                caseON_RESTART: mTransactionHandler.performRestartActivity(...) ;break;
                default:
                    throw new IllegalArgumentException("Unexpected lifecycle state: "+ state); }}}Copy the code

PauseActivityItemCall analysis of

Using the PauseActivityItem class as an example, let’s look at the specific execution logic:

public class PauseActivityItem extends ActivityLifecycleItem {...@Override
    public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {... client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions,"PAUSE_ACTIVITY_ITEM"); . }}Copy the code

You execute the ClientTransactionHandler abstract class, which is essentially the handlePauseActivity() method of the ActivityThread class.

HandlePauseActivity () method calls the performPauseActivity ActivityThread class () method, which is the last call to performPauseActivityIfNeeded () method, the code is as follows:

    private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {... mInstrumentation.callActivityOnPause(r.activity); . }Copy the code

The callActivityOnPause() method of the Instrumentation class is executed as follows:

    public void callActivityOnPause(Activity activity) {
        activity.performPause();
    }
Copy the code

Very succinct, continue to check:

public class Activity{
    final void performPause(a) {
        mDoReportFullyDrawn = false;
        mFragments.dispatchPause();
        mCalled = false;
        onPause();
        writeEventLog(LOG_AM_ON_PAUSE_CALLED, "performPause");
        mResumed = false; . }}Copy the code

Do you have any! Do you have any! onPause(); Finally called…

We’ve found the flow of the call from the application side, but how does it get triggered for AMS?

Next, let’s examine the Activity launch process. During the Activity launch process, we can find an example of AMS triggering the declaration cycle

Start theActivity

To explore the calling details of the Activity lifecycle, start with the most familiar place, the startActivity (Intent Intent) method of the Activity object

Activty.startActivty()

The startActivity (Intent Intent) method is called as follows:

class Activity{
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if(options ! =null) {
            startActivityForResult(intent, -1, options);
        } else {
            startActivityForResult(intent, -1); }}public void startActivityForResult(...). {... Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, who, intent, requestCode, options); . }}class Instrumentation{
    public ActivityResult execStartActivity(...). { IApplicationThread whoThread = (IApplicationThread) contextThread; .try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            intresult = ActivityManager.getService() .startActivity(...) ; checkStartActivityResult(result, intent); }catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null; }}class ActivityManagerService{
    public final int startActivity(...). {
        returnstartActivityAsUser(...) ; }public final int startActivityAsUser(...). {...return mActivityStartController.obtainStarter(intent, "startActivityAsUser")... .execute(); }}Copy the code

We see that the last thing we call is the AMS startActivityAsUser method. If you trace the call to the startActivityAsUser method, the ActivityStarter class’s execute() method is used to start the Activity:

class ActivityStater{
    int execute(a) {
        try {
            if (mRequest.mayWait) {
                returnstartActivityMayWait(...) ; }else {
                return startActivity(...);
            }
        } finally{ onExecutionComplete(); }}}Copy the code

We see that execute() has two methods to start the Activity, and we’ll continue with the startActivityMayWait() method, since we’ll end up in startActivity() as well.

ActivityStarter.startActivityMayWait()

The brief code is as follows:

private int startActivityMayWait(...). {...// Get information about the Activity to start
    ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
    synchronized (mService) {
        ......
        intres = startActivity(caller, ...) ; .if(outResult ! =null) { // The result needs to be returned
            outResult.result = res;
            final ActivityRecord r = outRecord[0];
            switch(res) {
                case START_SUCCESS: {
                    // Add to a specific collection
                    mSupervisor.mWaitingActivityLaunched.add(outResult);
                    do {
                        try {
                            // Wait for the Activity to start in the application process
                            mService.wait();
                        } catch (InterruptedException e) {
                        }
                    } while(outResult.result ! = START_TASK_TO_FRONT && ! outResult.timeout && outResult.who ==null); .break; }... }}returnres; }}Copy the code

The startActivityMayWait() method flows as follows:

  • First callresolveActivity()Method to get theActivityThe information of
  • getActivityAfter the message, continue the callstartActivity()Method to continue the startupActivity
  • If you startActivityIf the application needs to get the return resultmServiceThe object’swait()Method suspends the thread to wait for the result of starting

Here’s the code that calls the startActivity() method on ActivityStarter. Let’s look at some of the details:

private int startActivity(IApplicationThread caller, ...) {
    interr = ActivityManager.START_SUCCESS; .if(caller ! =null) {
        // Get information about the process that started the Activity
        callerApp = mService.getRecordForAppLocked(caller);
        if(callerApp ! =null) {
            callingPid = callerApp.pid;
            callingUid = callerApp.info.uid;
        } else{ err = ActivityManager.START_PERMISSION_DENIED; }}final intuserId = aInfo ! =null&& aInfo.applicationInfo ! =null
            ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0; .// Omit a lot of error checking
    // Check the relevant permissions of the caller
    booleanabort = ! mSupervisor.checkStartAnyActivityPermission(...) ;// Check whether the Intent firewall blocks the Intentabort |= ! mService.mIntentFirewall.checkStartActivity(...) ; .if(mService.mController ! =null) {
        try {
            // The IActivityControler interface that listens to the Activity change is notified of the Activity start messageIntent watchIntent = intent.cloneFilter(); abort |= ! mService.mController.activityStarting(watchIntent, aInfo.applicationInfo.packageName); }catch (RemoteException e) {
            mService.mController = null; }}...if (abort) {
        ......// If abort is true, exit
        returnSTART_ABORTED; }...// Create an ActivityRecord object
    ActivityRecord r = newActivityRecord(...) ;if(outActivity ! =null) {
        outActivity[0] = r; }...// The ActivityStack that the current user is operating on
    final ActivityStack stack = mSupervisor.mFocusedStack;
    // Check whether the caller has permission to switch processes in case of frequent process switching
    if (voiceSession == null && (stack.getResumedActivity() == null|| stack.getResumedActivity().info.applicationInfo.uid ! = realCallingUid)) {if(! mService.checkAppSwitchAllowedLocked(callingPid, callingUid, realCallingPid, realCallingUid,"Activity start")) {
            // For cases where you cannot switch processes, place the Activity information in the MpendingActivityLauncher list
            mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
                    sourceRecord, startFlags, stack, callerApp));
            ActivityOptions.abort(checkedOptions);
            returnActivityManager.START_SWITCHES_CANCELED; }}if (mService.mDidAppSwitch) {
        mService.mAppSwitchesAllowedTime = 0;
    } else {
        mService.mDidAppSwitch = true;// Turn on the switch to allow switching between processes
    }
    // To start the pending activities, you start each Activity in the MpendingActivityLauncher list.
    // startActivity is also called
    // In most cases the MPendingActivitylauncher list is blank
    mController.doPendingActivityLaunches(false); .// Call startActivity another overloaded method, taking ActivityRecord as the first argument
    returnstartActivity(r, ...) ; }private int startActivity(final ActivityRecord r, ...) {
    intresult = START_CANCELED; . result = startActivityUnchecked(r, ...) ; .return result;
}
Copy the code

I don’t need to go into too much detail here, but it’s important to understand how the Activity method is called. The last call is the startActivityUnchecked() method.

ActivityStarter.startActivityUnchecked()

The method is as follows:

private int startActivityUnchecked(final ActivityRecord r, ...) {
    // Initialize the environment and lunchModeFlags
    setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
            voiceInteractor);
    computeLaunchingTaskFlags();
    computeSourceStack();
    mIntent.setFlags(mLaunchFlags);

    // Determine whether the Activity needs to insert a new Task if reusedActivity is not empty
    // 1. Set FLAG_ACTIVITY_NEW_TASK:
    // 2. Start mode singleTask:
    // 3. The startup mode is singleInstanceActivityRecord reusedActivity = getReusableIntentActivity(); .final booleandontStart = top ! =null && mStartActivity.resultTo == null&& top.realActivity.equals(mStartActivity.realActivity) && top.userId == mStartActivity.userId && top.app ! =null&& top.app.thread ! =null&& ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) ! =0
            || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK));
    if (dontStart) { // No need to start the case
        // For paranoia, make sure we have correctly resumed the top activity.
        topStack.mLastPausedActivity = null;
        if(mDoResume) { mSupervisor.resumeFocusedStackTopActivityLocked(); }... deliverNewIntent(top); .return START_DELIVERED_TO_TOP;
    }
    boolean newTask = false;
    finalTaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord ! =null)? mSourceRecord.getTask() :null;
    // Determine whether the current Activity needs a new Task
    int result = START_SUCCESS;
    if (mStartActivity.resultTo == null && mInTask == null&&! mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) ! =0) {
        newTask = true;
        result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
    } else if(mSourceRecord ! =null) {
        result = setTaskFromSourceRecord();
    } else if(mInTask ! =null) {
        result = setTaskFromInTask();
    } else {
        // This not being started from an existing activity, and not part of a new task...
        // just put it in the top task, though these days this case should never happen.setTaskToCurrentTopOrCreateNewTask(); }.../ / start the Activity
    // startActivityLocked basically adds an ActivityRecord object to the top of the Task
    // Also add Task to the top of mTaskHistory
    mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
            mOptions);
    // Make the Activity visible using WindowManager
    if (mDoResume) {
        final ActivityRecord topTaskActivity = mStartActivity.getTask().topRunningActivityLocked();
        if(! mTargetStack.isFocusable() || (topTaskActivity ! =null&& topTaskActivity.mTaskOverlay && mStartActivity ! = topTaskActivity)) { mTargetStack.ensureActivitiesVisibleLocked(null.0, !PRESERVE_WINDOWS);
            mService.mWindowManager.executeAppTransition(); // The animation should be executed to switch between applications
        } else{... mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity, mOptions); }}else if(mStartActivity ! =null) { mSupervisor.mRecentTasks.add(mStartActivity.getTask()); }...return START_SUCCESS;
}
Copy the code

The startActivityUnchecked() method uses the Intent flag and Activity properties to determine the Activity’s Task and then pushes it to the top of the stack. We’ll skip over the details. Need to focus on the method is mSupervisor resumeFocusedStackTopActivityLocked () method call. Trace the call, the execution is resumeTopActivityInnerLocked ActivityStack class () method

ActivityStack.resumeTopActivityInnerLocked()

We already know resumeFocusedStackTopActivityLocked () method will eventually call resumeTopActivityInnerLocked ActivityStack class () method.

ResumeTopActivityInnerLocked () method is the role of the main in the Activity displayed on the top of the stack, but before that, the old Activity (variable mResumedActivity reference is) also showed on the screen. The method content is as follows:

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    if(! mService.mBooting && ! mService.mBooted) {// Not ready yet!
        return false;
    }
    // Find the Activity to start from mTaskHistory
    // This should be done because the Activity is already on the stack
    final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
    final booleanhasRunningActivity = next ! =null; .if(! hasRunningActivity) {// There are no activities left in the stack, let's look somewhere else.
        return resumeTopActivityInNextFocusableStack(prev, options, "noMoreActivities");
    }
    next.delayedResume = false;
    // If the currently displayed Activity is the Activity to start, return directly
    if (mResumedActivity == next && next.isState(RESUMED)
            && mStackSupervisor.allResumedActivitiesComplete()) {
        executeAppTransition(options);
        return false;
    }
    // If you are hibernating or shutting down, return directly
    if (shouldSleepOrShutDownActivities()
            && mLastPausedActivity == next
            && mStackSupervisor.allPausedActivitiesComplete()) {
        executeAppTransition(options);
        return false;
    }
    // User status check
    if(! mService.mUserController.hasStartedUserState(next.userId)) {return false;
    }
    // The Activity to be started is removed from the relevant queue
    mStackSupervisor.mStoppingActivities.remove(next);
    mStackSupervisor.mGoingToSleepActivities.remove(next);
    next.sleeping = false;
    mStackSupervisor.mActivitiesWaitingForVisibleActivity.remove(next);
    // Check if any Activity is being paused
    if(! mStackSupervisor.allPausedActivitiesComplete()) {return false;
    }
    // Set applicationInfo to launchmStackSupervisor.setLaunchSource(next.info.applicationInfo.uid); .boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
    if(mResumedActivity ! =null) {
        // Suspend the current Activity
        // startPausingLocked() triggers onPause() for the old Activity
        pausing |= startPausingLocked(userLeaving, false, next, false); }... ActivityStack lastStack = mStackSupervisor.getLastStack();if(next.app ! =null&& next.app.thread ! =null) {
        // If the application in which the Activity resides already exists, just display the Activity.synchronized(mWindowManager.getWindowManagerLock()) {
            // This activity is now becoming visible.
            if(! next.visible || next.stopped || lastActivityTranslucent) { next.setVisibility(true); }...try {
                finalClientTransaction transaction = ClientTransaction.obtain(next.app.thread, next.appToken); .// Add ActivityResultItem if the Activity is still waiting for results to return.
                // The onActivityResult callback is executed
                ArrayList<ResultInfo> a = next.results;
                if(a ! =null) {
                    final int N = a.size();
                    if(! next.finishing && N >0) {
                        if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
                                "Delivering results to " + next + ":"+ a); transaction.addCallback(ActivityResultItem.obtain(a)); }}// Add NewIntentItem, where onNewIntent is executed
                if(next.newIntents ! =null) {
                    transaction.addCallback(NewIntentItem.obtain(next.newIntents,
                            false /* andPause */)); } transaction.setLifecycleStateRequest( ResumeActivityItem.obtain(next.app.repProcState, mService.isNextTransitionForward())); mService.getLifecycleManager().scheduleTransaction(transaction); . }catch (Exception e) {
                // Whoops, need to restart this activity!. mStackSupervisor.startSpecificActivityLocked(next,true.false);
                if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
                return true; }}... }else {
        // Whoops, need to restart this activity!. mStackSupervisor.startSpecificActivityLocked(next,true.true); }...return true;
}
Copy the code

Longer the streamline resumeTopActivityInnerLocked () code, the core logic is as follows:

  • First, through thestartPausingLocked()Suspension of the oldActivity.startPausingLocked()The method is as follows:
    final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
            ActivityRecord resuming, boolean pauseImmediately) {... mService.getLifecycleManager().scheduleTransaction(prev.app.thread, prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, prev.configChangeFlags, pauseImmediately)); . }Copy the code
    • This is the same as the frontClientTransactionEcho up, heh heh
  • ifActivityThe application is already started. YesActivityDisplay processing, createResumeActivityItemMake life cycle notifications
    • Eventually lead toActivityThe object’sonResume()Method execution
  • If the application has not yet been startedstartSpecificActivityLocked()Method To continue processing, the method is as follows:
    void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // Get the Activity's corresponding process
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
        if(app ! =null&& app.thread ! =null) {
            try{...// If application processes already exist, execute realStartActivityLocked()
                // andResume = true
                realStartActivityLocked(r, app, andResume, checkConfig);
                // Then return
                return;
            } catch (RemoteException e) {
            }
    
        }
        // The Activity's corresponding process is empty. Create a new process through AMS's startProcessLocked()
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true.0."activity", r.intent.getComponent(), false.false.true);
    }
    Copy the code
    • The core approach isrealStartActivityLocked(), even in the case of restarting the process, the final execution is the samerealStartActivityLocked()

ActivityStackSupervisor.realStartActivityLocked()

For the realStartActivityLocked() method, let’s take a quick look at the life cycle:

    final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {...// Create activity launch transaction.
        final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
                r.appToken);
        // Add LaunchActivityItem, which triggers the onCreate method
        clientTransaction.addCallback(LaunchActivityItem.obtain(newIntent(r.intent), ...) ;// Set the final state, resume or pause
        final ActivityLifecycleItem lifecycleItem;
        // According to the previous call parameters, andResume = true
        if (andResume) {
            // Set the final status to ON_RESUME
            lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
        } else {
            lifecycleItem = PauseActivityItem.obtain();
        }
        clientTransaction.setLifecycleStateRequest(lifecycleItem);
        // Schedule transaction.mService.getLifecycleManager().scheduleTransaction(clientTransaction); .return true;
    }
Copy the code

The LaunchActivityItem and ResumeActivityItem classes are added to the method, and the scheduleTransaction() method is called.

LaunchActivityItem is one of the more complex invocation logic

Using the LaunchActivityItem class as an example, let’s look at tracking downgrades:

public class LaunchActivityItem extends ClientTransactionItem {
    @Override
    public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {... client.handleLaunchActivity(r, pendingActions,null /* customIntent */); . }}Copy the code

This calls the handleLaunchActivity() method in ActivityThread:

    public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) {...finalActivity a = performLaunchActivity(r, customIntent); .return a;
    }
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {... Activity activity =null;
        try{ java.lang.ClassLoader cl = appContext.getClassLoader(); activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent); . }catch (Exception e) {
            ...
        }
        try{...if(activity ! =null) {... activity.mCalled =false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                if(! activity.mCalled) {throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onCreate()");
                }
                r.activity = activity;
            }
            // Set the state to ON_CREATE
            r.setState(ON_CREATE);
        } catch (SuperNotCalledException e) {
            throw e;
        } catch (Exception e) {
            ......
        }
        return activity;
    }
Copy the code

Is called Instrumentation. CallActivityOnCreate () method, the content is as follows:

    public void callActivityOnCreate(Activity activity, Bundle icicle) {
        prePerformCreate(activity);
        activity.performCreate(icicle);
        postPerformCreate(activity);
    }
Copy the code

The final pass is to call the activity.performCreate () method:

    final void performCreate(Bundle icicle, PersistableBundle persistentState) {...if(persistentState ! =null) {
            onCreate(icicle, persistentState);
        } else{ onCreate(icicle); }... }Copy the code

At this point, the LaunchActivityItem logic ends and the onCreate() callback is executed, setting the state to ON_CREATE.

However, since the final state in realStartActivityLocked() is set to ON_RESUME, the current Activity state is not final, so The TransactionExecutor will continue.