The first chapter of the series of four components of the startup process: Activity startup process based on Android 11 source code

This series of articles is mainly aimed at Android developers with a certain foundation. If you have any questions, please feel free to exchange and learn.

When we call startActivity to start a new Activity, how does it start the Activity?

StartActivity ()

The process for starting an Activity is divided into three parts: Part 1: Activity to ATMS Part 2: ATMS to ActivityThread Part 3: ActivityThread to Activity start

The Activity to the ATMS

The app process starts startActivity

startActivity(new Intent(this, MainActivity.class));
Copy the code

Activity#startActivity(Intent)

    @Override
    public void startActivity(Intent intent) {
    	// The second argument is null
        this.startActivity(intent, null);
    }
Copy the code

Call the overloaded method of startActivity

    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if(mIntent ! =null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)
                && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {
            if (TextUtils.equals(getPackageName(),
                    intent.resolveActivity(getPackageManager()).getPackageName())) {
                // Apply Autofill restore mechanism on the started activity by startActivity()
                final IBinder token =
                        mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
                // Remove restore ability from current activity
                mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
                mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY);
                // Put restore token
                intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);
                intent.putExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY, true); }}if(options ! =null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            // Options == null
            startActivityForResult(intent, -1); }}Copy the code

Activity#startActivityForResult(Intent, int)

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
        startActivityForResult(intent, requestCode, null);
    }
Copy the code

Call the overloaded method of startActivityForResult

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            // Here comes the key
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if(ar ! =null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received. Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.
                mStartedActivity = true;
            }

            cancelInputsAndStartExitTransition(options);
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
            if(options ! =null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode); }}}Copy the code

Key to call mInstrumentation execStartActivity

The APP process goes to the ATMS process. Procedure

Instrumentation#execStartActivity

    @UnsupportedAppUsage
    publicActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { IApplicationThread whoThread = (IApplicationThread) contextThread; Uri referrer = target ! =null ? target.onProvideReferrer() : null;
        if(referrer ! =null) {
            intent.putExtra(Intent.EXTRA_REFERRER, referrer);
        }
        if(mActivityMonitors ! =null) {
            synchronized (mSync) {
                final int N = mActivityMonitors.size();
                for (int i=0; i<N; i++) {
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    ActivityResult result = null;
                    if (am.ignoreMatchingSpecificIntents()) {
                        result = am.onStartActivity(intent);
                    }
                    if(result ! =null) {
                        am.mHits++;
                        return result;
                    } else if (am.match(who, null, intent)) {
                        am.mHits++;
                        if (am.isBlocking()) {
                            return requestCode >= 0 ? am.getResult() : null;
                        }
                        break; }}}}try{ intent.migrateExtraStreamToClipData(who); intent.prepareToLeaveProcess(who); int result = ActivityTaskManager.getService().startActivity(whoThread, who.getBasePackageName(), who.getAttributionTag(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target ! =null ? target.mEmbeddedID : null, requestCode, 0.null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }
Copy the code

Finally through ActivityTaskManager. GetService () calls for ATMS service agents and ATMS. StartActivity method, into the SystemServer from app process at this moment, there was a across processes.

ATMS to ActivityThread

ActivityTaskManagerService#startActivity

    @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
            String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
            Bundle bOptions) {
        return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
                resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }
Copy the code

ActivityTaskManagerService#startActivityAsUser

    @Override
    public int startActivityAsUser(IApplicationThread caller, String callingPackage,
            String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
            String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
            Bundle bOptions, int userId) {
        return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
                resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
                true /*validateIncomingUser*/);
    }
Copy the code

ActivityTaskManagerService#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) {
        assertPackageMatchesCallingUid(callingPackage);
        enforceNotIsolatedCaller("startActivityAsUser");

        userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
                Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

        // TODO: Switch to user app stacks here.
        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

The object that returns at the end sets up so many properties that it calls excute() at the end.

        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

First take a look at getActivityStartController () is what

    ActivityStartController getActivityStartController() {
        return mActivityStartController;
    }
Copy the code
getActivityStartController().obtainStarter(intent, "startActivityAsUser")
Copy the code
    ActivityStarter obtainStarter(Intent intent, String reason) {
        return mFactory.obtain().setIntent(intent).setReason(reason);
    }
Copy the code

Mfactory.obtain () uses the factory pattern to extract the ActivityStarter object from the cache pool of the DefaultFactory class with a maximum of 3 caches

getActivityStartController().obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
Copy the code

SetCaller (Caller) A caller is an object of the type IApplicationThread. The ActivityStarter caches a bridge to connect to app processes. After that, you can call app processes across processes.

ApplicationThread is an ActivityThread internal class that inherits from iApplicationThread. Stub and serves as a server to accept and execute requests from AMS. ApplicationThread is the bridge between ActivityThread and AMS.

And then execute() at the end

        return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                ...
                .execute();
Copy the code

ActivityStarter#execute

    int execute() {
        try{... res = executeRequest(mRequest); .return getExternalResult(mRequest.waitResult == null ? res
                : waitForResult(res, mLastStartActivityRecord));
    	} finally{ onExecutionComplete(); }}Copy the code

ActivityStarter#executeRequest

	/** * Execute the activity start request to start the journey of the activity. Here * first perform a few preliminary checks. The normal activity startup process will * pass through {@link# startActivityUnchecked} to {@link# startactivitynner}. * /
    private int executeRequest(Request request) {
    	...
    	// Create an ActivityRecord object here that describes the Activity information
    	finalActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid, callingPackage, callingFeatureId, intent, resolvedType, aInfo, mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode, request.componentSpecified, voiceSession ! =null, mSupervisor, checkedOptions, sourceRecord); . mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession, request.voiceInteractor, startFlags,true /* doResume */, checkedOptions, inTask, restrictedBgActivity, intentGrants); .return mLastStartActivityResult;
    }
Copy the code

ActivityStarter#startActivityUnchecked

    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                int startFlags, boolean doResume, ActivityOptions options, Task inTask,
                boolean restrictedBgActivity, NeededUriGrants intentGrants) {
        int result = START_CANCELED;
        final ActivityStack startedActivityStack;
        try {
            mService.deferWindowLayout();
            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
            / / key
            result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
            startedActivityStack = handleStartResult(r, result);
            mService.continueWindowLayout();
        }

        postStartActivityProcessing(r, result, startedActivityStack);

        return result;
    }
Copy the code

ActivityStarter#startActivityInner

    int startActivityInner(finalActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, Task inTask, boolean restrictedBgActivity, NeededUriGrants intentGrants) { .... mRootWindowContainer.resumeFocusedStacksTopActivities( mTargetStack, mStartActivity, mOptions); .return START_SUCCESS;
    }
Copy the code

Call the RootWindowContainer# resumeFocusedStacksTopActivities

boolean resumeFocusedStacksTopActivities( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) { ... result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions); .return result;
   }
Copy the code

Call ActivityStack# resumeTopActivityUncheckedLocked

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) { ... result = resumeTopActivityInnerLocked(prev, options); .return result;
    }
Copy the code
    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    ...
    // Key key key!! Next. App.getthread () returns IApplication
    finalClientTransaction transaction = ClientTransaction.obtain(next.app.getThread(), next.appToken); transaction.setLifecycleStateRequest( ResumeActivityItem.obtain(next.app.getReportedProcState(), dc.isNextTransitionForward())); mAtmService.getLifecycleManager().scheduleTransaction(transaction); .return true;
    }
Copy the code

mStackSupervisor.startSpecificActivity(next, true, true); ActivityStackSupervisor#startSpecificActivity

void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) { ... realStartActivityLocked(r, wpc, andResume, checkConfig); . }Copy the code

ActivityStackSupervisor#realStartActivityLocked

  boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
            boolean andResume, boolean checkConfig) throws RemoteException {
	    ...
		// Create activity launch transaction.
		// Key key key!! Proc.getthread () returns IApplication
		// The mClient object assigned to ClientTransaction
        final ClientTransaction clientTransaction = ClientTransaction.obtain(
                        proc.getThread(), r.appToken);

        final DisplayContent dc = r.getDisplay().mDisplayContent;
                clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                        System.identityHashCode(r), r.info,
                        // TODO: Have this take the merged configuration instead of separate global
                        // and override configs.
                        mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
                        r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
                        dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
                        r.assistToken, r.createFixedRotationAdjustmentsIfNeeded()));

        // Set desired final state.
        final ActivityLifecycleItem lifecycleItem;
        if (andResume) {
        	lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
        } else {
              lifecycleItem = PauseActivityItem.obtain();
        }
        clientTransaction.setLifecycleStateRequest(lifecycleItem);

        // Schedule transaction.mService.getLifecycleManager().scheduleTransaction(clientTransaction); . }Copy the code

Get an object of type ClientTransaction from the cache pool, And through the mService. GetLifecycleManager () call scheduleTransaction method began to perform a task is mService ActivityTaskManagerService types of objects ActivityTaskManagerService#getLifecycleManager

    ClientLifecycleManager getLifecycleManager() {
        return mLifecycleManager;
    }
Copy the code

Return an object of type ClientLifecycleManager and see what its scheduleTransaction does

    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(); }}Copy the code

Call ClientTransaction’s Schedule method, simple and crude… Would you like to go back and see how the ClientTransaction schedule is executed

The ATMS process switches back to the APP process

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

Call mClient’s scheduleTransaction… Well, back to what an mClient object is and this is what an mClient is defined in ClientTransaction

    /** Target client. */
    private IApplicationThread mClient;
Copy the code

The IApplicationThread object is a bridge to the app process! Just call ActivityStack# resumeTopActivityUncheckedLocked will IApplicationThread preach into ClientTransaction? So this ClientTransaction object is called in the IApplicationThread. Those of you who know that the ApplicationThread is an inner class of ActivityThread. The IApplicationThread.Stub is also implemented.

mClient.scheduleTransaction(this); ApplicationThread#scheduleTransaction occurs across processes: from the SystemServer process to the app process ApplicationThread#scheduleTransaction

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

An internal call to ActivityThread#scheduleTransaction found that ActivityThread does not have a specific implementation of scheduleTransaction. If the parent class of ActivityThread is an ActivityThread that inherits ClientTransactionHandler, it’s found in ClientTransactionHandler scheduleTransaction

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

Call the sendMessage method with the value of WHAT as activityThread.h.execute_TRANSACTION

ClientTransactionHandler#sendMessage

    abstract void sendMessage(int what, Object obj);
Copy the code

SendMessage is an abstract method. Look for ActivityThread implementation ActivityThread#sendMessage

    void sendMessage(int what, Object obj) {
        sendMessage(what, obj, 0.0.false);
    }

    private void sendMessage(int what, Object obj, int arg1) {
        sendMessage(what, obj, arg1, 0.false);
    }

    private void sendMessage(int what, Object obj, int arg1, int arg2) {
        sendMessage(what, obj, arg1, arg2, false);
    }

    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) {
            Slog.v(TAG,
                    "SCHEDULE " + what + "" + mH.codeToString(what) + ":" + arg1 + "/" + obj);
        }
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
    }

    private void sendMessage(int what, Object obj, int arg1, int arg2, int seq) {
        if (DEBUG_MESSAGES) Slog.v(
                TAG, "SCHEDULE " + mH.codeToString(what) + " arg1=" + arg1 + " arg2=" + arg2 +
                        "seq= " + seq);
        Message msg = Message.obtain();
        msg.what = what;
        SomeArgs args = SomeArgs.obtain();
        args.arg1 = obj;
        args.argi1 = arg1;
        args.argi2 = arg2;
        args.argi3 = seq;
        msg.obj = args;
        mH.sendMessage(msg);
    }
Copy the code

There are a series of overloaded methods, but they all end up calling mh.sendMessage

final H mH = new H();
Copy the code

H is an inner class for ActivityThread that inherits from Handler

    class H extends Handler 
Copy the code

The message that mh. sendMessage just sent activityThread.h.execute_transaction will be processed by H for ActivityThread#H#handleMessage

        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
            	...
                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();
                    }
                    // TODO(lifecycler): Recycle locally scheduled transactions.
                    break; . }}Copy the code

Call the Execute of TransactionExecutor

    publicvoid execute(ClientTransaction transaction) { ... executeCallbacks(transaction); . }Copy the code

TransactionExecutor#executeCallbacks

    /** Cycle through all states requested by callbacks and execute them at proper times. */
    @VisibleForTesting
    public void executeCallbacks(ClientTransaction transaction) {
    	Callback is appended to the LaunchActivityItem in Activitystackcontainer #realStartActivityLocked
    	 final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
        if (callbacks == null || callbacks.isEmpty()) {
            // No callbacks to execute, return early.
            return;
        }
    	finalIBinder token = transaction.getActivityToken(); ActivityClientRecord r = mTransactionHandler.getActivityClient(token); .final int size = callbacks.size();
        for (int i = 0; i < size; ++i) {
            final ClientTransactionItem item = callbacks.get(i); . item.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions); . }}Copy the code

So what we’re doing here is executing LaunchActivityItem execute LaunchActivityItem# Execute

    @Override
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
        ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mPendingResults, mPendingNewIntents, mIsForward,
                mProfilerInfo, client, mAssistToken, mFixedRotationAdjustments);
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }
Copy the code

Internal call client handleLaunchActivity, the type of client is ClientTransactionHandler, The ActivityThread that you’ve just combed through inherits is ClientTransactionHandler.

ActivityThread starts the Activity

ActivityThread#handleLaunchActivity

    public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
    ...
    finalActivity a = performLaunchActivity(r, customIntent); .return a;
    }
Copy the code

ActivityThread#performLaunchActivity

    /** Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
    // The app Context is created here
    ContextImpl appContext = createBaseContextForActivity(r);
    	Activity activity = null;
    	try {
        	// Create an Activity object by reflection
            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); }}...// The makeApplication method internally determines whether the app has created an Application and returns it if it has, or if it has not
    Application app = r.packageInfo.makeApplication(false, mInstrumentation); .// Attach method is very important!! The PhoneWindow object is created internally
    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); .// Start Attach's life cycle onCreate
    if (r.isPersistable()) {
          mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
    } else{ mInstrumentation.callActivityOnCreate(activity, r.state); }... }Copy the code

The Activity startup process is ready to be combed. There are so many classes involved. But combing through, can deepen the impression of Activity, increase memory, later forget slowly ~~