When I click on the App icon of the Launcher, I click on the onClickAppShortcut that’s passed to ItemClickHandler, And ultimately calls to the launcher. The startActivitySafely – > BaseDraggingActivity. StartActivitySafely:

    public boolean startActivitySafely(View v, Intent intent, @Nullable ItemInfo item,
            @Nullable String sourceContainer) {
        // ...
        // Set the Intent Flag to FLAG_ACTIVITY_NEW_TASK
        // Start the Activity in a new Activity task stack
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        // ...
        try {
            / /... Omit some shortcuts to start
            else if (user == null || user.equals(Process.myUserHandle())) {
                // Could be launching some bookkeeping activity
                // Start the application Activity
                startActivity(intent, optsBundle);
                AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(),
                        Process.myUserHandle(), sourceContainer);
            }
            // ...
            return true;
        } catch (NullPointerException|ActivityNotFoundException|SecurityException e) {
            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
        }
        return false;
    }
Copy the code

The implementation of startActivity is in the Activity:

    public void startActivity(Intent intent, @Nullable Bundle options) {
        / /... Both call startActivityForResult to start the Activity
        // The incoming requestCode is -1
        if(options ! =null) {
            startActivityForResult(intent, -1, options);
        } else {
            startActivityForResult(intent, -1); }}Copy the code

Start the Activity through the final Instrumentation execStartActivity method to start, and the role of Instrumentation is actually monitoring the application and system interaction in the middle of this, is a layer of Android Hook operation, ExecStartActivity execStartActivity execStartActivity execStartActivity execStartActivity execStartActivity execStartActivity execStartActivity execStartActivity execStartActivity

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

ActivityTaskManager is a new class added to Android 10 that takes over the role of activities interacting with ActivityTasks in ActivityManager. And ActivitTaskManager. GetService return is IActivityTaskManager the AIDL document declared in the interface, And system services in the process of the SystemServer ActivityTaskManagerService only needs to inherit IActivityTaskManager. The Stub can realize the user process and service process of communication.

new Singleton<IActivityTaskManager>() {
	@Override
	protected IActivityTaskManager create(a) {
		final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
		returnIActivityTaskManager.Stub.asInterface(b); }};Copy the code

First get SystemServer ActivityTaskManagerService this system in the process of service’s IBinder interface, and then converts the IBinder interface IActivityTaskManager interface, This allows the reference process to call the methods of IActivityTaskManager to communicate with the ATMS.

The application process calls the startActivity method of the ATMS, and the logic to create the Activity goes from the Launcher process to the SystemServer process of the ATMS:

In the ATMS startActivity, call ATMS. StartActivityAsUser:

    private int startActivityAsUser(IApplicationThread caller, String callingPackage,
            @Nullable String callingFeatureId, Intent intent, String resolvedType,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
        // Verify the pre-permission
        // Get the ActivityStart object
        // This object is a proxy object that controls the start of the Activity
        // After 7.0, collect all kinds of parameter logic related to the Activity start
        // Decide how to start the Activity level 1 Task and TaskStack association
        return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
                / /... A lot of parameters are set
                .execute();

    }
Copy the code

After setting a bunch of parameters to the ActivityStarter object, call it execute to start:

    int execute(a) {
        try {
            // ...
            int res;
            synchronized (mService.mGlobalLock) {
                // ...
                // The startup information is in mRequest, execute the request
                res = executeRequest(mRequest);
								// Start some notification after completion of work......}}finally{ onExecutionComplete(); }}Copy the code

Executterequest contains a lot of validation logic, such as checking startup parameters, Flag, etc. The normal startup process will create an ActivityRecord object based on various startup parameters. The ActivityRecord object represents an Activity entity in the task stack that is finally called to ActivityStarter’s startActivityUnchecked.

StartActivityUnchecked ->startActivityInner. In startActivityInner, check the Activity Flag. For example, if you start a root Activity, But instead of FLAG_ACTIVITY_NEW_TASK, the LaunchFlag is changed to FLAG_ACTIVITY_NEW_TASK. It then finds out if there is a task stack that can be reused. If not, it creates a new task stack. The core logic of startActivityInner is to call:

mRootWindowContainer.resumeFocusedStacksTopActivities(
                        mTargetStack, mStartActivity, mOptions);
Copy the code

RootWindowContainer is an object created in the WMS and can be understood as the content displayed on its manager screen. In RootWindowContainer, it calls to ActivityStack resumeTopActivityUncheckedLocked – > resumeTopActivityInnerLocked. This method is 400+ lines long on 11 and has a lot of logic. Key points related to the main process we are analyzing are as follows:

// attachedToProcess determines whether the process to start the Activity exists and
// Whether the ActivityThread for the corresponding process exists, and we are starting a new process
//, before the new process is created and ActivityRecord is bound to the new process
if (next.attachedToProcess()) {
  // ...
} else {
  // ...
  mStackSupervisor.startSpecificActivity(next, true.true);
}
Copy the code

ActivityStackSupervisor’s startSpecificActivity is as follows:

    void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        final WindowProcessController wpc =
                mService.getProcessController(r.processName, r.info.applicationInfo.uid);

        boolean knownToBeDead = false;
        // If the application process already exists, execute realStartActivityLocked
        // Start the Activity
        if(wpc ! =null && wpc.hasThread()) {
            try {
                // This function will be analyzed later
                realStartActivityLocked(r, wpc, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }

            // If a dead object exception was thrown -- fall through to
            // restart the application.
            knownToBeDead = true;
        }

        r.notifyUnknownVisibilityLaunchedForKeyguardTransition();

        final boolean isTop = andResume && r.isTopRunningActivity();
        // If the application process does not exist, ATMS(eventually AMS) will start the application process asynchronously
        mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
    }
Copy the code

In case the application process does not exist, AMS sends a Lambda Message to the SystemServer Message queue. When the Message executes, AMS calls the relation:

AMS.startProcessAsync->AMS.startProcess->AMS.startProcessLocked->ProcessList.startProcessLocked… Start ->ProcessList. StartProcess -> process. start -> startViaZygote -> ZygoteProcess -> startViaZygote A timeout message is sent to the SystemServer message queue (default: 10 seconds). If the application process has not started after the timeout, the failed process is killed.

After Zygote forks, it executes ActivityThrea’s main method, and the two most important things that ActivityThread’s main method does, Activate Looper for the main thread and create ActivityThread and call attach, where:

// mAppThread is an ApplicationThread object created when an ActivityThread is created
// Is the bridge between AMS and application processes
/ / initialization RuntimeInit here. MApplicationObject value
RuntimeInit.setApplicationObject(mAppThread.asBinder());
// Obtain the AMS Binder interface IActivityManager
final IActivityManager mgr = ActivityManager.getService();
try {
  // invoke AMS attachApplication
	mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
	throw ex.rethrowFromSystemServer();
}
Copy the code

AttachApplication in AMS is implemented as follows:

    public final void attachApplication(IApplicationThread thread, long startSeq) {
        // If the ApplicationThread passed is empty, the application process will be terminated unexpectedly
        if (thread == null) {
            throw new SecurityException("Invalid application interface");
        }
        synchronized (this) {
            // Get the PID and uid of the binder caller process, which is the application process
            int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            // Change the calling pid and UID of binder to the calling process PID and UID, and return the combination of the original UID and PID
            // The higher 32 bits indicate the uid above, and the lower 32 bits indicate the PID
            final long origId = Binder.clearCallingIdentity();
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);
            // Restore the PID and UIDBinder.restoreCallingIdentity(origId); }}Copy the code

AttachApplicationLocked is an extremely long function that does a lot of checking and setting for App processes.

// If there are any old process records, do some cleaning of the class
// ...
// Then for example debug mode also does some special Settings
// ...
// Create a Binder death callback when AMS server exits unexpectedly.
// Binder drivers can notify application processes and release dead process locks held by Binder files that are not properly closed.
// When the SystemServer process hangs due to an exception, there is a restart mechanism
// ...
// Remove the PROC_START_TIMEOUT_MSG message buried when AMS starts the process
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
// ...
// IPC calls the bindApplication of the ApplicationThread:thread.bindApplication(...) ;Copy the code

After setting up the ApplicationThread, AMS returns to the bindApplication of the application. When bindApplication is performed, AMS passes some common system services to the application, such as WMS, IMS, and so on.

public final void bindApplication(...). {
	if(services ! =null) {
	// Cache the generic system services from AMS to the ServiceManager
	// Static cache
	ServiceManager.initServiceCache(services);
	}
	// H via ActivityThread (inherited from Handler)
	// send a SET_CORE_SETTINGS message to the main thread
  // Set the coreSettings to the ActivityThread object
  // Triggers the restart of all activities in the current process (because the core Settings of the ActivityThread have been changed)
	setCoreSettings(coreSettings);
  // AppBindData is an encapsulation of bindApplication's data
	AppBindData data = new AppBindData();
  // Send the BIND_APPLICATION message to the main thread through the mH
	sendMessage(H.BIND_APPLICATION, data);
}
Copy the code

The following bindApplication logic goes into H, which is the custom Handler for the ActivityThread, such as Service creation, binding, and Activity lifecycle handling:

For BIND_APPLICATION, handleMessage calls handleBindApplication.

In the handleBindApplication, the data.info field is populated with the LoadApk object, which is obtained by getPackageInfo and contains information such as mPackagerName application package name, mDataDir application data directory, MResources, mApplication and other information.

Then complete the creation of the Context:

final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
// createAppContext
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo, String opPackageName) {
	if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
  // Create ContextImpl, initializing ApplicationContext's mMainThread, packageInfo, and other fields
  / / in the constructor of ContextImpl, also created ApplicationContentResolver this object
	ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null.null.null.null.0.null, opPackageName);
	context.setResources(packageInfo.getResources());
  // Is the system status bar Context
	context.mIsSystemOrSystemUiContext = isSystemOrSystemUI(context);
	return context;
}
Copy the code

After the Context has been created, the Application object will continue to be created, again in handleBindApplication:

Application app;
// ...
app = data.info.makeApplication(data.restrictedBackupMode, null);

/ / LoadedApk. MakeApplication:
// ...
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
// Call newApplication to create the Application object
app = mActivityThread.mInstrumentation.newApplication(
	cl, appClass, appContext);
// ...
// Assign Application to LoadedApk's mApplication and add it to ActivityThread's Application list
mApplication = app;
Copy the code

In the newApplication:

public Application newApplication(ClassLoader cl, String className, Context context)
	throws InstantiationException, IllegalAccessException, 
		ClassNotFoundException {
  // Inside is the newInstance of the reflection Application Class
	Application app = getFactory(context.getPackageName())
	.instantiateApplication(cl, className);
  // Bind the Context object to Application
	app.attach(context);
	return app;
}

// attach as follows:
final void attach(Context context) {
  // attachBaseContext is the mBase field that assigns the context to the Application (inherited from ContextWrapper)
	attachBaseContext(context);
	mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
Copy the code

Continue back to the handleBindApplication of the Application process, after creating the Application object:

// Call back to the onCreate method of the Application object
mInstrumentation.callApplicationOnCreate(app);
Copy the code

Now that the Application process is finally created, let’s go back to AMS attachApplicationLocked, after bindApplication has finished creating the Application object:

// If Application has an Activity to start, start the Activity
// After creating a new process and Application, click icon to start an App from the Launcher
// Start MainActivity
if (normalMode) {
	try {
		didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
	} catch (Exception e) {
		Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
		badApp = true; }}/ / ActivityTaskManagerService inner class LocalService implementation attachApplication method:
// Internal call
mRootWindowContainer.attachApplication(wpc);

Copy the code

RootWindowContainer. AttachApplication as follows:

    boolean attachApplication(WindowProcessController app) throws RemoteException {
        boolean didSomething = false;
        for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
            mTmpRemoteException = null;
            mTmpBoolean = false; // Set to true if an activity was started.

            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) {
                    final ActivityStack rootTask = taskDisplayArea.getStackAt(taskNdx);
                    if (rootTask.getVisibility(null /*starting*/) == STACK_VISIBILITY_INVISIBLE) {
                        break;
                    }
                    // Find the ActivityRecord to start, and then
                    / / call startActivityForAttachedApplicationIfNeeded
                    final PooledFunction c = PooledLambda.obtainFunction(
                            RootWindowContainer::startActivityForAttachedApplicationIfNeeded, this,
                            PooledLambda.__(ActivityRecord.class), app,
                            rootTask.topRunningActivity());
                    rootTask.forAllActivities(c);
                    c.recycle();
                    if(mTmpRemoteException ! =null) {
                        throw mTmpRemoteException;
                    }
                }
            }
            didSomething |= mTmpBoolean;
        }
        if(! didSomething) { ensureActivitiesVisible(null.0.false /* preserve_windows */);
        }
        return didSomething;
    }
Copy the code

And startActivityForAttachedApplicationIfNeeded implementation, is to launch ActivityRecord we find, call to mStackSupervisor realStartActivityLocked.

Back to ActivityStackSupervisor’s startSpecificActivity:

    void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        final WindowProcessController wpc =
                mService.getProcessController(r.processName, r.info.applicationInfo.uid);

        boolean knownToBeDead = false;
        // If the application process already exists, execute realStartActivityLocked
        // Start the Activity
        if(wpc ! =null && wpc.hasThread()) {
            try {
                // This function will be analyzed later
                realStartActivityLocked(r, wpc, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }

            // If a dead object exception was thrown -- fall through to
            // restart the application.
            knownToBeDead = true;
        }

        r.notifyUnknownVisibilityLaunchedForKeyguardTransition();

        final boolean isTop = andResume && r.isTopRunningActivity();
        // If the application process does not exist, ATMS(eventually AMS) will start the application process asynchronously
        mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
    }
Copy the code

AMS in the call to the mService. StartProcessAsync after starting a new application process, ultimately through ActivityStackSupervisor realStartActivityLocked, start the application process of the first Activity, RealStartActivityLocked Is still quite long. The logic we are interested in is:

// Create a transaction that the Activity starts. ClientTransaction is a class that implements the Parcelable interface
That is, the transaction object can be passed across processes
final ClientTransaction clientTransaction = ClientTransaction.obtain(
	proc.getThread(), r.appToken);
final DisplayContent dc = r.getDisplay().mDisplayContent;
// Add a LaunchActivityItem to the transaction, representing the transaction's Callback. The logic in the Callback will be executed later
clientTransaction.addCallback(LaunchActivityItem.obtain(newIntent(r.intent),...) );// ...
// Schedule transaction,
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
Copy the code

Let’s take a look at how transactions are acquired:

public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
	// Create an object from the object pool
  ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
	if (instance == null) {
		instance = new ClientTransaction();
	}
  // Assign IApplicationThread to the transaction's mClient field,
  // Indicates which process's ApplicationThread is the receiver of this transaction
	instance.mClient = client;
	instance.mActivityToken = activityToken;
	return instance;
}
Copy the code

ClinetLifeCycleManager schedules transactions as follows:

void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
	final IApplicationThread client = transaction.getClient();
	transaction.schedule();
	// ...
}
//transaction.schedule(); The implementation is as follows: IPC calls scheduleTransaction of the ApplicationThread
mClient.scheduleTransaction(this);
Copy the code

The scheduleTransaction implementation of the ApplicationThread is the scheduleTransaction method that calls the ActivityThread (AT inherits from ClientTransactionHandler, Implementation in parent class) :

void scheduleTransaction(ClientTransaction transaction) {
  // When a client process executes, a hook callback is performed prior to execution
	transaction.preExecute(this);
	sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
Copy the code

The outgoing message is ultimately handed to H for processing:

final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
Copy the code

MTransactionExecutor is not a multithreaded Executor, but a logical encapsulation of the sequential processing of transactions. Execute:

public void execute(ClientTransaction transaction) {
	// ...
  // The point in executeCallbacks is to execute the callback method of the incoming transaction
  // item.execute(mTransactionHandler, token, mPendingActions);
  // 
	executeCallbacks(transaction);
	executeLifecycleState(transaction);
	mPendingActions.clear();
	// ...
}
Copy the code

When AMS calls realStartActivityLocked the incoming transaction callback is the LaunchActivityItem, and its execute is as follows:

public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {
  // Create an ActivityClientRecord object
	ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mPendingResults, mPendingNewIntents, mIsForward,
                mProfilerInfo, client, mAssistToken, mFixedRotationAdjustments);
  // The client is actually the mTransactionHandler in TransactionExecutor
	client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
}
Copy the code

In ActivityThread, the mTransactionExecutor object is created when the ActivityThread object is created and the this reference is passed to the TransactionExecutor constructor. So mTransactionHandler is the ActivityThread object that implements the ClientTransactionHandler interface. In the ActivityThread handleLaunchActivity:

final Activity a = performLaunchActivity(r, customIntent);
Copy the code

PerformLaunchActivity creates the corresponding Activity object. For the analysis of performLaunchActivity, see the previous two Android UI workflow articles.

Android UI Workflow 1 Android UI Workflow 2