“This is the fifth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

preface

We have written the startup process of APP and system before, so we can understand it first

Activity Start Analysis

The startup of an Activity is divided into the following types: When the system app is started, users configure the Activity corresponding to the following intent-filter in androidmanifest.xml

<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
Copy the code

And start the Activity within the app after the app is opened.

The system App starts and the user App’s main Activity

When the Android system starts, Zygote forks the SystemServer process. The SystemServer process starts some of the system services, including ActivityManagerServic and creates the system context. The following is a snippet of the system context created by calling the run method when systemServer.java is initialized, and we can see that the ActivityThread is created and attached to the Application from here

private void createSystemContext(a) {
    ActivityThread activityThread = ActivityThread.systemMain();
    mSystemContext = activityThread.getSystemContext();
    mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);

    final Context systemUiContext = activityThread.getSystemUiContext();
    systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
}
Copy the code

Here is the attach method in the ActivityThread.


private void attach(boolean system, long startSeq) {
 / /...
    if(! system) {// The system is not started
      / /...
        try {
        Call AMS attachApplication
            mgr.attachApplication(mAppThread, startSeq);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    / /...
    } else {
          / /...
        try {
        / /... Create the application
            mInitialApplication = context.mPackageInfo.makeApplication(true.null);
            mInitialApplication.onCreate();
        } catch (Exception e) {
         
        }
    }
/ /...
}
Copy the code

Attach input Boolean SYSTEM Determines whether the system is started or the user’s application is started. For system startup, the Application is created and the onCreate method is called. For user App startup, AMS attachApplication is called and attachApplicationLocked is called

private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
/ /...
if(app.getIsolatedEntryPoint() ! =null) {
    // This is an isolated process which should just call an entry point instead of
    // being bound to an application.
    The main () method of ActivityThread is run if the entry point is ActivityThread
    thread.runIsolatedEntryPoint(
            app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());
            
} else if(instr2 ! =null) {
     The ProcessRecord Instrumention object is Instrumention. If the ProcessRecord object is not empty, the ProcessRecord Instrumention object is Instrumentionthread.bindApplication(processName, appInfo, providerList, instr2.mClass, profilerInfo, instr2.mArguments, instr2.mWatcher, instr2.mUiAutomationConnection, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || ! normalMode, app.isPersistent(),new Configuration(app.getWindowProcessController().getConfiguration()),
            app.getCompat(), getCommonServicesLocked(app.isolated),
            mCoreSettingsObserver.getCoreSettingsLocked(),
            buildSerial, autofillOptions, contentCaptureOptions,
            app.getDisabledCompatChanges(), serializedSystemFontMap);
} else {
    thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
            null.null.null, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || ! normalMode, app.isPersistent(),new Configuration(app.getWindowProcessController().getConfiguration()),
            app.getCompat(), getCommonServicesLocked(app.isolated),
            mCoreSettingsObserver.getCoreSettingsLocked(),
            buildSerial, autofillOptions, contentCaptureOptions,
            app.getDisabledCompatChanges(), serializedSystemFontMap);
}
    return true;
}
Copy the code

You can see that the bindApplication method in ActivityThread is then called, and we follow up with the bindApplication method

@Override
public final void bindApplication(...). {
    / /...

    AppBindData data = new AppBindData();
    data.processName = processName;
    / /...
    // Call Handler to create the Application
    sendMessage(H.BIND_APPLICATION, data);
}

public void handleMessage(Message msg) {
    switch (msg.what) {
        case BIND_APPLICATION:
            AppBindData data = (AppBindData)msg.obj;
            handleBindApplication(data);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            break;
            / /...
}
Copy the code

You can see that you end up using the Handler to create the Application and call the onCreate method

The Activity starts within the application

As you have seen above, the activity start is eventually delivered to startActivity in the ATMS

@Override
public final int startActivity(..) {
    return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
            resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
            UserHandle.getCallingUserId());

    //startActivity will eventually call startActivityAsUser
private int startActivityAsUser(...).;

    userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
            Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
    
    / / getActivityStartController (.) obtainStarter () is a ActivityStarter object
    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();

}

Copy the code

Here we go to the StartStarter object. Execute the execute method. Execute ends up calling realStartActivityLocked in ActivityStackSupervisor.

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

            / /... Omit N more code

            // Create the clientTransaction that starts the activity
            final ClientTransaction clientTransaction = ClientTransaction.obtain(
                    proc.getThread(), r.appToken);
            // omit N more code

            // Submit things through ClientLifecycleManager
            mService.getLifecycleManager().scheduleTransaction(clientTransaction);
}
Copy the code

We follow up to CLientLifecycleMnager to find the scheduleTransaction method

void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    final IApplicationThread client = transaction.getClient();
    transaction.schedule();
    if(! (clientinstanceof 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(); }}Copy the code
private IApplicationThread mClient;

public void schedule(a) throws RemoteException {
    mClient.scheduleTransaction(this);
}
Copy the code

You can see that mClient is the applicationThread object

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

Proceed to call scheduleTransaction from ActivityThread’s parent class ClientTransactionHandler

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

// Use handlers in ActivityThread to process messages
private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);
case EXECUTE_TRANSACTION:
    final ClientTransaction transaction = (ClientTransaction) msg.obj;
    mTransactionExecutor.execute(transaction);
    break;
    
  // mTransactionExecutor.execute()
public void execute(ClientTransaction transaction) {
    final IBinder token = transaction.getActivityToken();
    if(token ! =null) {
        final Map<IBinder, ClientTransactionItem> activitiesToBeDestroyed =
                mTransactionHandler.getActivitiesToBeDestroyed();
        final ClientTransactionItem destroyItem = activitiesToBeDestroyed.get(token);
        if(destroyItem ! =null) {
            if (transaction.getLifecycleStateRequest() == destroyItem) {
                // It is going to execute the transaction that will destroy activity with the
                // token, so the corresponding to-be-destroyed record can be removed.
                activitiesToBeDestroyed.remove(token);
            }
            if (mTransactionHandler.getActivityClient(token) == null) {
                // The activity has not been created but has been requested to destroy, so all
                // transactions for the token are just like being cancelled.
                Slog.w(TAG, tId(transaction) + "Skip pre-destroyed transaction:\n"
                        + transactionToString(transaction, mTransactionHandler));
                return; }}}// omit N more code
    executeCallbacks(transaction);
    executeLifecycleState(transaction);
}
public void executeCallbacks(ClientTransaction transaction) {
        // omit N more code
        

  // While instantiating ClientTransaction in activitystackcontainer #realStartActivityLocked the addCallback is passing in the LaunchActivityItem; / / so there is actually LaunchActivityItem of execution. The execute method
        item.execute(mTransactionHandler, token, mPendingActions);
        item.postExecute(mTransactionHandler, token, mPendingActions);
}
Copy the code

From the above code comments can know that our final call is LaunchActivityItem the execute method

@Override
public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {
            mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
            mPendingResults, mPendingNewIntents, mIsForward,
            mProfilerInfo, client, mAssistToken, mFixedRotationAdjustments);
            // Because the ActivityThread inherits ClientTransactionHandler, the ActivityThread's handleLaunchActivity is eventually called
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
}
Copy the code

PerformLaunchActivity is also called in the handlerActivity, which is the core method for starting the activity, as you can see from the official website comments below

/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ActivityInfo aInfo = r.activityInfo;
    if (r.packageInfo == null) {
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                Context.CONTEXT_INCLUDE_CODE);
    }

    ComponentName component = r.intent.getComponent();
    if (component == null) {
        component = r.intent.resolveActivity(
            mInitialApplication.getPackageManager());
        r.intent.setComponent(component);
    }

    if(r.activityInfo.targetActivity ! =null) {
        component = new ComponentName(r.activityInfo.packageName,
                r.activityInfo.targetActivity);
    }

    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        r.intent.prepareToEnterProcess();
        if(r.state ! =null) { r.state.setClassLoader(cl); }}catch (Exception e) {
        if(! mInstrumentation.onException(activity, e)) {throw new RuntimeException(
                "Unable to instantiate activity " + component
                + ":"+ e.toString(), e); }}try {
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
        if (localLOGV) Slog.v(
                TAG, r + ": app=" + app
                + ", appName=" + app.getPackageName()
                + ", pkg=" + r.packageInfo.getPackageName()
                + ", comp=" + r.intent.getComponent().toShortString()
                + ", dir=" + r.packageInfo.getAppDir());

        if(activity ! =null) {
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            if(r.overrideConfig ! =null) {
                config.updateFrom(r.overrideConfig);
            }
            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                    + r.activityInfo.name + " with config " + config);
            Window window = null;
            if(r.mPendingRemoveWindow ! =null && r.mPreserveWindow) {
                window = r.mPendingRemoveWindow;
                r.mPendingRemoveWindow = null;
                r.mPendingRemoveWindowManager = null;
            }

            // Activity resources must be initialized with the same loaders as the
            // application context.
            appContext.getResources().addLoaders(
                    app.getResources().getLoaders().toArray(new ResourcesLoader[0]));

            appContext.setOuterContext(activity);
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config,
                    r.referrer, r.voiceInteractor, window, r.configCallback,
                    r.assistToken);

            if(customIntent ! =null) {
                activity.mIntent = customIntent;
            }
            r.lastNonConfigurationInstances = null;
            checkAndBlockForNetworkAccess();
            activity.mStartedActivity = false;
            int theme = r.activityInfo.getThemeResource();
            if(theme ! =0) {
                activity.setTheme(theme);
            }

            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;
            mLastReportedWindowingMode.put(activity.getActivityToken(),
                    config.windowConfiguration.getWindowingMode());
        }
        r.setState(ON_CREATE);

        // updatePendingActivityConfiguration() reads from mActivities to update
        // ActivityClientRecord which runs in a different thread. Protect modifications to
        // mActivities to avoid race.
        synchronized(mResourcesManager) { mActivities.put(r.token, r); }}catch (SuperNotCalledException e) {
        throw e;

    } catch (Exception e) {
        if(! mInstrumentation.onException(activity, e)) {throw new RuntimeException(
                "Unable to start activity " + component
                + ":"+ e.toString(), e); }}return activity;
}
Copy the code

From the above code, we can see the figure of the important Application Window and the attach call of the Activity in our application. The activity is now fully started

// It’s been two days and I’m so tired… There e are too many details to analyze.