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

The application Activity Launcher process (Initial)

From the aforementioned application process startup process analysis (client) and application process startup process analysis (server), we describe the application process FORK and startup process with the startup process of the application process Launcher, then we continue to analyze the application Activity startup process of the first two.

Before we look at the ActivityThread main function, we need to reorganize the basic structure of the ActivityThread class as follows:

classDiagram ClientTransactionHandler <|-- ActivityThread Handler <|-- H ActivityThread *-- H ActivityThread *-- AppBindData ActivityThread *-- ActivityClientRecord ActivityThread *-- ApplicationThread IApplicationThread *-- Stub Stub <|-- ApplicationThread <<abstract>> ClientTransactionHandler <<interface>> Stub class ActivityThread { +main(String[] args) void -attach(boolean system, long startSeq) void -installContentProviders(Context context, List<ProviderInfo> providers) void -handleBindApplication(AppBindData data) void +handleLaunchActivity(ActivityClientRecord, PendingTransactionActions, Intent) Activity } class ClientTransactionHandler { #scheduleTransaction(ClientTransaction transaction) void } class H {  +handleMessage(Message msg) void }

As you can see here, the ActivityThread class inherits from the ClientTransactionHandler abstract class and contains four inner classes, where

  1. Class H inherits from Handler and overrides Handler’s handleMessage function
  2. The ApplicationThread class inherits from the iAppliactionThread. Stub object and uses Binder communication to pass data
  3. AppBindData stores basic information about application processes

What does the main function of ActivityThread do

public static void main(String[] args) {
    / /...
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
    / /...
}
Copy the code

The Main function of the ActivityThread primarily initializes the ActivityThread object and calls its attach function.

However, before we analyze the attach function, first we need to confirm what the second parameter startSeq is.

What does the second parameter startSeq to the attach function of ActivityThread represent

Tracing the startSeq parameter value, you can see that it is passed in the main function of ActivityThread with the corresponding parameter value of the “seq=” string in args

public static void main(String[] args) {
    / /...
    long startSeq = 0;
    if(args ! =null) {
        for (int i = args.length - 1; i >= 0; --i) {
            if(args[i] ! =null&& args[i].startsWith(PROC_START_SEQ_IDENT)) { startSeq = Long.parseLong( args[i].substring(PROC_START_SEQ_IDENT.length())); }}}/ /...
}
Copy the code

The args of the main function is based on the parameters passed during the process of starting the process. When it comes to the process of starting the process, the parameter data of the server is transmitted from the client through the Socket of Zygote. Therefore, it can be traced back to the code of the client

ProcessList.java
boolean startProcessLocked(...) {
    / /...
    final long startSeq = app.startSeq = ++mProcStartSeqCounter;
    / /...
    mPendingStarts.put(startSeq, app);

    / /...
    final Process.ProcessStartResult startResult = startProcess(hostingRecord,
            entryPoint, app,
            uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo,
            requiredAbi, instructionSet, invokeWith, startTime);
    / /...
}

private Process.ProcessStartResult startProcess(...) {
    / /...
    // Notice the last parameterstartResult = Process.start(...... .new String[]{PROC_START_SEQ_IDENT + app.startSeq});
    / /...
}

ZygoteProcess.java
private Process.ProcessStartResult startViaZygote(args[......]
                                                  @Nullable String[] extraArgs)
                                                  throws ZygoteStartFailedEx {
    / /...

    if(extraArgs ! =null) {
        Collections.addAll(argsForZygote, extraArgs);
    }
    / /...
    returnzygoteSendArgsAndGetResult(...... , argsForZygote);/ /...
}
Copy the code

Therefore, the value of the startSeq parameter passed in the attach function of the ActivityThread object above is an index value generated in the ProcessList object during process startup. This index value and the corresponding ProcessRecord object containing the Activity information generate <key, value>, which is saved in the mPendingStarts parameter object of ProcessList

The Attach function of the ActivityThread runs

Next, let’s take a look at what the Attach function of ActivityThread does

final ApplicationThread mAppThread = new ApplicationThread();

private void attach(boolean system, long startSeq) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    // Pass the argument false
    if(! system) {/ /...
        // Get the corresponding ActivityManagerService object
        final IActivityManager mgr = ActivityManager.getService();
        try {
            // call AMS attachApplication
            mgr.attachApplication(mAppThread, startSeq);
        }
        / /...
        // Watch for getting close to heap limit.
        // Listen to the current heap memory information, timely reclaim memory space
        BinderInternal.addGcWatcher(new Runnable() {
            @Override public void run(a) {
                / /...}}); }/ /...
    ViewRootImpl.ConfigChangedCallback configChangedCallback
            = (Configuration globalConfig) -> {
        / /...
    };
    ViewRootImpl.addConfigCallback(configChangedCallback);
}
Copy the code

AttachApplication (AMS) is invoked in this function, and a listener for heap memory information is added to release and reclaim memory space in time

ActivityManagerService.java
public final void attachApplication(IApplicationThread thread, long startSeq) {
    / /...
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final longorigId = Binder.clearCallingIdentity(); attachApplicationLocked(thread, callingPid, callingUid, startSeq); Binder.restoreCallingIdentity(origId); }}private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
    / /...
    ProcessReocrd, which starts with a key of startReq, can be obtained from the mPendingStarts parameter
    // Of course, here is the information for the application Launcher to start the Activity
    // It's possible that process called attachApplication before we got a chance to
    // update the internal state.
    if (app == null && startSeq > 0) {
        final ProcessRecord pending = mProcessList.mPendingStarts.get(startSeq);
        if(pending ! =null && pending.startUid == callingUid && pending.startSeq == startSeq
                && mProcessList.handleProcessStartedLocked(pending, pid, pending
                        .isUsingWrapper(),
                        startSeq, true)) { app = pending; }}/ /...
    
    // Get all ContentProvider information contained in the current application
    boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
    List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
    / /...
    final BackupRecord backupTarget = mBackupTargets.get(app.userId);
    try {
        / /...ApplicationInfo appInfo = instr ! =null ? instr.mTargetInfo : app.info;
        app.compat = compatibilityInfoForPackage(appInfo);

        / /...

        mAtmInternal.preBindApplication(app.getWindowProcessController());
        final ActiveInstrumentation instr2 = app.getActiveInstrumentation();
        if(mPlatformCompat ! =null) {
            mPlatformCompat.resetReporting(app.info);
        }
        final ProviderInfoList providerList = ProviderInfoList.fromList(providers);
        / /...
        thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
                null.null.null, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || ! normalMode, app.isPersistent(),new Configuration(app.getWindowProcessController().getConfiguration()),
                app.compat, getCommonServicesLocked(app.isolated),
                mCoreSettingsObserver.getCoreSettingsLocked(),
                buildSerial, autofillOptions, contentCaptureOptions,
                app.mDisabledCompatChanges);

        // Make app active after binding application or client may be running requests (e.g
        // starting activities) before it is ready.
        // Notice that the ProcessRecord object's makeActive function sets the current ApplicationThread object to ProcessRecord
        // This will be used in the subsequent analysis
        app.makeActive(thread, mProcessStats);
        / /...
    }
    
    // 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; }}/ /... This article will only discuss the startup process of the Activity, and the subsequent services, broadcasting and other startup will not be analyzed temporarily
    return true;
}
Copy the code

And as you can see from this side, eventually

  1. Call the bindApplication function of the ApplicationThread object here to start the entire Application
  2. Object. Then by calling ActivityTaskManagerService LocalService attachApplication function to start the Activity, enter the Activity of the whole statement cycle