“This is my 28th day of participating in the First Challenge 2022. For details: First Challenge 2022.”

The application Activity Launcher process

After the main function of the ActivityThread is started, it initializes an ActivityThread object and calls its attach function. And finally call AMS’s attachApplicationLocked function. In this function, it mainly does:

  1. Start the Application object
  2. Start the Activity object

As follows, we continue our analysis from the previous paper

Application Start process analysis

In the initial article, we analyzed that the bindApplication function of the ApplicationThread object is called in AMS attachApplicationLocked

ApplicationThread.java
public final void bindApplication(String processName, ApplicationInfo appInfo,
        ProviderInfoList providerList, ComponentName instrumentationName,
        ProfilerInfo profilerInfo, Bundle instrumentationArgs,
        IInstrumentationWatcher instrumentationWatcher,
        IUiAutomationConnection instrumentationUiConnection, int debugMode,
        boolean enableBinderTracking, boolean trackAllocation,
        boolean isRestrictedBackupMode, boolean persistent, Configuration config,
        CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
        String buildSerial, AutofillOptions autofillOptions,
        ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges) {
    if(services ! =null) {
        / /...

        // Setup the service cache in the ServiceManager
        // Add the corresponding services required by AMS to the ServiceManager cache, so that in subsequent work,
        // You can directly obtain the corresponding service from the ServiceManager
        ServiceManager.initServiceCache(services);
    }

    setCoreSettings(coreSettings);
    // Initializes the AppBindData object and sets its corresponding parameters
    // This object holds the application information that started the application
    AppBindData data = new AppBindData();
    data.processName = processName;
    data.appInfo = appInfo;
    data.providers = providerList.getList();
    data.instrumentationName = instrumentationName;
    data.instrumentationArgs = instrumentationArgs;
    data.instrumentationWatcher = instrumentationWatcher;
    data.instrumentationUiAutomationConnection = instrumentationUiConnection;
    data.debugMode = debugMode;
    data.enableBinderTracking = enableBinderTracking;
    data.trackAllocation = trackAllocation;
    data.restrictedBackupMode = isRestrictedBackupMode;
    data.persistent = persistent;
    data.config = config;
    data.compatInfo = compatInfo;
    data.initProfilerInfo = profilerInfo;
    data.buildSerial = buildSerial;
    data.autofillOptions = autofillOptions;
    data.contentCaptureOptions = contentCaptureOptions;
    data.disabledCompatChanges = disabledCompatChanges;
    // Send the message, which is eventually processed in the ActivityThread.h class object
    sendMessage(H.BIND_APPLICATION, data);
}
Copy the code

As you can see, the main thing here is to initialize an AppBindData object and then process it by sending a message to the ActivityThread.h object

ActivityThread. H classpublic void handleMessage(Message msg) {
    switch (msg.what) {
        case BIND_APPLICATION:
            AppBindData data = (AppBindData)msg.obj;
            // Call handleBindApplication
            handleBindApplication(data);
            break;
        / /...}}private void handleBindApplication(AppBindData data) {
    / /...
    // Initialize an Instrumentation object
    mInstrumentation = new Instrumentation();
    mInstrumentation.basicInit(this);
    / /...

    try {
        // If the app is being launched for full backup or restore, bring it up in
        // a restricted environment with the base application class.
        // Initialize the Application object
        // If an Application class that inherits the Application class is defined in the Application's Androidmanifest.xml file, the class object is initialized here
        // If not, an Application base object is initialized
        This section uses AOSP Launcher3 as an example to initialize the Application object
        // It is worth mentioning that this function also adds the current Application object to the mAllApplications parameter of ActivityThread
        app = data.info.makeApplication(data.restrictedBackupMode, null);
        / /...
        mInitialApplication = app;
        // Run all contentProviders for the corresponding application
        if(! data.restrictedBackupMode) {if (!ArrayUtils.isEmpty(data.providers)) {
                installContentProviders(app, data.providers);
            }
        }
        / /...
        try {
            // Call the onCreate function of the Application object corresponding to ApplicationInfo
            // Of course, in our Application Launcher, we call the Application's default onCreate without doing anything
            mInstrumentation.callApplicationOnCreate(app);
        }
        / /...
    }
    / /...
}
Copy the code

In the code and remarks above, the Application onCreate function does nothing for the Application Launcher, but if some other Application defines an Application subclass object in androidmanifest.xml, The onCreate function will be called to perform some application-level initialization operations and start some key services, such as AOSP Dialer application.

In this way, we have finished analyzing the startup process of the Application.

Note: After the Application startup process has been analyzed, ProcessRecord’s makeActive function is called, which sets the thread parameter of ProcessRecord to the current ApplicationThread object. And set the mThread parameter value of its mWindowProcessController parameter to this object. Because the code is relatively simple, it is not analyzed here

Analyze the Activity startup process

The ATMS.LocalService object uses the attachApplication function to start the Activity declaration cycle

ActivityManagerService.java
if (normalMode) {
    try {
        / / mAtmInternal is a generally. The LocalService objects, the class inherits from ActivityTaskManagerInternal class
        didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
    } catch (Exception e) {
        Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
        badApp = true; }}public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
    / /...
    return mRootWindowContainer.attachApplication(wpc);
    / /...
}

boolean attachApplication(WindowProcessController app) throws RemoteException {
    boolean didSomething = false;
    for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
        / /...
        final DisplayContent display = getChildAt(displayNdx);
        for (int areaNdx = display.getTaskDisplayAreaCount() - 1; areaNdx >= 0; --areaNdx) {
            final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(areaNdx);
            for (int taskNdx = taskDisplayArea.getStackCount() - 1; taskNdx >= 0; --taskNdx) {
                // Get the previously created ActivityStack object, which holds the previously added ActivityRecord object to the top layer
                final ActivityStack rootTask = taskDisplayArea.getStackAt(taskNdx);
                / /...
                // PooledLambda will eventually call the function applied to the first argument
                final PooledFunction c = PooledLambda.obtainFunction(
                        RootWindowContainer::startActivityForAttachedApplicationIfNeeded, this,
                        PooledLambda.__(ActivityRecord.class), app,
                        rootTask.topRunningActivity());
                rootTask.forAllActivities(c);
                / /...
            }
        }
        didSomething |= mTmpBoolean;
    }
    / /...
    return didSomething;
}
Copy the code

Since the obtainFunction function of the PooledLambda class object eventually initializes the PooledFunction object and eventually runs the corresponding function reference for that object

rivate boolean startActivityForAttachedApplicationIfNeeded(ActivityRecord r, WindowProcessController app, ActivityRecord top) {
    / /...
    // realStartActivityLocked of the ActivityStackSupervisor object
    if (mStackSupervisor.realStartActivityLocked(r, app,
            top == r && r.isFocusable() /*andResume*/.true /*checkConfig*/)) {
        mTmpBoolean = true;
    }
    / /...
    return false;
}

boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
        boolean andResume, boolean checkConfig) throws RemoteException {
    / /...
    // Create activity launch transaction.
    // A ClientTransaction object is initialized here
    final ClientTransaction clientTransaction = ClientTransaction.obtain(
            proc.getThread(), r.appToken);

    final DisplayContent dc = r.getDisplay().mDisplayContent;
    // Add the current ClientTransaction object's callback,
    // Actually add the LaunchActivityItem here to the mActivityCallbacks parameter of the ClientTransaction object
    clientTransaction.addCallback(/ *... This parameter is temporarily ignored, when necessary to analyze */);
    / /...
    
    final ActivityLifecycleItem lifecycleItem;
    if (andResume) {
        // A ResumeActivityItem object is initialized here
        lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
    } else {
        lifecycleItem = PauseActivityItem.obtain();
    }
    // Lifecycle Request is set for ClientTransaction
    clientTransaction.setLifecycleStateRequest(lifecycleItem);
    
    // Schedule transaction.
    // Finally get the scheduleTransaction function of the ClientLifecycleManager object
    mService.getLifecycleManager().scheduleTransaction(clientTransaction);
    / /...
}
Copy the code

As you can see from the code and comments above, after initializing a ClientTransaction object and setting its Callback and Lifecycle State Request, The scheduleTransaction function of ClientListcycleManager is called to plan the business process

Before moving on to the code flow, it is important to review the structure of the ClientTransaction and ClientTransactionItem classes as follows

classDiagram Parcelable <|-- ClientTransactionItem ClientTransactionItem <|-- LaunchActivityItem ClientTransactionItem <|-- ActivityLifecycleItem BaseClientRequest <|-- ClientTransactionItem ObjectPoolItem <|-- BaseClientRequest ActivityLifecycleItem <|-- ResumeActivityItem ActivityLifecycleItem <|-- PauseActivityItem ActivityLifecycleItem <|-- StopActivityItem ActivityLifecycleItem <|-- DestroyActivityItem ActivityLifecycleItem <|-- StartActivityItem ClientTransaction <-- ClientTransactionItem Parcelable <|-- ClientTransaction ObjectPoolItem <|-- ClientTransaction ClientTransaction <-- ActivityLifecycleItem class BaseClientRequest { +preExecute(ClientTransactionHandler, IBinder) void default +execute(ClientTransactionHandler, IBinder, PendingTransactionActions) void +postExecute(ClientTransactionHandler, IBinder, PendingTransactionActions) void default } class ClientTransaction { +schedule() void } class ObjectPoolItem { #recycle()  void } class ClientTransactionItem { +getPostExecutionState() int +describeContents() int } class LaunchActivityItem { +preExecute(ClientTransactionHandler, IBinder) void +execute(ClientTransactionHandler, IBinder, PendingTransactionActions) void +postExecute(ClientTransactionHandler, IBinder, PendingTransactionActions) void -LaunchActivityItem() +recycle() +obtain(......) LaunchActivityItem -LaunchActivityItem(Parcel in) -setValues(......) void } <<interface>> ObjectPoolItem <<interface>> BaseClientRequest <<interface>> Parcelable <<abstract>> ClientTransactionItem <<abstract>> ActivityLifecycleItem

As you can see from this schematic

  1. Both ClientTransaction and ClientTransactionItem implement the Parcelable interface, which at least indicates that both objects can be carried through Message messages
  2. Both ActivityLifecycleItem and LaunchActivityItem inherit from ClientTransactionItem and are associated with ClientTransaction
  3. The ActivityLifecycleItem class contains five subclasses that, from their names, seem to correspond to the various stages of an Activity launch

We continue our code flow through the scheduleTransaction function of the ClientLifecycleManager object

void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    / /...
    transaction.schedule();
    / /...
}

public void schedule(a) throws RemoteException {
    // The mClient parameter is passed in when the ClientTransaction object's obtain function is called to initialize
    // It is passed in through the mThread argument of WindowProcessController, which is set through the makeActive function of ProcessRecord
    // Therefore, mClient is the inner class ApplicationThread object in the ActivityThread class
    mClient.scheduleTransaction(this);
}

public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    // Call ActivityThread's scheduleTransaction function. ActivityThread did not override this function
    // Therefore call the scheduleTransaction function of its parent class ClientTransactionHandler
    ActivityThread.this.scheduleTransaction(transaction);
}

void scheduleTransaction(ClientTransaction transaction) {
    // The preExecute function of the ClientTransaction object is called first
    transaction.preExecute(this);
    // The message is processed in ActivityThread.h after being sent
    sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
Copy the code

As you can see from the above code, there are two operations

  1. The preExecute function of the ClientTransaction object is called first, marking this as the A identifier
  2. After the message is sent, it is processed in ActivityThread.h

Let’s skip the first operation and look at the second operation

public void handleMessage(Message msg) {
    switch (msg.what) {
        case EXECUTE_TRANSACTION:
            / / -_ -
            final ClientTransaction transaction = (ClientTransaction) msg.obj;
            // Call the TransactionExecutor object's execute function
            mTransactionExecutor.execute(transaction);
            / /...}}public void execute(ClientTransaction transaction) {
    / /...
    // 1. Call executeCallbacks first
    executeCallbacks(transaction);
    // 2. Call the executeLifecycleState function
    executeLifecycleState(transaction);
    / /...
}
Copy the code

Call the executeCallbacks function

Following the code above, let’s take a look at the first point in the remarks

public void executeCallbacks(ClientTransaction transaction) {
    // Get the Callbacks in ClientTransaction,
    // Remember from the above code that the addCallback function corresponds to a LaunchActivityItem object
    // to the ClientTransaction object mActivityCallbacks parameter?
    final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
    / / not be empty
    if (callbacks == null || callbacks.isEmpty()) {
        // No callbacks to execute, return early.
        return;
    }
    / /...

    final IBinder token = transaction.getActivityToken();
    ActivityClientRecord r = mTransactionHandler.getActivityClient(token);

    / /...

    final int size = callbacks.size();
    for (int i = 0; i < size; ++i) {
        // Get the corresponding LaunchActivityItem object from ClientTransaction
        final ClientTransactionItem item = callbacks.get(i);
        / /...
        // Call the execute function of the LaunchActivityItem object, temporarily labeled b
        item.execute(mTransactionHandler, token, mPendingActions);
        // Call the postExecute function of the LaunchActivityItem object, temporarily labeled C
        item.postExecute(mTransactionHandler, token, mPendingActions);
        / /...}}Copy the code

With the code and comments above, we continue with the B and C identifiers

Call the executeLifecycleState function

We continue with the second point above, the executelifeccleState function

private void executeLifecycleState(ClientTransaction transaction) {
    // Get the Lifecycle Request of the ClientTransaction object
    // In the previously analyzed code, a ResumeActivityItem object was set
    final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
    / /...

    // Cycle to the state right before the final requested state.
    // Call cycleToPath
    Lifecycle Request object Lifecycle Request object Lifecycle Request object Lifecycle Request object Lifecycle Request object Lifecycle Request object Lifecycle Request
    // Check if there are any other states in the interval, if so, run the corresponding state function
    // We'll temporarily label it d here
    cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */, transaction);

    // Execute the final transition with proper parameters.
    // Run the execute function on the ResumeActivityItem object described above, which we temporarily identified here as e
    lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
    // Run the postExecute function for the ResumeActivityItem object above, which we temporarily identified here as f
    lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
}
Copy the code

With the code and comments above, we continue to annotate E and F

summary

As for the overall code analysis above, our identifiers are:

  1. A calls the preExecute function of ClientTransaction
  2. B Calls the execute function of the LaunchActivityItem object
  3. C calls the postExecute function of the LaunchActivityItem object
  4. D calls the TransactionExecutor cycleToPath function
  5. E Calls the execute function of the ResumeActivityItem object
  6. F calls the postExecute function of the ResumeActivityItem object

The code represented by these symbols also forms the lifecycle of an Activity, which we’ll examine in the next article