Here we go, young man. Let’s introduce ourselves

  • My name is ***, I am proficient in Android system…..

What? Are you proficient in Android? Here, tell me about the process of starting an Activity.

The startup process of an Activity is a representative process in the system, involving the interaction between various processes and the callback control of the life cycle, which is one of the reasons why it occurs so frequently in the interview process.

In API28, the Activity initiation process has been changed to the transaction initiation process. There are some changes to the logic of the previous version, but the process remains similar, with the addition of classes to better divide responsibilities and better process logic.


Before we get started, let’s just cover the basics.

There are three processes involved in starting an Activity.

    1. System process SystemServer (responsible for managing the entire framework, was the first process that Zygote incubated)
    1. App process (App process is when the user clicks on the desktop icon, requests SystemServer through the process Launcher, and then calls Zygote incubation)
    1. Zygote process (all process incubation is done by Zygote, and Zygote is a child of init process, also incubated by init process)
    1. If you click on the desktop icon to launch, you will also involve the Launcher process (the first application process that Zygote incubates).

How do processes communicate with each other?

As we all know, processes are data isolated from each other and cannot access data from each other. Therefore, communication between processes is accomplished by Binder.

Interviewers may ask why you use Binder for correspondence and what advantages Binder has over Socket.

  • I didn’t even think to say one copy, because one copy

The question was asked why Binder was able to do one copy, whereas other technologies were able to do two copies

  • I was young, and I didn’t know the details, but I knew about memory mapping. I’ll just smack it on the head because Binder creates memory mapping on the server side in the kernel using mMAP technology, and when we communicate with the server, You only need to copy the communication data of the Client to the memory area mapped with the Server in the kernel, which is equivalent to copying the communication data to the Server……..

Ok, can you describe how the mapping actually works? .

  • Big brother, I really don’t know…

Here I recommend Binder’s article, which I think is well described in Binder’s extensive blog, no nonsense, for the impatient. Interested students can learn the following, to prevent the interview as I called brother.

Android Binder communications a copy do you really understand?


How many steps does the Activity startup process consist of?

We start by clicking on an icon of Launcher and pull the whole process of launching the Activity. The desktop is actually an Activity of the LauncherApp

    1. When the Launcher icon is clicked to start, the Launcher process will send the launch information as AMS does (the information is the launch information defined in the androidMainifest.xml tag and parses the data from the PackageManagerService).
    1. AMS will successively after ActivityTaskManagerService after receipt of the information – > ActivityStartController – > ActivityStarter inner class Request, and then to save the information into the Request, And tells the process to hibernate the Activity. (A side note: this process checks for the Activity’s registration with AndroidMainifest.xml and reports an error if it hasn’t been registered.)
    1. When the ApplicationThread object of the process Launcher receives the message, it calls handlePauseActivity() to pause and notifies AMS that it has paused.

    Implementation details: ActivityThread. SendMessage () sent via ActivityThread H class Handler, and then trigger mTransactionExecutor. Execute (transaction), Numerical and through the execution of dependence ActivityClientRecord. MLifecycleState ClientTransactionHandler the realization of the abstract class (ActivityThread) for distribution.

    Note: ActivityClientRecord. MLifecycleState (1 ~ 7 represent UNDEFINED, PRE_ON_CREATE, ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP ON_DESTROY, ON_RESTART)

    1. AMS after receiving the news has suspended the Launcher, will check to start the Activity in the Process has started, if has launched the is open, if you do not start through the Process. The start (android. App. ActivityThread) to start a new Process.
    1. Once the process is created, it calls activityThread.main (), initializes MainLooper, and creates the Application object. Reflection to create the Application, and Instrumentation. NewApplication () to create ContextImpl through the Application of the attach binding method and Application, Will eventually invoke Instrumentation. CallApplicationOnCreate perform Application onCreate function some initialization work. AMS will be notified that the process is started when it is complete.

      Notification process: through IActivityManager. AttachApplication (IApplicationThread thread, long startSeq), the Application object into the AMS

    1. AMS after receiving the news that the success of app process starts, corresponding Activity from the ActivityTaskManagerService startup information, and through ApplicationThreadProxy object, Call its scheduleTransaction(ClientTransaction transaction) method, and the Activity to be started is in the ClientTransaction object.
    1. ApplicationThread app process after receiving the message will be called ActiivtyThread. SendMessage (), sent via H Handler, In the interior of the handleMessage method will call mTransactionExecutor. Execute (transaction); Refer to Step 3 for details

Finally, we call the performLaunchActivity method to create and associate the activity and context, Then through mInstrumentation. CallActivityOnCreate () – > Activity. PerformCreate () – > Activity. The onCreate () callback to the life cycle of the Activity.


Which classes are mainly involved in the Activity startup process

  • To prevent further extensive source code analysis from affecting the overall link relationship, after analyzing the source code, I summarized the related classes and call methods, which are described below.

Starting an Activity is usually done with startActivity()

startActivity(new Intent(OneActivity.this,TwoActivity.class));
Copy the code
  • Activity startActivity() startActivityForResult()

  • Instrumentation is the base class used to implement application detection code. When run on opening program instructions, this class will be instantiated for you before any application-sequence code and can monitor all system interactions with applications. The tag in the AndroidManifest.xml file. execStartActivity()

  • ActivityManagerService startActivity() startActivityAsUser()

  • ActivityStarter is used to explain how to start an activity. This class records all the logic that determines how intents and flags are converted to activities and the associated tasks and stacks. execute() startActivity() startActivityUnchecked()

  • ActivityStackSupervisor resumeFocusedStackTopActivityLocked()

  • ResumeTopActivityUncheckedLocked ActivityStack individual Activity of the stack state and management () resumeTopActivityInnerLocked ()

  • RealStartActivityLocked ActivityStackSupervisor Activity stack management startSpecificActivityLocked () ()

  • ClientTransaction A container that holds a series of messages (such as declaring the state of a cycle) that can be sent to a client. ClientTransaction. Obtain (app) thread, state Richard armitage ppToken) / / initializes the addCallback ((LaunchActivityItem. Obtain (new Intent (r.i ntent),…).

  • ClientLifecycleManager // This class is capable of combining multiple Client lifecycle transformation requests/callbacks and executing scheduleTransaction(clientTransaction) as a single transaction

  • ClientTransaction schedule()

  • ApplicationThread scheduleTransaction()

  • ActivityThread manages the scheduling and execution of activities, broadcasts, and other actions requested by the activity manager in the main thread of the application process. scheduleTransaction() sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);

  • ClientTransactionHandler //ActivityThread inherits ClientTransactionHandler, so it calls the parent scheduleTransaction() scheduleTransaction()

  • Execute () executeCallbacks() Transaction.getCallbacks ().get(I).execute()

  • LaunchActivityItem Requests to start the Activity execute()

  • ActivityThread handleLaunchActivity() performLaunchActivity()

  • Instrumentation callActivityOnCreate()

  • Activity onCreate()


The source layer analyzes the entire link

Let’s take a look at the normal way to start an Activity. We usually start a new Activity in the following way.

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

In fact, this is the method of calling in an Activity, which is the startActivity() method of the parent Activity. Due to different parameters, it is divided into two methods, as follows

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

The final call is startActivityForResult()

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

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                // Note that mInstrumentation is the Instrumentation object
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
        } 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

The core logic is called Instrumentation. ExecStartActivity ()

  public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {...try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            // This is the core sentence
            intresult = ActivityManager.getService() .startActivity(whoThread, who.getBasePackageName(), 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

ActivityManager. GetService () who is this access? Logic from IActivityManagerSingleton. The get (), who IActivityManagerSingleton is that? IActivityManagerSingleton is so defined Singleton IActivityManagerSingleton IActivityManager get out, look at the capital I know it’s an interface in the beginning, Its implementation, ActivityManagerService, is actually called. ActivityManagerService. startActivity()

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

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

    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
            boolean validateIncomingUser) {
        enforceNotIsolatedCaller("startActivity");

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

        // TODO: Switch to user app stacks here.
        return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setMayWait(userId)
                .execute();

    }
Copy the code

MActivityStartController. Is ActivityStarter obtainStarter actual call. The execute (), joint call to ActivityStarter. StartActivity ()

 private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
                ActivityRecord[] outActivity) {
        int result = START_CANCELED;
        try {
            mService.mWindowManager.deferSurfaceLayout();
            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity);
        } finally{... } postStartActivityProcessing(r, result, mTargetStack);return result;
    }
Copy the code

ActivityStarter. StartActivityUnchecked () joint call ActivityStackSupervisor. ResumeFocusedStackTopActivityLocked ();

 boolean resumeFocusedStackTopActivityLocked( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {

        if(! readyToResume()) {return false;
        }

        if(targetStack ! =null && isFocusedStack(targetStack)) {
            // Here is the main point
            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }

        final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
        if (r == null| |! r.isState(RESUMED)) { mFocusedStack.resumeTopActivityUncheckedLocked(null.null);
        } else if (r.isState(RESUMED)) {
            // Kick off any lingering app transitions form the MoveTaskToFront operation.
            mFocusedStack.executeAppTransition(targetOptions);
        }
        return false;
    }
Copy the code

TargetStack as ActivityStack object, ActivityStack. ResumeTopActivityUncheckedLocked ()

 boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        if (mStackSupervisor.inResumeTopActivity) {
            // Prevent recursion
            return false;
        }

        boolean result = false;
        try {
            // Protect against recursion.
            mStackSupervisor.inResumeTopActivity = true;
            // This is the main point
            result = resumeTopActivityInnerLocked(prev, options);
            if (next == null || !next.canTurnScreenOn()) {
                checkReadyForSleep();
            }
        } finally {
            mStackSupervisor.inResumeTopActivity = false;
        }

        return result;
    }
Copy the code

ActivityStack. ResumeTopActivityInnerLocked () call the mStackSupervisor. StartSpecificActivityLocked (next, true, true); MStackSupervisor is ActivityStackSupervisor. ActivityStackSupervisor. StartSpecificActivityLocked () call ActivityStackSupervisor. RealStartActivityLocked ()

  final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {...// Schedule transaction.
   mService.getLifecycleManager().scheduleTransaction(clientTransaction);
}
Copy the code

Notice that this clientTransaction object is initialized this way

    / / app. Thread for IApplicationThread
    final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,  r.appToken);

     / / note under this LaunchActivityItem. Obtain
    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, app.repProcState, r.icicle,
                        r.persistentState, results, newIntents, mService.isNextTransitionForward(),
                        profilerInfo));
Copy the code

ClientLifecycleManager.scheduleTransaction(clientTransaction);

    void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
        final IApplicationThread client = transaction.getClient();
        transaction.schedule();
        if (!(client instanceof Binder)) { 
            transaction.recycle();
        }
    }
Copy the code

transaction.schedule(); Need to find

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

ApplicationThread mClient is described above, so we follow up ApplicationThread. ScheduleTransaction ()

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

Shit Call the ActivityThread. ScheduleTransaction (transaction), but no scheduleTransaction ActivityThread (), so we find he inherited class ClientTransactionH ScheduleTransaction ();

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

Copy the code

The above message is sent through the ActivityThread H object and the parsing is also in the ActivityThread

  case EXECUTE_TRANSACTION:
                    final ClientTransaction transaction = (ClientTransaction) msg.obj;
                    mTransactionExecutor.execute(transaction);
                    if (isSystem()) { 
                        transaction.recycle();
                    }
                    // TODO(lifecycler): Recycle locally scheduled transactions.
                    break;
Copy the code

We can see the TransactionExecutor. Execute (transaction);

    // First, all callbacks are executed in the order they appear in the list. If the callback requires a specific pre - or post-execution state,
   // The client converts accordingly. The client will then cycle to the final lifecycle state (if provided).
   // Otherwise, it will remain in the initial or final state required for the callback.
    public void execute(ClientTransaction transaction) {
        final IBinder token = transaction.getActivityToken();
        log("Start resolving transaction for client: " + mTransactionHandler + ", token: " + token);

        executeCallbacks(transaction);

        executeLifecycleState(transaction);
        mPendingActions.clear();
        log("End resolving transaction");
    }

Copy the code

We’ll focus on the executeCallbacks() method here

  /** Transition to the final state if requested by the transaction. */
  public void executeCallbacks(ClientTransaction transaction) {
/ / transaction. GetCallbacks () can get clientTransaction addCallbacks () data.
        final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
        if (callbacks == null) {
            // No callbacks to execute, return early.
            return;
        }
        log("Resolving callbacks");

        final IBinder token = transaction.getActivityToken();
        ActivityClientRecord r = mTransactionHandler.getActivityClient(token);

        // In case when post-execution state of the last callback matches the final state requested
        // for the activity in this transaction, we won't do the last transition here and do it when
        // moving to final state instead (because it may contain additional parameters from server).
        final ActivityLifecycleItem finalStateRequest = transaction.getLifecycleStateRequest();
        final intfinalState = finalStateRequest ! =null ? finalStateRequest.getTargetState()
                : UNDEFINED;
        // Index of the last callback that requests some post-execution state.
        final int lastCallbackRequestingState = lastCallbackRequestingState(transaction);

        final int size = callbacks.size();
        for (int i = 0; i < size; ++i) {
            final ClientTransactionItem item = callbacks.get(i);
            log("Resolving callback: " + item);
            final int postExecutionState = item.getPostExecutionState();
            final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
                    item.getPostExecutionState());
            if(closestPreExecutionState ! = UNDEFINED) { cycleToPath(r, closestPreExecutionState); } item.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions);if (r == null) {
                // Launch activity request will create an activity record.
                r = mTransactionHandler.getActivityClient(token);
            }

            if(postExecutionState ! = UNDEFINED && r ! =null) {
                // Skip the very last transition and perform it by explicit state request instead.
                final booleanshouldExcludeLastTransition = i == lastCallbackRequestingState && finalState == postExecutionState; cycleToPath(r, postExecutionState, shouldExcludeLastTransition); }}}Copy the code

ClientTransaction transaction. GetCallbacks () is the process to create process assignment LaunchActivityItem objects, so basically see LaunchActivityItem. Under the 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);
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }

Copy the code

At this time of the client as ActivityThread, so call ActivityThread. HandleLaunchActivity ()

   @Override
    public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

        if (r.profilerInfo != null) {
            mProfiler.setProfiler(r.profilerInfo);
            mProfiler.startProfiling();
        }

        // Make sure we are running with the most recent config.
        handleConfigurationChanged(null, null);

        if (localLOGV) Slog.v(
            TAG, "Handling launch of " + r);

        // Initialize before creating the activity
        if (!ThreadedRenderer.sRendererDisabled) {
            GraphicsEnvironment.earlyInitEGL();
        }
        WindowManagerGlobal.initialize();

        final Activity a = performLaunchActivity(r, customIntent);
...
}
Copy the code
 /** 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) { ... }}try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation); . activity.mCalled =false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                if(! activity.mCalled) { } r.activity = activity; } r.setState(ON_CREATE); mActivities.put(r.token, r); }catch (SuperNotCalledException e) {
            throw e;
        } catch (Exception e) {
            }
        }

        return activity;
    }
Copy the code

Main follow-up mInstrumentation. CallActivityOnCreate ()

    public void callActivityOnCreate(Activity activity, Bundle icicle, PersistableBundle persistentState) {
        prePerformCreate(activity);
        activity.performCreate(icicle, persistentState);
        postPerformCreate(activity);
    }
Copy the code

Activity.performCreate()

 final void performCreate(Bundle icicle, PersistableBundle persistentState) {
        mCanEnterPictureInPicture = true;
        restoreHasCurrentPermissionRequest(icicle);
        if(persistentState ! =null) {
            onCreate(icicle, persistentState);
        } else {
            onCreate(icicle);
        }
        writeEventLog(LOG_AM_ON_CREATE_CALLED, "performCreate"); mActivityTransitionState.readState(icicle); mVisibleFromClient = ! mWindow.getWindowStyle().getBoolean( com.android.internal.R.styleable.Window_windowNoDisplay,false);
        mFragments.dispatchActivityCreated();
        mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
    }
Copy the code

At this point, the onCreate() method of the Activity is called, and the Activity is officially started, followed by the corresponding declaration cycle callback.