In a recent review see the ams is found that the Android Q source has modified, the activity start to have activitytaskmanagerservice implementation, the blog articles are based on the ams, so to record your own learning process, if there are any errors, please correction. This paper mainly analyzes the general process.

First listed the core classes: Activity: interface display UI operations, such as everyone is familiar with ActivityThread: application of the main thread, entrance ActivityTaskManagerService (ATMS) : ActivityManagerService(AMS) : manages activities in the same parent class as ATMS, ActivityStarter: starts mode, starts Flag, and handles ActivityStack: ActivityStackSupervisor is responsible for managing individual stack activities and their state, that is, the specific execution of the startup. ClientTransaction: Handles related information and lifecycle states. TransactionExecutor: manages the execution order of information

Set the MainActivity(home page) startup mode to singleTask, then start other activities in standard mode, and then click the home button to enter the background, click the icon again, how to go the life cycle:

First, start the general process

Click the icon to start –ATMS detects if there is a running Activity– notifies the application to pause when the running Activity completes –ATMS detects if the process exists — starts the target Activity, does not start the process, and then starts the application

In addition, attached is a personal summary of the start-up process, the process is more complex, put a separate link, interested can be combined with this to see. www.processon.com/view/link/5…

Two, combined with source code analysis

1, click on the desktop icon to start the Launcher. StartActivitySafely — Activity. StartActivity interested in desktop to start the details you can refer to this blog

2, enter the Activity Activity. StartActivity – > Activity. StartActivityForResult

  options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
Copy the code

Then call mInstrumentation execStartActivity method, everyone pay attention to the incoming parameters Instrumentation this class is responsible for application and system process of interaction, as well as the application and Activity class loading operations such as: newActivity; newApplication

3, mInstrumentation execStartActivity method, using the binder mechanism, across processes call ATMS. StartActivity

intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(who); int result = ActivityTaskManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target ! = null ? target.mEmbeddedID : null, requestCode, 0, null, options);Copy the code

4, enter the system process, call the ATMS. StartActivity method, then call its internal class method once, and finally call the startActivityAsUser method

 return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setMayWait(userId)
                .execute();
Copy the code

From here, go to ActivityStarter, which handles startup mode, FLAG, and so on

5. Go to ActivityStarter and execute to see if you need to wait. There are two methods

if (mRequest.mayWait) {
    startActivityMayWait
} else {
    startActivity
}
Copy the code

Then step by step to the startActivityUnchecked method, which is the key method, because some of the core processing is here, and the answer to the above question is here

  • The following three methods are called first
computeLaunchingTaskFlags();
computeSourceStack();
ActivityRecord reusedActivity = getReusableIntentActivity();

Copy the code
  • ComputeLaunchingTaskFlags will according to different situations, reconfigure the intent. The FlAG, you can have a look at the source code, part of the code listed below, for from the processing of the Activity, such as ContextImpl launched, There is also handling for SigleInstance
         if (mInTask == null) {
            if(mSourceRecord == null) {// The target Activity is created entirely, in which case a new task is always startedif ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
                    Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
                            "Intent.FLAG_ACTIVITY_NEW_TASK for: "+ mIntent); mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; }}else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
                // The original activity who is starting us is running as a single
                // instance...  this new activity it is starting must go on its
                // own task.
                mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
            } else if(isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) { // The activity being started is a single instance... it always // gets launched into its own task. mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; }}Copy the code
  • ComputeSourceStack is responsible for processing sourceRecord to see if it is finishing, if it is, copy its information, and then set it to null.
if(! mSourceRecord.finishing) { mSourceStack = mSourceRecord.getActivityStack();return;
        }

        // If the source is finishing, we can't further count it as our source. This is because the // task it is associated with may now be empty and on its way out, so we don't want to
        // blindly throw it in to that task.  Instead we will take the NEW_TASK flow and try to find
        // a task for it. But save the task information so it can be used when creating the new task.
        if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
            Slog.w(TAG, "startActivity called from finishing " + mSourceRecord
                    + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
            mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
            mNewTaskInfo = mSourceRecord.info;

            // It is not guaranteed that the source record will have a task associated with it. For,
            // example, if this method is being called for processing a pending activity launch, it
            // is possible that the activity has been removed from the task after the launch was
            // enqueued.
            final TaskRecord sourceTask = mSourceRecord.getTaskRecord();
            mNewTaskIntent = sourceTask ! = null ?sourceTask.intent : null;
        }
        mSourceRecord = null;
        mSourceStack = null;
Copy the code
  • GetReusableIntentActivity to a method to judge whether the background process to switch to the front desk, if it is; Returns the activity reused at the top of the current task; If not, look for the target activity in the task belonging to the application. If it’s not found, it’s null, and that’s where SingleInstance is handled. The search for a separate optimization, this method is more important, you can take a look at the source. And that’s why when we go to the foreground, it shows the previous interface, so the logic is there, right
        // If bring to front is requested, and no result is requested and we have not been given
        // an explicit task to launch in to, and we can find a task that was started with this
        // same component, then instead of launching bring that one to the front.
        putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
        ActivityRecord intentActivity = null;
        if(mOptions ! = null && mOptions.getLaunchTaskId() ! = -1) { final TaskRecord task = mRootActivityContainer.anyTaskForId(mOptions.getLaunchTaskId()); intentActivity = task ! = null ? task.getTopActivity() : null; }else if(putIntoExistingTask) { ..... Specific can see the source}Copy the code

So let’s go back to the startActivityUnchecked method above, which, when it finds a reusable activity that starts in SingleInstance or SinleTask mode, it removes it,

 if((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) ! = 0 || isDocumentLaunchesIntoExisting(mLaunchFlags) || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) { final TaskRecord task = reusedActivity.getTaskRecord(); // In this situation we want to remove all activities from the task up to the one // being started. In most cases this means we are resetting the task to its initial // state. final ActivityRecord top = task.performClearTaskForReuseLocked(mStartActivity, mLaunchFlags); }Copy the code

It removes the activity before the target activity in the stack of reusable activities, not the reused activity. == This is also the answer to the above question. When set to singleTask, destory the activity above first, and destoryB first

6, then according to the different situation, but in the end will enter ActivityStack. ResumeTopActivityInnerLocked, because the process is complicated, the general steps listed first, and then the analysis one by one

  • Start by suspending an activity that is already running
 boolean pausing = getDisplay().pauseBackStacks(userLeaving, next, false);
Copy the code
  • After the pause, check whether the process exists
if (next.attachedToProcess()) {}
Copy the code
  • If not, the application is told to start the process, which is not analyzed here, but will definitely call ActivityThread.main
  • Existential reuse

7. Pause the application, and in pauseBackStacks, ActivityStack’s startPausingLocked is called

if(resumedActivity ! = null && (stack.getVisibility(resuming) ! = STACK_VISIBILITY_VISIBLE || ! stack.isFocusable())) {if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack +
                        " mResumedActivity=" + resumedActivity);
                someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
                        dontWait);
            }
Copy the code

Pass in information like the PauseActivityItem and the thread that ran the activity before

  mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
     prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
      prev.configChangeFlags, pauseImmediately));                                             
Copy the code

Then call ClientTransaction. The schedule

void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
        final IApplicationThread client = transaction.getClient();
        transaction.schedule();
        if(! (client instanceof Binder)) { // If client is not an instance of Binder - it's a remote call and at this point it is // safe to recycle the object. All objects used for local calls will be recycled after // the transaction is executed on client in ActivityThread. transaction.recycle(); } //mClient:private IApplicationThread mClient; Very well, Is ActivityThread. ApplicationThread public void the schedule () throws RemoteException {mClient. ScheduleTransaction (this); }Copy the code

So that brings us back to ActivityThread, and if you look at the parent class of ActivityThread, you’re in the application process

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

The methods called here are those of the ActivityThread parent class ClientTransactionHandler

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

Before going back to activityThread. H, remember the PasuingActivityItem passed in earlier

case EXECUTE_TRANSACTION:
  final ClientTransaction transaction = (ClientTransaction) msg.obj;
  mTransactionExecutor.execute(transaction);
       if (isSystem()) {
          // Client transactions inside system process are recycled on the client side
          // instead of ClientLifecycleManager to avoid being cleared before this
          // message is handled.
                        transaction.recycle();
  }                                                               
Copy the code

Go into TransactionExecutor, execute the execute method, and there are two important methods for this method

executeCallbacks(transaction);
executeLifecycleState(transaction);
Copy the code

The main analysis is executeCallbacks

final ActivityLifecycleItem finalStateRequest = transaction.getLifecycleStateRequest();
item.execute(mTransactionHandler, token, mPendingActions);
item.postExecute(mTransactionHandler, token, mPendingActions);
Copy the code

In this method, we call the PauseActivityItem method we passed in earlier

public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
        client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions,
                "PAUSE_ACTIVITY_ITEM");
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }
Copy the code
 public void postExecute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        if (mDontReport) {
            return; } try { // TODO(lifecycler): Use interface callback instead of AMS. ActivityTaskManager.getService().activityPaused(token); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); }}Copy the code

There are two methods, one is the client. The handlePauseActivity, client is ClientTransactionHandler, namely ActivityThread. So you will be suspended Another is ActivityTaskManager. GetService () activityPaused (token); Notify ATMS of the completion of the pause, proceed with the action related to the pause information, at this point the pause is complete. The pause process of the activity is understood.

  • And then there’s another question, how does the next lifecycle approach go, or the one before that,
 // Cycle to the state right before the final requested state.
        cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */, transaction);
Copy the code

If you look at the comments, this is the final state before going through the configured state

if(closestPreExecutionState ! = UNDEFINED) { cycleToPath(r, closestPreExecutionState, transaction); } item.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions);Copy the code

The cycleToPath method will eventually call performLifecycleSequence, which will call the corresponding methods in the order configured

 /** Transition the client through previously initialized state sequence. */
    private void performLifecycleSequence(ActivityClientRecord r, IntArray path, ClientTransaction transaction) 
Copy the code

8, the process exists, reuses, and pauses behind the logical type, only the ResumeActivityItem passed in is not expanded here

9. Next, analyze the situation where the application is not started

  • ActivityThread.main
  • ActivityThread.attach
final IActivityManager mgr = ActivityManager.getService();
    try {
         mgr.attachApplication(mAppThread, startSeq);
        } catch (RemoteException ex) {
          throw ex.rethrowFromSystemServer();
    }
Copy the code

Enter attachApplication in AMS, which is to notify system processes of reference start. In this case, threads are started, and attachApplicationLocked is invoked

thread.bindApplication(processName, appInfo, providers, instr2.mClass, profilerInfo, instr2.mArguments, instr2.mWatcher, instr2.mUiAutomationConnection, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || ! normalMode, app.isPersistent(), new Configuration(app.getWindowProcessController().getConfiguration()), app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, autofillOptions, contentCaptureOptions, disabledCompatChanges); . // See if the top visible activity is waiting to run in this process... if (normalMode) { try { didSomething = mAtmInternal.attachApplication(app.getWindowProcessController()); } catch (Exception e) { Slog.wtf(TAG, "Exception thrown launching activities in " + app, e); badApp = true; }}Copy the code
  • Configure the properties of the application
  • thread.bindApplcation
  • mAtmInternal.attachApplication(app.getWindowProcessController());

One thread bindApplicaion, namely ActivityThread. ApplicationThread. BindApplication

sendMessage(H.BIND_APPLICATION, data); / / in ActivityThread. H handleMessagecase BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break
Copy the code

Completes application initialization in handleBindApplication,

if(! data.restrictedBackupMode) {if(! ArrayUtils.isEmpty(data.providers)) { installContentProviders(app, data.providers); } } mInstrumentation.callApplicationOnCreate(app);Copy the code

You can see here that the ContentProvider precedes the application.oncreate method,

– Next, start the Activity

 didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
Copy the code

class LocalService extends ActivityTaskManagerInternal

  • Call ATMS. LocalService. AttachApplication
 public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
            synchronized (mGlobalLockWithoutBoost) {
                returnmRootActivityContainer.attachApplication(wpc); }}Copy the code

The last call ActivityStack realStartActivityLocked

clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
Copy the code

The following process is similar to pasue and resume, but will not be described.

To this point, the activity startup related core classes and core steps are included, and do a simple introduction. Then you need to dig into that piece of code and just look at the right code. I hope I can help you and make progress together.