The process of starting an Activity is a must-ask question for an interview. It is very complicated, and it is very important to get all the core things right during the interview. Today, I will follow this process in detail and summarize it. Aim for five hours.

The key class

ActivityThread Specifies the main thread code for the application process. Used to communicate with the server Instrument is responsible for calling the Activity and the Application of life cycle ActivityTaskManagerService is responsible for managing the AMS ActivityStarter is responsible for starting mode, Start Flag related ActivityStack ActivityStackSuprevisor ClientTransactionItem: an abstract class that executes a specific activity lifecycle. Subclasses: TransactionExecutor executes ClientTransaction ClientLifecycleManager Management calls for the life cycleCopy the code

Click the desktop icon to trigger the Laucher process

The Launcher app registers a click callback for each icon when it creates a desktop icon

	// packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

    public View createShortcut(ViewGroup parent, WorkspaceItemInfo info) {
        BubbleTextView favorite = (BubbleTextView) LayoutInflater.from(parent.getContext())
                .inflate(R.layout.app_icon, parent, false);
        favorite.applyFromWorkspaceItem(info);
        favorite.setOnClickListener(ItemClickHandler.INSTANCE);	// Callback method
        favorite.setOnFocusChangeListener(mFocusHandler);
        return favorite;
    }
Copy the code

When clicking on the icon to trigger ItemClickHandler onClick method, and then executes startAppShortcutOrInfoActivity method

public class ItemClickHandler {
    private static void onClick(View v, String sourceContainer) {
        // Make sure that rogue clicks don't get through while allapps is launching, or after the
        // view has detached (it's possible for this to happen if the view is removed mid touch).
        if (v.getWindowToken() == null) return;

        Launcher launcher = Launcher.getLauncher(v.getContext());
        if(! launcher.getWorkspace().isFinishedSwitchingState())return;

        Object tag = v.getTag();
        if (tag instanceof WorkspaceItemInfo) {
            // Click desktop Components
            onClickAppShortcut(v, (WorkspaceItemInfo) tag, launcher, sourceContainer);
        } else if (tag instanceof FolderInfo) {
            // Click the folder icon
            if (v instanceofFolderIcon) { onClickFolderIcon(v); }}else if (tag instanceof AppInfo) {
            // Click the app icon
            startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher,
                    sourceContainer == null ? CONTAINER_ALL_APPS: sourceContainer);
        } else if (tag instanceof LauncherAppWidgetInfo) {
            // Click the Start widget
            if (v instanceofPendingAppWidgetHostView) { onClickPendingWidget((PendingAppWidgetHostView) v, launcher); }}}private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher,
            @Nullable String sourceContainer) {
        Intent intent;
        if (item instanceof PromiseAppInfo) {
            PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
            intent = promiseAppInfo.getMarketIntent(launcher);
        } else {
            intent = item.getIntent();
        }
        if (intent == null) {
            throw new IllegalArgumentException("Input must have a valid intent");
        }
        if (item instanceof WorkspaceItemInfo) {
            WorkspaceItemInfo si = (WorkspaceItemInfo) item;
            if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI)
                    && Intent.ACTION_VIEW.equals(intent.getAction())) {
                // make a copy of the intent that has the package set to null
                // we do this because the platform sometimes disables instant
                // apps temporarily (triggered by the user) and fallbacks to the
                // web ui. This only works though if the package isn't set
                intent = new Intent(intent);
                intent.setPackage(null); }}if(v ! =null && launcher.getAppTransitionManager().supportsAdaptiveIconAnimation()) {
            // Preload the icon to reduce latency b/w swapping the floating view with the original.
            FloatingIconView.fetchIcon(launcher, v, item, true /* isOpening */);
        }
        
        // Call the startActivitySafely method of the Launcherlauncher.startActivitySafely(v, intent, item, sourceContainer); }}Copy the code
public class Launcher extends BaseDraggingActivity implements LauncherExterns.Callbacks.LauncherProviderChangeListener.UserEventDelegate.InvariantDeviceProfile.OnIDPChangeListener {
            
    public boolean startActivitySafely(View v, Intent intent, ItemInfo item,
            @Nullable String sourceContainer) {
        if(! hasBeenResumed()) {// Workaround an issue where the WM launch animation is clobbered when finishing the
            // recents animation into launcher. Defer launching the activity until Launcher is
            // next resumed.
            addOnResumeCallback(() -> startActivitySafely(v, intent, item, sourceContainer));
            UiFactory.clearSwipeSharedState(true /* finishAnimation */);
            return true;
        }

        boolean success = super.startActivitySafely(v, intent, item, sourceContainer);
        if (success && v instanceof BubbleTextView) {
            // This is set to the view that launched the activity that navigated the user away
            // from launcher. Since there is no callback for when the activity has finished
            // launching, enable the press state and keep this reference to reset the press
            // state when we return to launcher.
            BubbleTextView btv = (BubbleTextView) v;
            btv.setStayPressed(true);
            addOnResumeCallback(btv);
        }
        returnsuccess; }}Copy the code

It then calls the startActivitySafely method of its BaseDraggingActivity parent class, where it calls the Activity’s startActity method and adds the FLAG_ACTIVITY_NEW_TASK flag. Pull the application in a new task stack.

public abstract class BaseDraggingActivity extends BaseActivity
        implements WallpaperColorInfo.OnChangeListener {
    public boolean startActivitySafely(View v, Intent intent, @Nullable ItemInfo item,
            @Nullable String sourceContainer) {
        if(mIsSafeModeEnabled && ! PackageManagerHelper.isSystemApp(this, intent)) {
            Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
            return false; } Bundle optsBundle = (v ! =null)? getActivityLaunchOptionsAsBundle(v) :null;
        UserHandle user = item == null ? null : item.user;

        // Add the FLAG_ACTIVITY_NEW_TASK flag
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if(v ! =null) {
            intent.setSourceBounds(getViewBounds(v));
        }
        try {
            boolean isShortcut = (item instanceofWorkspaceItemInfo) && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) && ! ((WorkspaceItemInfo) item).isPromise();if (isShortcut) {
                // Shortcuts need some special checks due to legacy reasons.
                startShortcutIntentSafely(intent, optsBundle, item, sourceContainer);
            } else if (user == null || user.equals(Process.myUserHandle())) {
                // Could be launching some bookkeeping activity
                startActivity(intent, optsBundle);
                AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(),
                        Process.myUserHandle(), sourceContainer);
            } else {
                LauncherAppsCompat.getInstance(this).startActivityForProfile(
                        intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
                AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(), user,
                        sourceContainer);
            }
            getUserEventDispatcher().logAppLaunch(v, intent);
            getStatsLogManager().logAppLaunch(v, intent);
            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 Activity process

. It is worth noting that the mMainThread getApplicationThread () to obtain the Launcher application process of ApplicationThread object, the object is a IPC communication server object, behind for AMS and scheduling application through the object.

public class Activity {
	public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            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

Instrumentation is a practical class for starting activities in the Android system to monitor the interaction between applications and the system.

public class Instrumentation {
	public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        // IPC communication objectIApplicationThread whoThread = (IApplicationThread) contextThread; Uri referrer = target ! =null ? target.onProvideReferrer() : null;
        if(referrer ! =null) { intent.putExtra(Intent.EXTRA_REFERRER, referrer); }... .try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            // Call the startActivity method of ActivityTaskManager
            intresult = ActivityTaskManager.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

Through the IPC communication here, in the call to the system server ActivityTaskManagerService.

ActivityTaskManagerService process

An ActivityStarter object is constructed using the Builder mode. The Request object inside the ActivityStarter class maintains all the information needed to start an Activity.

public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
	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());
    }
    
    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("startActivityAsUser");

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

        // Get the ActivityStarter object
        return getActivityStartController().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
class ActivityStarter {
	int execute(a) {
        try {
            if (mRequest.mayWait) {
                / / go here
                returnstartActivityMayWait(mRequest.caller, mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid, mRequest.intent, mRequest.resolvedType, mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo, mRequest.resultWho, mRequest.requestCode, mRequest.startFlags, mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig, mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId, mRequest.inTask, mRequest.reason, mRequest.allowPendingRemoteAnimationRegistryLookup, mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart); }......}finally{ onExecutionComplete(); }}// After a series of calls to startActivity, finally get to startActivityUnchecked
    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity, boolean restrictedBgActivity) {
        
        // Initialize the various configurations that start the Activity
        setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
                voiceInteractor, restrictedBgActivity);

        final int preferredWindowingMode = mLaunchParams.mWindowingMode;
	
        // Calculate the enabled Flag and assign it to mLaunchFlags
        computeLaunchingTaskFlags();

        computeSourceStack();

        mIntent.setFlags(mLaunchFlags);
		
        // Determine if there are activities that can be reusedActivityRecord reusedActivity = getReusableIntentActivity(); mSupervisor.getLaunchParamsController().calculate( reusedActivity ! =null ? reusedActivity.getTaskRecord() : mInTask,
                r.info.windowLayout, r, sourceRecord, options, PHASE_BOUNDS, mLaunchParams);
        mPreferredDisplayId =
                mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
                        : DEFAULT_DISPLAY;

        // Do not start home activity if it cannot be launched on preferred display. We are not
        // doing this in ActivityStackSupervisor#canPlaceEntityOnDisplay because it might
        // fallback to launch on other displays.
        if(r.isActivityTypeHome() && ! mRootActivityContainer.canStartHomeOnDisplay(r.info, mPreferredDisplayId,true /* allowInstrumenting */)) {
            Slog.w(TAG, "Cannot launch home on display " + mPreferredDisplayId);
            return START_CANCELED;
        }

        if(reusedActivity ! =null) {
        	/ / reusedActivity is null· · · · · · · · · · · ·} mTargetStack. StartActivityLocked (mStartActivity topFocused, newTask, mKeepCurTransition, mOptions);if (mDoResume) {
            final ActivityRecord topTaskActivity =
                    mStartActivity.getTaskRecord().topRunningActivityLocked();
            if(! mTargetStack.isFocusable() || (topTaskActivity ! =null&& topTaskActivity.mTaskOverlay && mStartActivity ! = topTaskActivity)) {// If the activity is not focusable, we can't resume it, but still would like to
                // make sure it becomes visible as it starts (this will also trigger entry
                // animation). An example of this are PIP activities.
                // Also, we don't want to resume activities in a task that currently has an overlay
                // as the starting activity just needs to be in the visible paused state until the
                // over is removed.
                mTargetStack.ensureActivitiesVisibleLocked(mStartActivity, 0, !PRESERVE_WINDOWS);
                // Go ahead and tell window manager to execute app transition for this activity
                // since the app transition will not be triggered through the resume channel.
                mTargetStack.getDisplay().mDisplayContent.executeAppTransition();
            } else {
                // If the target stack was not previously focusable (previous top running activity
                // on that stack was not visible) then any prior calls to move the stack to the
                // will not update the focused stack. If starting the new activity now allows the
                // task stack to be focusable, then ensure that we now update the focused stack
                // accordingly.
                if(mTargetStack.isFocusable() && ! mRootActivityContainer.isTopDisplayFocusedStack(mTargetStack)) { mTargetStack.moveToFront("startActivityUnchecked");
                }
                // The most important stepmRootActivityContainer.resumeFocusedStacksTopActivities( mTargetStack, mStartActivity, mOptions); }}else if(mStartActivity ! =null) {
            mSupervisor.mRecentTasks.add(mStartActivity.getTaskRecord());
        }
        mRootActivityContainer.updateUserStack(mStartActivity.mUserId, mTargetStack);

        mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTaskRecord(),
                preferredWindowingMode, mPreferredDisplayId, mTargetStack);

        returnSTART_SUCCESS; }}Copy the code

The key object is mRootActivityContainer, which is an object that temporarily shares some of the ActivityStackSupervisor class.

class RootActivityContainer extends ConfigurationContainer
        implements DisplayManager.DisplayListener {
        
   boolean resumeFocusedStacksTopActivities( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {

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

        boolean result = false;
        if(targetStack ! =null&& (targetStack.isTopStackOnDisplay() || getTopDisplayFocusedStack() == targetStack)) { result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); } · · · · · ·returnresult; }}Copy the code

To ActivityStack resumeTopActivityUncheckedLocked method, one of the important steps: judge whether there is currently in a state of Resume Activity, first to convert them into onPause state. The current scenario is to switch the Launcher state to onPause

class ActivityStack extends ConfigurationContainer {
	boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        if (mInResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }

        boolean result = false;
        try {
            // Protect against recursion.
            mInResumeTopActivity = true;
            result = resumeTopActivityInnerLocked(prev, options);

            // When resuming the top activity, it may be necessary to pause the top activity (for
            // example, returning to the lock screen. We suppress the normal pause logic in
            // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the
            // end. We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here
            // to ensure any necessary pause logic occurs. In the case where the Activity will be
            // shown regardless of the lock screen, the call to
            // {@link ActivityStackSupervisor#checkReadyForSleepLocked} is skipped.
            final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
            if (next == null || !next.canTurnScreenOn()) {
                checkReadyForSleep();
            }
        } finally {
            mInResumeTopActivity = false;
        }

        return result;
    }
    
    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
        if(! mService.isBooting() && ! mService.isBooted()) {// Not ready yet!
            return false;
        }

        boolean pausing = getDisplay().pauseBackStacks(userLeaving, next, false);
        If any of your Resumed activities are in the Resumed state, transition them to the Pause state
        if(mResumedActivity ! =null) {
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
            pausing |= startPausingLocked(userLeaving, false, next, false);
        }
        
        // Start the specified Activity again
        mStackSupervisor.startSpecificActivityLocked(next, true.true);

        return true; }}Copy the code

Analyze the startPausingLocked process first, and then pull back startSpecificActivityLocked method specified application.

class ActivityStack extends ConfigurationContainer {
	final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
            ActivityRecord resuming, boolean pauseImmediately) ActivityRecord prev = mResumedActivity;if (prev == null) {
            if (resuming == null) {
                Slog.wtf(TAG, "Trying to pause when nothing is resumed");
                mRootActivityContainer.resumeFocusedStacksTopActivities();
            }
            return false;
        }

        if (prev == resuming) {
            Slog.wtf(TAG, "Trying to pause activity that is in process of being resumed");
            return false;
        }

        if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSING: " + prev);
        else if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Start pausing: "+ prev); mPausingActivity = prev; mLastPausedActivity = prev; mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) ! =0|| (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) ! =0 ? prev : null;
        prev.setState(PAUSING, "startPausingLocked");
        prev.getTaskRecord().touchActiveTime();
        clearLaunchTime(prev);

        mService.updateCpuStats();

        if (prev.attachedToProcess()) {
            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
            try {
                EventLogTags.writeAmPauseActivity(prev.mUserId, System.identityHashCode(prev),
                        prev.shortComponentName, "userLeaving=" + userLeaving);
				
                // Get the ClientLifecycleManager object to schedule the application lifecycle
                mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
                        prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
                                prev.configChangeFlags, pauseImmediately));
            } catch (Exception e) {
                // Ignore exception, if process died other code will cleanup.
                Slog.w(TAG, "Exception thrown during pause", e);
                mPausingActivity = null;
                mLastPausedActivity = null;
                mLastNoHistoryActivity = null; }}else {
            mPausingActivity = null;
            mLastPausedActivity = null;
            mLastNoHistoryActivity = null; }}}Copy the code

The ClientLifecycleManager object is a class that assists in managing the application lifecycle and holds an ApplicationThread object internally for IPC communication.

class ClientLifecycleManager {
	void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
        final IApplicationThread client = transaction.getClient();
        transaction.schedule();
        if(! (clientinstanceof 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
public class ClientTransaction implements Parcelable.ObjectPoolItem {
	public void schedule(a) throws RemoteException {
        mClient.scheduleTransaction(this); }}Copy the code

Through IPC communication, the scheduleTransaction method of the ActivityThread is called, and eventually the handleMessage method of the Inner class H of the ActivityThread is called

public final class ActivityThread extends ClientTransactionHandler {
	public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
            ActivityThread.this.scheduleTransaction(transaction);
    }
    
    / / what for EXECUTE_TRANSACTION
    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); }}Copy the code
class H extends Handler {
	public void handleMessage(Message msg) {
    	case EXECUTE_TRANSACTION:
            final ClientTransaction transaction = (ClientTransaction) msg.obj;
        	// Important method
            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

At this time and came to the TransactionExecutor the execute method, will perform PauseActivityItem executeLifecycleState. The execute method

public void execute(ClientTransaction transaction) {
        if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Start resolving transaction");

        final IBinder token = transaction.getActivityToken();
        if(token ! =null) {
            final Map<IBinder, ClientTransactionItem> activitiesToBeDestroyed =
                    mTransactionHandler.getActivitiesToBeDestroyed();
            final ClientTransactionItem destroyItem = activitiesToBeDestroyed.get(token);
            if(destroyItem ! =null) {
                if (transaction.getLifecycleStateRequest() == destroyItem) {
                    // It is going to execute the transaction that will destroy activity with the
                    // token, so the corresponding to-be-destroyed record can be removed.
                    activitiesToBeDestroyed.remove(token);
                }
                if (mTransactionHandler.getActivityClient(token) == null) {
                    // The activity has not been created but has been requested to destroy, so all
                    // transactions for the token are just like being cancelled.
                    Slog.w(TAG, tId(transaction) + "Skip pre-destroyed transaction:\n"
                            + transactionToString(transaction, mTransactionHandler));
                    return; }}}if (DEBUG_RESOLVER) Slog.d(TAG, transactionToString(transaction, mTransactionHandler));
		
		// Important method 1
        executeCallbacks(transaction);
		
    	// Important method 2
        executeLifecycleState(transaction);
        mPendingActions.clear();
        if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "End resolving transaction");
    }

private void executeLifecycleState(ClientTransaction transaction) {
    	// This lifecycleItem is brought by ATMS and is actually a PauseActivityItem object
        final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
        if (lifecycleItem == null) {
            // No lifecycle request, return early.
            return;
        }

        final IBinder token = transaction.getActivityToken();
        final ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
        if (DEBUG_RESOLVER) {
            Slog.d(TAG, tId(transaction) + "Resolving lifecycle state: "
                    + lifecycleItem + " for activity: "
                    + getShortActivityName(token, mTransactionHandler));
        }

        if (r == null) {
            // Ignore requests for non-existent client records for now.
            return;
        }

        // Cycle to the state right before the final requested state.
        cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */, transaction);

        // Execute the final transition with proper parameters.
        lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
        lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
    }
Copy the code
public class PauseActivityItem extends ActivityLifecycleItem {
	@Override
    public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
        // This client is the ActivityThread object
        client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions,
                "PAUSE_ACTIVITY_ITEM"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); }}Copy the code
public final class ActivityThread extends ClientTransactionHandler {
	@Override
    public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
            int configChanges, PendingTransactionActions pendingActions, String reason) {
        ActivityClientRecord r = mActivities.get(token);
        if(r ! =null) {
            if (userLeaving) {
                performUserLeavingActivity(r);
            }

            r.activity.mConfigChangeFlags |= configChanges;
            performPauseActivity(r, finished, reason, pendingActions);

            // Make sure any pending writes are now committed.
            if (r.isPreHoneycomb()) {
                QueuedWork.waitToFinish();
            }
            mSomeActivitiesChanged = true; }}private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {
        if (r.paused) {
            // You are already paused silly...
            return;
        }

        // Always reporting top resumed position loss when pausing an activity. If necessary, it
        // will be restored in performResumeActivity().
        reportTopResumedActivityChanged(r, false /* onTop */."pausing");

        try {
            r.activity.mCalled = false;
            // Continue to Instrument's callActivityOnPause
            mInstrumentation.callActivityOnPause(r.activity);
            if(! r.activity.mCalled) {throw new SuperNotCalledException("Activity " + safeToComponentShortString(r.intent)
                        + " did not call through to super.onPause()"); }}catch (SuperNotCalledException e) {
            throw e;
        } catch (Exception e) {
            if(! mInstrumentation.onException(r.activity, e)) {throw new RuntimeException("Unable to pause activity "
                        + safeToComponentShortString(r.intent) + ":"+ e.toString(), e); } } r.setState(ON_PAUSE); }}Copy the code

Continue to Instrument’s callActivityOnPause method

public class Instrumentation {
	public void callActivityOnPause(Activity activity) { activity.performPause(); }}Copy the code

The Activity is the user’s Activity, in this case launcher.java

public class Activity {
	final void performPause(a) {
        dispatchActivityPrePaused();
        mDoReportFullyDrawn = false;
        mFragments.dispatchPause();
        mCalled = false;
        // Template method, user - defined onPause method
        onPause();
        writeEventLog(LOG_AM_ON_PAUSE_CALLED, "performPause");
        mResumed = false;
        if(! mCalled && getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.GINGERBREAD) {throw new SuperNotCalledException(
                    "Activity " + mComponent.toShortString() +
                    " did not call through to super.onPause()"); } dispatchActivityPostPaused(); }}Copy the code

Well, at this point, the Launcher Activity completed onPause callback, get back to below the ActivityStackManagerService startSpecificActivityLocked method, pull up the specified application.

Starting an Application Process

There are two ways to start an Activity: 1. The Application in which the Activity is started does not need to create a process. 2. Create a process for the Activity.

public class ActivityStackSupervisor implements RecentTasks.Callbacks {
	void startSpecificActivityLocked(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(wpc ! =null && wpc.hasThread()) {
            try {
                // If the Application to which the Activity belongs is already started
                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;
        }

        // Suppress transition until the new activity becomes ready, otherwise the keyguard can
        // appear for a short amount of time before the new process with the new activity had the
        // ability to set its showWhenLocked flags.
        if (getKeyguardController().isKeyguardLocked()) {
            r.notifyUnknownVisibilityLaunched();
        }

        try {
            if (Trace.isTagEnabled(TRACE_TAG_ACTIVITY_MANAGER)) {
                Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "dispatchingStartProcess:"
                        + r.processName);
            }
            
            // startProcess is triggered to create a new process with a Handler message
            final Message msg = PooledLambda.obtainMessage(
                    ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName,
                    r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent());
            mService.mH.sendMessage(msg);
        } finally{ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); }}}Copy the code

mService.mH.sendMessage(msg); This message triggers ActivityManagerService to the startProcess method of the inner class LocalService, which is called through several layers, eventually calling the process. start method.

public final class LocalService extends ActivityManagerInternal {
	public void startProcess(String processName, ApplicationInfo info,
                boolean knownToBeDead, String hostingType, ComponentName hostingName) {
        try {
            if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "startProcess:"
                                 + processName);
            }
            synchronized (ActivityManagerService.this) {
                startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */.new HostingRecord(hostingType, hostingName),
                                   false /* allowWhileBooting */.false /* isolated */.true /* keepIfLarge */); }}finally{ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); }}final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            HostingRecord hostingRecord, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) {
        return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
                hostingRecord, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
                null /* ABI override */.null /* entryPoint */.null /* entryPointArgs */.null /* crashHandler */);
    }
    
    private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
            ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
            String seInfo, String requiredAbi, String instructionSet, String invokeWith,
            long startTime) {
        try {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                    app.processName);
            checkSlow(startTime, "startProcess: asking zygote to start proc");
            final Process.ProcessStartResult startResult;
            if (hostingRecord.usesWebviewZygote()) {
                startResult = startWebView(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, null, app.info.packageName,
                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});
            } else if (hostingRecord.usesAppZygote()) {
                final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);

                startResult = appZygote.getProcess().start(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, null, app.info.packageName,
                        /*useUsapPool=*/ false.new String[] {PROC_START_SEQ_IDENT + app.startSeq});
            } else {
                // For important methods, call porcess.start
                startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith, app.info.packageName,
                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});
            }
            checkSlow(startTime, "startProcess: returned from zygote!");
            return startResult;
        } finally{ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); }}}Copy the code

Process.start Creates an application Process using Zygote

public class Process {
	public static ProcessStartResult start(@NonNull final String processClass,
                                           @Nullable final String niceName,
                                           int uid, int gid, @Nullable int[] gids,
                                           int runtimeFlags,
                                           int mountExternal,
                                           int targetSdkVersion,
                                           @Nullable String seInfo,
                                           @NonNull String abi,
                                           @Nullable String instructionSet,
                                           @Nullable String appDataDir,
                                           @Nullable String invokeWith,
                                           @Nullable String packageName,
                                           @Nullable String[] zygoteArgs) {
        return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, packageName,
                    /*useUsapPool=*/ true, zygoteArgs); }}Copy the code

The Zygote creation process is left for another article to analyze. The Zygote sends a Socket message to the Zygote server, which forks a new process that executes the Main method of the ActivityThread thread.

ActivityThread process

When the application process is incubated by Zygote, it first executes the ActivityThread.main method, where some initialization is performed, including creating a Looper for the main thread. The most important is the Attach method, which notifies AMS via an IPC message that the application process has been pulled up.

public final class ActivityThread extends ClientTransactionHandler {
    private void attach(boolean system, long startSeq) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if(! system) { android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                    UserHandle.myUserId());
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            ActivityManagerService ipc object
            final IActivityManager mgr = ActivityManager.getService();
            try {
                mgr.attachApplication(mAppThread, startSeq);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            // Watch for getting close to heap limit.......}}Copy the code
public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor.BatteryStatsImpl.BatteryCallback {
	public final void attachApplication(IApplicationThread thread, long startSeq) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final longorigId = Binder.clearCallingIdentity(); attachApplicationLocked(thread, callingPid, callingUid, startSeq); Binder.restoreCallingIdentity(origId); }}}Copy the code

It then moves to the attachApplication method of LocalService

public final class LocalService extends ActivityManagerInternal {
	public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
            synchronized (mGlobalLockWithoutBoost) {
                returnmRootActivityContainer.attachApplication(wpc); }}}Copy the code
class RootActivityContainer extends ConfigurationContainer
        implements DisplayManager.DisplayListener {
    
	boolean attachApplication(WindowProcessController app) throws RemoteException {
        final String processName = app.mName;
        boolean didSomething = false;
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
            final ActivityStack stack = display.getFocusedStack();
            if(stack ! =null) {
                stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList);
                final ActivityRecord top = stack.topRunningActivityLocked();
                final int size = mTmpActivityList.size();
                for (int i = 0; i < size; i++) {
                    final ActivityRecord activity = mTmpActivityList.get(i);
                    if (activity.app == null && app.mUid == activity.info.applicationInfo.uid
                            && processName.equals(activity.processName)) {
                        try {
                            // Call realStartActivityLocked on ActivityStackSuperVisor
                            if (mStackSupervisor.realStartActivityLocked(activity, app,
                                    top == activity /* andResume */.true /* checkConfig */)) {
                                didSomething = true; }}catch (RemoteException e) {
                            Slog.w(TAG, "Exception in new application when starting activity "
                                    + top.intent.getComponent().flattenToShortString(), e);
                            throw e;
                        }
                    }
                }
            }
        }
        if(! didSomething) { ensureActivitiesVisible(null.0.false /* preserve_windows */);
        }
        returndidSomething; }}Copy the code
public class ActivityStackSupervisor implements RecentTasks.Callbacks {
    boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
            boolean andResume, boolean checkConfig) throws RemoteException {

        try {
            // Create a Transaction to start the application
            final ClientTransaction clientTransaction = ClientTransaction.obtain(
                proc.getThread(), r.appToken);

            final DisplayContent dc = r.getDisplay().mDisplayContent;
            / / LaunchActivityITtem object
            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.icicle, r.persistentState, results, newIntents,
                   dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
                   	r.assistToken));

            // 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

We have previously analyzed the execution of clientTransaction, which is sent to the ApplicationThread via IPC communication and then executes the LaunchActivtyItem execute method

public class LaunchActivityItem extends ClientTransactionItem {
    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);
        The client object is an ActivityThread object
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); }}Copy the code
public final class ActivityThread extends ClientTransactionHandler {
    public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) {
       	
        / / create the Activity
        final Activity a = performLaunchActivity(r, customIntent);

        if(a ! =null) {
            r.createdConfig = new Configuration(mConfiguration);
            reportSizeConfigurations(r);
            if(! r.activity.mFinished && pendingActions ! =null) {
                pendingActions.setOldState(r.state);
                pendingActions.setRestoreInstanceState(true);
                pendingActions.setCallOnPostCreate(true); }}else {
            // If there was an error, for any reason, tell the activity manager to stop us.
            try {
                ActivityTaskManager.getService()
                        .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                                Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throwex.rethrowFromSystemServer(); }}return a;
    }
    
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ActivityInfo aInfo = r.activityInfo;
		
        / / create the Context
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            Instrument creates an Activity object using reflection
            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 {
            / / create the Application
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            if(activity ! =null) {
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if(r.overrideConfig ! =null) {
                    config.updateFrom(r.overrideConfig);
                }
                Window window = null;
                if(r.mPendingRemoveWindow ! =null && r.mPreserveWindow) {
                    window = r.mPendingRemoveWindow;
                    r.mPendingRemoveWindow = null;
                    r.mPendingRemoveWindowManager = null;
                }
                appContext.setOuterContext(activity);
                // The Activity binds the context
                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);

                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    // Execute onCreate
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                if(! activity.mCalled) {throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onCreate()");
                }
                r.activity = activity;
            }

        returnactivity; }}Copy the code

At this point the Activity is created and the onCreate method is executed, followed by the onStart, onResume callback. After the new Activity completes its onResume, the original top-stack Activity begins its onStop lifecycle.