startActivity

We usually use the startActivity method with one argument. Overloading eventually calls the startActivityForResult method. The -1 passed in as the second argument means that we don’t need to get the result of the startActivity

android.app.Activity @Override public void startActivity(Intent intent) { this.startActivity(intent, null); } @Override public void startActivity(Intent intent, @Nullable Bundle options) { ...... 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. startActivityForResult(intent, -1); } } @Override public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) { if (mParent == null) { options = transferSpringboardActivityOptions(options); The key code Instrumentation. ActivityResult ar = mInstrumentation. ExecStartActivity (this, mMainThread getApplicationThread (), mToken, this, intent, requestCode, options); . }... }Copy the code

This mInstrumentation will be familiar to anyone who has seen the previous Application initialization article, and a specific explanation of this class will follow. The official commentary for Instrumentation roughly translates as

Base class used to implement application detection code. When run with detection open, this class will be instantiated for you before any application code, allowing you to monitor all interactions between the system and the application. Instrumentation implementation is described to the system through the < Instrumentation > tag in AndroidManifest.xml.Copy the code

Familiar with the Instrumentation

And then the Instrumentation

android.app.Instrumentation @UnsupportedAppUsage public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { try { intent.migrateExtraStreamToClipData(who); intent.prepareToLeaveProcess(who); / / key code 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

Before looking at the key code, take a look at checkStartActivityResult below, because it contains a familiar error.

android.app.Instrumentation @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public static void checkStartActivityResult(int res, Object intent) { ...... switch (res) { case ActivityManager.START_INTENT_NOT_RESOLVED: case ActivityManager.START_CLASS_NOT_FOUND: if (intent instanceof Intent && ((Intent)intent).getComponent() ! = null) throw new ActivityNotFoundException( "Unable to find explicit activity class " + ((Intent)intent).getComponent().toShortString() + "; have you declared this activity in your AndroidManifest.xml?" ); . }Copy the code

This is where errors are reported when an Activity is not registered in The AndroidManifest, but there are other tests as well. Look at the key code first

android.app.Instrumentation

ActivityTaskManager.getService().startActivity()
Copy the code
android.app.Instrumentation.ActivityTaskManager public static IActivityTaskManager getService() { return IActivityTaskManagerSingleton.get(); } @UnsupportedAppUsage(trackingBug = 129726065) private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton = new Singleton<IActivityTaskManager>() { @Override protected IActivityTaskManager create() { final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE); return IActivityTaskManager.Stub.asInterface(b); }};Copy the code

Source has a lot of this through binde access way, probably actually returns a ActivityTaskManagerService here

com.android.server.wm.ActivityTaskManagerService @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()); }... @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*/); }... 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(); } ActivityStartController getActivityStartController() { return mActivityStartController; }Copy the code

Can see after several calls, the last is to call the getActivityStartController () obtainStarter ()

com.android.server.wm.ActivityStartController

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

The return is an ActivityStarter object, and the chain of calls to execute() must also be in the ActivityStarter. If we found a lead, we should follow it

ActivityStarter:

com.android.server.wm.ActivityStarter /** * Resolve necessary information according the request parameters provided earlier, and execute * the request which begin the journey of starting an activity. * @return The starter result. */ int execute() { ...... res = executeRequest(mRequest); . }Copy the code

Previous versions of agents had many methods to execute. 30 was encapsulated in executeRequest, and the comment above execute made it clear how important this method was.

· Parse the necessary information based on the request parameters provided previously and execute the request to start the activity journey

com.android.server.wm.ActivityStarter private int executeRequest(Request request) { ...... mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession, request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask, restrictedBgActivity, intentGrants); . } private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, Task inTask, boolean restrictedBgActivity, NeededUriGrants intentGrants) { try { mService.deferWindowLayout(); Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner"); 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(); } } @VisibleForTesting int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, Task inTask, boolean restrictedBgActivity, NeededUriGrants intentGrants) { ...... Key code mRootWindowContainer. ResumeFocusedStacksTopActivities (mTargetStack mStartActivity, mOptions); . }Copy the code

This is mRootWindowContainer, which is RootWindowContainer, which is completely different from the previous version. If you’re interested, check out the previous version, which SEEMS to be called mRootActivityer if I remember correctly

com.android.server.wm.RootWindowContainer boolean resumeFocusedStacksTopActivities( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) { if (! mStackSupervisor.readyToResume()) { return false; }... if (targetStack ! = null && (targetStack.isTopStackInDisplayArea() || getTopDisplayFocusedStack() == targetStack)) { result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); }... }Copy the code

· ActivityStack · ActivityStackSupervisor mStackSupervisor is an instance of an ActivityStackSupervisor object, If the person who opened the code with me might not find the mStackSupervisor variable in ActivityStack, it’s time to look in its parent class. Sure enough, in ActivityStack’s parent Task, you can see that the targetStack is of type ActivityStack

com.android.server.wm.Task class Task extends WindowContainer<WindowContainer> { ...... final ActivityStackSupervisor mStackSupervisor; . }Copy the code

Let’s move on to method execution

com.android.server.wm.ActivityStack @GuardedBy("mService") boolean resumeTopActivityUncheckedLocked(ActivityRecord prev,  ActivityOptions options) { ...... result = resumeTopActivityInnerLocked(prev, options); . } @GuardedBy("mService") private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { ...... If (mResumedActivity! = null) { pausing |= startPausingLocked(userLeaving, false /* uiSleeping */, next); }}... } final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,ActivityRecord resuming) { ...... mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, prev.configChangeFlags, pauseImmediately)); . }Copy the code

And the above mStackSupervisor, mAtmService is defined in the superclass Task a ActivityTaskManagerService instance.

com.android.server.wm.ActivityTaskManagerService

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

MAtmService. GetLifecycleManager () returns a ClientLifecycleManager object, nature also here that scheduleTransaction method

com.android.server.wm.ClientLifecycleManager 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
android.app.servertransaction.ClientTransaction ...... /** Target client. */ private IApplicationThread mClient; . public void schedule() throws RemoteException { mClient.scheduleTransaction(this); }Copy the code

If you are familiar with IApplicationThread, go to ApplicationThread. And I can make a bold guess, finally sent a message to H

android.app.ActivityThread private class ApplicationThread extends IApplicationThread.Stub { @Override public void scheduleTransaction(ClientTransaction transaction) throws RemoteException { ActivityThread.this.scheduleTransaction(transaction); }}Copy the code

Yi.. I didn’t send a message. I guess I was wrong. The ActivityThread class does not have a scheduleTransaction method. In this case, the ActivityThread class has no scheduleTransaction method

android.app.ClientTransactionHandler

public abstract class ClientTransactionHandler {

    // Schedule phase related logic and handlers.

    /** Prepare and schedule transaction for execution. */
    void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);
        sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
    }
Copy the code

Emmmm, I was wrong but not completely wrong. Finally, an H. execute_Transaction message occurs

android.app.ActivityThread // An executor that performs multi-step transactions. private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this); . class H extends Handler { ...... 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(); }... }Copy the code

· TransactionExecutor

android.app.servertransaction.TransactionExecutor ...... private ClientTransactionHandler mTransactionHandler; . public void execute(ClientTransaction transaction) { ...... executeCallbacks(transaction); . } @VisibleForTesting public void executeCallbacks(ClientTransaction transaction) { ...... if (postExecutionState ! = UNDEFINED && r ! = null) { // Skip the very last transition and perform it by explicit state request instead. final boolean shouldExcludeLastTransition = i == lastCallbackRequestingState && finalState == postExecutionState; The key code cycleToPath (r, postExecutionState, shouldExcludeLastTransition, transaction); } } private void cycleToPath(ActivityClientRecord r, int finish, boolean excludeLastState, ClientTransaction transaction) { ...... performLifecycleSequence(r, path, transaction); } private void performLifecycleSequence(ActivityClientRecord r, IntArray path, ClientTransaction transaction) { final int size = path.size(); for (int i = 0, state; i < size; i++) { state = path.get(i); if (DEBUG_RESOLVER) { Slog.d(TAG, tId(transaction) + "Transitioning activity: " + getShortActivityName(r.token, mTransactionHandler) + " to state: " + getStateName(state)); } switch (state) { case ON_CREATE: Key code mTransactionHandler. HandleLaunchActivity (r, mPendingActions, null customIntent / * * /); break; case ON_START: mTransactionHandler.handleStartActivity(r.token, mPendingActions); break; case ON_RESUME: mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */, r.isForward, "LIFECYCLER_RESUME_ACTIVITY"); break; case ON_PAUSE: mTransactionHandler.handlePauseActivity(r.token, false /* finished */, false /* userLeaving */, 0 /* configChanges */, mPendingActions, "LIFECYCLER_PAUSE_ACTIVITY"); break; case ON_STOP: mTransactionHandler.handleStopActivity(r.token, 0 /* configChanges */, mPendingActions, false /* finalStateRequest */, "LIFECYCLER_STOP_ACTIVITY"); break; case ON_DESTROY: mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */, 0 /* configChanges */, false /* getNonConfigInstance */, "performLifecycleSequence. cycling to:" + path.get(size - 1)); break; case ON_RESTART: mTransactionHandler.performRestartActivity(r.token, false /* start */); break; default:Copy the code

After a series of method calls the execute – > executeCallbacks – > cycleToPath – > performLifecycleSequence, we finally see the familiar things, a pile of the Activity lifecycle. MTransactionHandler is an instance of type ClientTransactionHandler, handleLaunchActivity is its abstract method, ActivityThread is its subclass, The handleLaunchActivity method is implemented

android.app.ClientTransactionHandler public abstract class ClientTransactionHandler { ...... /** Perform activity launch. */ public abstract Activity handleLaunchActivity(ActivityThread.ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent); . }Copy the code
android.app.ActivityThread @Override public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) { ...... final Activity a = performLaunchActivity(r, customIntent); . } private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ...... Activity activity = null; try { java.lang.ClassLoader cl = appContext.getClassLoader(); Key code 1 activity = mInstrumentation. NewActivity (cl, component getClassName (), r.i ntent); 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); }}... 2 if the key code (r.i sPersistable ()) {mInstrumentation. CallActivityOnCreate (activity, r.s Tate, r.p ersistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); }... }Copy the code

If you’ve seen the Activity launch process before, or if you’ve seen The Art of Android Development, you’ll remember the performLaunchActivity method. We’re about to get to the bottom of it.

Instrumentation is mentioned in the Application Initialization Process article that Instrumentation is responsible for the creation and lifecycle control of applications and activities. Take a look at how he creates the Activity.

android.app.Instrumentation public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException { String pkg = intent ! = null && intent.getComponent() ! = null ? intent.getComponent().getPackageName() : null; return getFactory(pkg).instantiateActivity(cl, className, intent); } private AppComponentFactory getFactory(String pkg) { ...... return apk.getAppFactory(); }Copy the code

InstantiateActivity can be traced to the AppComponentFactory and finally done in the AppComponentFactory. The newActivity parameter is a ClassLoader and a className. I like to look at code with my own guess, how I would execute it, so that by the end of the guess, whether right or wrong. Will be more impressive. If you’re wrong, you’re enlightened. If you’re right, you’re complacent.)

android.appinstantiateActivity

public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className,
        @Nullable Intent intent)
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    return (Activity) cl.loadClass(className).newInstance();
}
Copy the code

It was a reflex. PerformLaunchActivity is created in code 1 by Instrumentation, and in code 2 by the name, which probably indicates that the OnCreate method of the Activity is executed

android.app.Instrumentation

/**
 * Perform calling of an activity's {@link Activity#onCreate}
 * method.  The default implementation simply calls through to that method.
 *
 * @param activity The activity being created.
 * @param icicle The previously frozen state (or null) to pass through to onCreate().
 */
public void callActivityOnCreate(Activity activity, Bundle icicle) {
    prePerformCreate(activity);
    activity.performCreate(icicle);
    postPerformCreate(activity);
}
Copy the code

As you can see, the second line, which is more critical, is handed over directly to the Activity. So basically, when you’re inside the Activity, you’re at the end.

android.app.Activity final void performCreate(Bundle icicle) { performCreate(icicle, null); } @UnsupportedAppUsage final void performCreate(Bundle icicle, PersistableBundle persistentState) { dispatchActivityPreCreated(icicle); mCanEnterPictureInPicture = true; // initialize mIsInMultiWindowMode and mIsInPictureInPictureMode before onCreate final int windowingMode = getResources().getConfiguration().windowConfiguration .getWindowingMode(); mIsInMultiWindowMode = inMultiWindowMode(windowingMode); mIsInPictureInPictureMode = windowingMode == WINDOWING_MODE_PINNED; restoreHasCurrentPermissionRequest(icicle); PersistentState! = null) { onCreate(icicle, persistentState); } else { onCreate(icicle); } EventLogTags.writeWmOnCreateCalled(mIdent, getComponentName().getClassName(), "performCreate"); mActivityTransitionState.readState(icicle); mVisibleFromClient = ! mWindow.getWindowStyle().getBoolean( com.android.internal.R.styleable.Window_windowNoDisplay, false); mFragments.dispatchActivityCreated(); mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions()); dispatchActivityPostCreated(icicle); }Copy the code

OK, you see the Activity executing onCreate. The end.