There are a lot of articles about the Activity startup process on Baidu.

But these articles are either too simplistic, ignoring details in order to clarify the process; Otherwise, it is too deep into details, resulting in unclear context of the whole article, even the main process of Activity starting is not clearly explained.

Through this article, we will comb through the overall process of launching an Activity and the details we should pay attention to.

The overall process of starting an Activity

The start of a normal Activity

A normal Activity starts by calling the startActivity function to start a new Activity. The overall process is shown as follows:

There are two processes involved, App process and AMS process. The overall steps are:

  1. The initiator Activity asks the target Activity to start with Instrumentation.
  2. Instrumentation through AMS in the App process IBinder interface (IActivityManager), access to AMS, at this time App process blocking waiting for AMS process call back, the use of cross-process technology is AIDL;
  3. The AMS process performs a series of validation tasks, such as determining whether the target Activity instance already exists, what startup mode it is in, and whether it is registered in the Androidmanifest.xml file.
  4. When AMS validation is complete, transactions are sent to the App process via ClientLifeCycleManager, The ApplicationThread of App process is accessed by the IBinder interface (IApplicationThread) of AMS process, and the cross-process technology is AIDL.
  5. ApplicationThread is an inner class of ActivityThread. When ApplicationThread receives a transaction from AMS, it forwards the transaction directly to ActivityThread.
  6. The ActivityThread uses Instrumentation to create instances using class loaders (reflections), while using Instrumentation to call back to the target Activity lifecycle.

Introduce a few key classes:

  • Instrumentation: Instrumentation is the class in which activities are associated with the outside world. Target activities require Instrumentation to start, and ActivityThreads allow Instrumentation to create activities and call back to the Activity lifecycle.
  • ActivityThread: Each application has a unique instance that manages Activity creation. ActivityThread’s internal class ApplicationThread is only responsible for communicating between App and AMS processes, handing transactions from AMS to ActivityThread.
  • AMS, full name for ActivityManagerService, is a system-level service that manages four components.

The root Activity starts

The root Activity is the first Activity that the application starts when we click on the mobile desktop icon. The process for starting the root Activity is similar to the process for starting a normal Activity, except that a new App process is required to start the root Activity. The overall process is shown as follows:

There are four processes involved: Launcher, AMS, App, and Zygote. The overall steps are:

  1. The Launcher process accesses the AMS process to start the target Activity using a cross-process technology called AIDL.
  2. AMS process access Zygote process request to start a new process, using the cross-process technology is Socket;
  3. Called by the Zygote processforkFunction to create App process;
  4. After the App process is created, the App process accesses the AMS process for notification, and the cross-process technology is AIDL.
  5. When the AMS process receives a notification from the App process, it encapsulates the Activity startup as a ClientTransaction (described below) and sends the encapsulated transaction to the App process.
  6. After the App process receives a transaction from AMS, it creates a target Activity based on the transaction and calls back the target Activity’s life cycle.

The source code

The root Activity startup process contains the normal Activity startup process, so we only need to analyze the root Activity startup process.

The whole startup process can be divided into three stages:

  1. The Activity request AMS
  2. AMS handles requests
  3. The App process creates the target Activity

The Activity request AMS

The Android desktop is actually an App called Launcher, which calls the startActivitySafely function when the user clicks on an App icon on the desktop.

// packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
public boolean startActivitySafely(View v, Intent intent, ItemInfo item)
{.../ / add Intent. FLAG_ACTIVITY_NEW_TASK
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    if (Utilities.ATLEAST_MARSHMALLOW 
            && (item instanceof ShortcutInfo) 
            && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT 
            || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) 
            && !((ShortcutInfo) item).isPromise())
    {
        startShortcutIntentSafely(intent, optsBundle, item);
    }
    else if (user == null || user.equals(Process.myUserHandle()))
    {
        startActivity(intent, optsBundle);
    }
    else
    {
        LauncherAppsCompat.getInstance(this).startActivityForProfile(
                intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
    }
    return true; . }Copy the code

The startActivity function of activity.java is eventually called.

// frameworks/base/core/java/android/app/Activity.java
public void startActivity(Intent intent)
{
    this.startActivity(intent, null);
}

public void startActivity(Intent intent, Bundle options)
{
    if(options ! =null)
    {
        startActivityForResult(intent, -1, options);
    }
    else
    {
        startActivityForResult(intent, -1); }}public void startActivityForResult(Intent intent, int requestCode)
{
    startActivityForResult(intent, requestCode, null);
}

public void startActivityForResult(Intent intent, int requestCode, Bundle options)
{
    // mParent refers to the ActivityGroup, which is now Fragment. MParent is empty
    if (mParent == null)
    {
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); }... }// Instrumentation.java
public ActivityResult execStartActivity(
        Context who, IBinder contextThread,
        IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options
){...intresult = ActivityManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target ! =null ? target.mEmbeddedID : null,
                requestCode, 0.null, options); . }Copy the code

ActivityManager. GetService () is an AIDL calls, access to the binder AMS instances as part of a drive. Basically, call the startActivity function of AMS.

AMS handles requests

Before going through the AMS section of the code, let’s introduce a few key classes that will appear in AMS code:

  • ProcessRecord: A class that describes information about a process. one ProcessRecord corresponds to one process.
  • ActivityRecord: A class that describes information about an Activity. An ActivityRecord corresponds to an Activity.
  • TaskRecord: a class that describes information about a Task. A TaskRecord corresponds to a Task and is maintained internallyArrayList<ActivityRecord>Used to record activityRecords saved in tasks.
  • ActivityStack: a class for managing tasks (TaskRecord), one of which is maintained internallyArrayList<TaskRecord>Is used to record tasks.
  • ActivityStackSupervisor: The class that manages ActivityStack. ActivityStack is created and managed by ActivityStackSupervisor. This class is created when AMS initializes.
  • ClientTransaction: A container that holds a series of messages that need to be sent to the App process. These messages include callbacks and the final life cycle status.
  • ClientTransactionItem: A callback message format sent to the App process for scheduling and execution.
  • LaunchActivityItem: Inherited from ClientTransactionItem, a message format used to call back the App process to start an Activity.
  • ActivityLifecycleItem: Inherits from ClientTransactionItem, a message format used to call back to the lifecycle state that the Activity requested to start by the App process should reach.
// ActivityManagerService.java
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());
}

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
){.../ / mActivityStartController ActivityStarter obtainStarter is available
    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) // mRequest.mayWait = true
            .execute();
}
Copy the code

All the logic for starting an Activity in AMS is performed by the ActivityStarter.

// ActivityStarter.java
int execute(a)
{...// mrequest. mayWait = true, if hit
    if (mRequest.mayWait)
    {
        returnstartActivityMayWait(mRequest.caller, mRequest.callingUid, mRequest.callingPackage, 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); }... }private int startActivityMayWait(
        IApplicationThread caller, int callingUid,
        String callingPackage, Intent intent, String resolvedType,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, 
        int startFlags, ProfilerInfo profilerInfo, WaitResult outResult,
        Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
        int userId, TaskRecord inTask, String reason,
        boolean allowPendingRemoteAnimationRegistryLookup
){...final ActivityRecord[] outRecord = new ActivityRecord[1];
    intres = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason, allowPendingRemoteAnimationRegistryLookup); . }private int startActivity(
        IApplicationThread caller, Intent intent, Intent ephemeralIntent,
        String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
        String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
        SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
        ActivityRecord[] outActivity, TaskRecord inTask, String reason,
        boolean allowPendingRemoteAnimationRegistryLookup
){... mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord, inTask, allowPendingRemoteAnimationRegistryLookup); . }private int startActivity(
        IApplicationThread caller, Intent intent, Intent ephemeralIntent,
        String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
        String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
        SafeActivityOptions options,
        boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
        TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup
){
    // Get the ProcessRecord object that describes the process Launcher
    ProcessRecord callerApp = null;
    if(caller ! =null) { callerApp = mService.getRecordForAppLocked(caller); . }...// Create an ActivityRecord object for the target Activity to record information about the target Activity
    ActivityRecord r = newActivityRecord(mService, callerApp, callingPid, callingUid, callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode, componentSpecified, voiceSession ! =null, mSupervisor, checkedOptions, sourceRecord); .return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
            true /* doResume */, checkedOptions, inTask, outActivity);
}

private int startActivity(
        final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, 
        TaskRecord inTask, ActivityRecord[] outActivity
){... result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags, doResume, options, inTask, outActivity); . }private int startActivityUnchecked(
        final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, 
        TaskRecord inTask, ActivityRecord[] outActivity
){
    // Initialization state. MStartActivity = target Activity, mDoResume = doResume = truesetInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession, voiceInteractor); . mIntent.setFlags(mLaunchFlags);/ / getReusableIntentActivity - > according to boot mode to judge whether to reuse existing target Activity instance.
    // If judged to be reused, return an ActivityRecord object describing the corresponding instance; Otherwise return NULLActivityRecord reusedActivity = getReusableIntentActivity(); .// If you need to reuse an existing target Activity instance. Obviously if doesn't hit
    if(reusedActivity ! =null) {... }...If the target Activity is the same as the Activity currently at the bottom of the foreground Task (top of the stack), then we need to check that it should only be started once. * (Check whether the process should start the target Activity again) */
    
    // Get all current tasks that might get focus (Task stack)
    final ActivityStack topStack = mSupervisor.mFocusedStack;
    // Get the ActivityRecord object that describes the Activity currently at the bottom of the foreground Task (top of the stack)
    final ActivityRecord topFocused = topStack.getTopActivity();
    final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);

    // If the process should not start the target Activity again, dontStart = true;
    // dontStart = false
    final booleandontStart = top ! =null && mStartActivity.resultTo == null&& top.realActivity.equals(mStartActivity.realActivity) && top.userId == mStartActivity.userId && top.app ! =null&& top.app.thread ! =null&& ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) ! =0
            || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK));
            
    // If is not hit
    if (dontStart)
    {
        ......
    }

    boolean newTask = false; .intresult = START_SUCCESS; .FLAG_ACTIVITY_NEW_TASK = intent.flag_activity_new_task = intent.flag_activity_new_task
    // If hits
    if (mStartActivity.resultTo == null && mInTask == null&&! mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) ! =0)
    {
        newTask = true;
        // Switch tasks. If the target Task is not created, it is created.
        // mTargetStack = target Taskresult = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack); }...// Set the target Task to the foreground and play the target Activity's start animation (if any)
    mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, 
            mKeepCurTransition, mOptions);

    // mDoResume = true, if hit
    if (mDoResume)
    {
        // Get the ActivityRecord object that describes the Activity whose state is currently visible
        final ActivityRecord topTaskActivity =
                mStartActivity.getTask().topRunningActivityLocked();
        // Determine whether the Activity currently at the bottom of the foreground Task (top of the stack) is the target Activity
        // mStartActivity = topTaskActivity. If not hit, else
        if(! mTargetStack.isFocusable() || (topTaskActivity ! =null&& topTaskActivity.mTaskOverlay && mStartActivity ! = topTaskActivity)) { ...... }else{... mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity, mOptions); }}... }Copy the code

All handling of the Activity startup mode is done in the startActivityUnchecked function of the ActivityStarter.

There are a lot of details in the startActivityUnchecked function, some of which I haven’t covered because they are irrelevant to the process being analyzed.

If you’re interested in the Activity launch mode, be sure to take a closer look at those details.

// ActivityStackSupervisor.java
boolean resumeFocusedStackTopActivityLocked( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions ){...// If the target Task is already in the foreground
    if(targetStack ! =null && isFocusedStack(targetStack))
    {
        returntargetStack.resumeTopActivityUncheckedLocked(target, targetOptions); }... }// ActivityStack.java
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options)
{...boolean result = false; . result = resumeTopActivityInnerLocked(prev, options); .return result;
}

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, // Target Activity ActivityOptions options){...// Get the ActivityRecord object that describes the Activity whose state is currently visible
    final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */); .// prev = next, if not hit
    if(prev ! =null&& prev ! = next) { ...... }...Next. App = next. App. Thread = null, else
    if(next.app ! =null&& next.app.thread ! =null) {... realStartActivityLocked(r, app, andResume, checkConfig);return;
    }
    else{... mStackSupervisor.startSpecificActivityLocked(next,true.true); }...return true;
}
Copy the code

Because we are analyzing the startup process of the root Activity, the target App process is not started yet.

If this is the normal Activity startup process, it hits if and calls realStartActivityLocked directly. (This function is also called after the target App process is created, so it will be analyzed later.)

The startup process of the root Activity is simply one more process creation operation than the normal Activity startup process.

AMS asked Zygote to create the App process

// ActivityStackSupervisor.java
void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig)
{
    // Find ProcessRecord for all App processes in the system to see if the target App process has been started
    // The target App process is not started, App = null
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, true); .// app = null, if not hit
    if(app ! =null&& app.thread ! =null) {... } mService.startProcessLocked(r.processName, r.info.applicationInfo,true.0."activity", r.intent.getComponent(), false.false.true);
}

// ActivityManagerService.java
final ProcessRecord startProcessLocked(String processName,
        ApplicationInfo info, boolean knownToBeDead, int intentFlags,
        String hostingType, ComponentName hostingName, boolean allowWhileBooting,
        boolean isolated, boolean keepIfLarge
){
    return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
            hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
            null /* ABI override */.null /* entryPoint */.null /* entryPointArgs */.null /* crashHandler */);
}

final ProcessRecord startProcessLocked(
        String processName, ApplicationInfo info,
        boolean knownToBeDead, int intentFlags, String hostingType, 
        ComponentName hostingName, boolean allowWhileBooting, boolean isolated, 
        int isolatedUid, boolean keepIfLarge, String abiOverride, 
        String entryPoint, String[] entryPointArgs, Runnable crashHandler
){...final booleansuccess = startProcessLocked(app, hostingType, hostingNameStr, abiOverride); .return success ? app : null;
}

private final boolean startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride ){
    return startProcessLocked(app, hostingType, hostingNameStr,
            false /* disableHiddenApiChecks */, abiOverride);
}

private final boolean startProcessLocked(ProcessRecord app, String hostingType,
        String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride
){...returnstartProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith, startTime); . }private boolean startProcessLocked(
        String hostingType, String hostingNameStr, String entryPoint,
        ProcessRecord app, int uid, int[] gids, 
        int runtimeFlags, int mountExternal, String seInfo, 
        String requiredAbi, String instructionSet, String invokeWith,
        long startTime
){...FLAG_PROCESS_START_ASYNC Defaults to true, if hit
    if (mConstants.FLAG_PROCESS_START_ASYNC)
    {
        ......
        finalProcessStartResult startResult = startProcess(app.hostingType, entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime); . }... }private ProcessStartResult startProcess(String hostingType, String entryPoint,
        ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
        String seInfo, String requiredAbi, String instructionSet, String invokeWith,
        long startTime
){...// Obviously do else
    if (hostingType.equals("webview_service")) {... }else
    {
        startResult = Process.start(entryPoint,
                app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                app.info.dataDir, invokeWith,
                newString[] {PROC_START_SEQ_IDENT + app.startSeq}); }...return startResult;
}

// Process.java
public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int runtimeFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String invokeWith,
                              String[] zygoteArgs
){
    return zygoteProcess.start(processClass, niceName, uid, gid, gids,
            runtimeFlags, mountExternal, targetSdkVersion, seInfo,
            abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}

// ZygoteProcess.java
public final Process.ProcessStartResult start(final String processClass,
                                              final String niceName,
                                              int uid, int gid, int[] gids,
                                              int runtimeFlags, int mountExternal,
                                              int targetSdkVersion,
                                              String seInfo,
                                              String abi,
                                              String instructionSet,
                                              String appDataDir,
                                              String invokeWith,
                                              String[] zygoteArgs
){...return startViaZygote(processClass, niceName, uid, gid, gids,
            runtimeFlags, mountExternal, targetSdkVersion, seInfo,
            abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */, zygoteArgs); . }private Process.ProcessStartResult startViaZygote(final String processClass,
                                                  final String niceName,
                                                  final int uid, final int gid,
                                                  final int[] gids,
                                                  int runtimeFlags, int mountExternal,
                                                  int targetSdkVersion,
                                                  String seInfo,
                                                  String abi,
                                                  String instructionSet,
                                                  String appDataDir,
                                                  String invokeWith,
                                                  boolean startChildZygote,
                                                  String[] extraArgs
){...return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}

private static Process.ProcessStartResult zygoteSendArgsAndGetResult( ZygoteState zygoteState, ArrayList
       
         args )
       {
    try
    {
        intsz = args.size(); .final BufferedWriter writer = zygoteState.writer;
        final DataInputStream inputStream = zygoteState.inputStream;

        writer.write(Integer.toString(args.size()));
        writer.newLine();

        for (int i = 0; i < sz; i++)
        {
            String arg = args.get(i);
            writer.write(arg);
            writer.newLine();
        }

        writer.flush();

        Process.ProcessStartResult result = new Process.ProcessStartResult();

        // Block the thread until Zygote returns
        result.pid = inputStream.readInt();
        result.usingWrapper = inputStream.readBoolean();

        return result;
    }
    catch(IOException ex) { zygoteState.close(); }}Copy the code

After the process to create the Zygote process, the specific code to create the process is no longer analyzed, interested in their own follow-up.

You can see that the AMS process communicates with the Zygote process through sockets. When the AMS process communicates with the Zygote process, the AMS process synchronously waits for the Zygote process to return the result.

When the target App process is created, Zygote process returns the result to AMS through Socket. The AMS thread wakes up and returns the result to the Launcher process. There are no particular details to note about the return process, which we won’t analyze here.

The App process is created

When the target App process is created, it is initialized to call the Main function of the ActivityThread.

// ActivityThread.java
public static void main(String[] args)
{... thread.attach(false, startSeq); . }private void attach(boolean system, long startSeq)
{...AIDL calls attachApplication in AMS
    finalIActivityManager mgr = ActivityManager.getService(); mgr.attachApplication(mAppThread, startSeq); . }// ActivityManagerService.java
public final void attachApplication(IApplicationThread thread, long startSeq)
{... attachApplicationLocked(thread, callingPid, callingUid, startSeq); . }private final boolean attachApplicationLockedIApplicationThread Thread, // thread = ApplicationThread of the target App processint pid, int callingUid, long startSeq
){...// When the system is started, mProcessesReady = normalMode = true
    booleannormalMode = mProcessesReady || isAllowedWhileBooting(app.info); .if (normalMode)
    {
        if (mStackSupervisor.attachApplicationLocked(app))
        {
            didSomething = true; }}... }// ActivityStackSupervisor.java
boolean attachApplicationLocked(ProcessRecord app)
{...for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx)
    {
        final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
        // Iterate through all tasks in the system
        for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx)
        {
            final ActivityStack stack = display.getChildAt(stackNdx);
            // If the current Task is not in the foreground, skip this loop
            if(! isFocusedStack(stack)) {continue;
            }
            // Assign mTmpActivityList to all visible activities
            stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList);
            // Get the ActivityRecord object that describes the Activity whose state is currently visible
            final ActivityRecord top = stack.topRunningActivityLocked();
            final int size = mTmpActivityList.size();
            / / traverse mTmpActivityList
            for (int i = 0; i < size; i++)
            {
                final ActivityRecord activity = mTmpActivityList.get(i);
                // If the Activity currently traversed belongs to the target App process
                if (activity.app == null 
                        && app.uid == activity.info.applicationInfo.uid
                        && processName.equals(activity.processName))
                {
                    // Execute realStartActivityLocked
                    if (realStartActivityLocked(activity, app,
                            top == activity /* andResume */.true /* checkConfig */))
                    {
                        didSomething = true;
                    }
                }
            }
        }
    }
    ......
    return didSomething;
}
Copy the code

Finally, when the App process is created, all visible activities in AMS will be traversed. If the Activity belongs to the target App process, realStartActivityLocked is called.

// ActivityStackSupervisor.java
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
        booleanAndResume, // At this point top = activity, andResume =true
        boolean checkConfig)
{...// Create a container ClientTransaction for the callback message
    final ClientTransaction clientTransaction = 
            ClientTransaction.obtain(app.thread, r.appToken);
    // Add the callback message LaunchActivityItem (starts an Activity)
    clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
            System.identityHashCode(r), r.info,
            mergedConfiguration.getGlobalConfiguration(),
            mergedConfiguration.getOverrideConfiguration(), r.compat,
            r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
            r.persistentState, results, newIntents, mService.isNextTransitionForward(),
            profilerInfo));

    final ActivityLifecycleItem lifecycleItem;
    // andResume = true, if hit
    if (andResume)
    {
        // Create callback message ResumeActivityItem (callback lifecycle status is Resume)
        lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
    }
    else
    {
        lifecycleItem = PauseActivityItem.obtain();
    }
    // Add the callback message ResumeActivityItem
    clientTransaction.setLifecycleStateRequest(lifecycleItem);

    // Send ClientTransaction to the App processmService.getLifecycleManager().scheduleTransaction(clientTransaction); . }// ClientLifecycleManager.java
void scheduleTransaction(ClientTransaction transaction)
{... transaction.schedule(); . }// ClientTransaction.java
public void schedule(a)
{
    // mClient = ApplicationThread of the target App process
    // AIDL call to ApplicationThread's scheduleTransaction function
    mClient.scheduleTransaction(this);
}
Copy the code

After the AIDL call, the target App process is returned to execute the scheduleTransaction function.

The App process creates the target Activity

// ActivityThread$ApplicationThread.java
public void scheduleTransaction(ClientTransaction transaction)
{
    ActivityThread.this.scheduleTransaction(transaction);
}

/ / ClientTransactionHandler. Java (ActivityThread inherited from ClientTransactionHandler)
void scheduleTransaction(ClientTransaction transaction)
{
    / / pretreatment
    transaction.preExecute(this);
    sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}

abstract void sendMessage(int what, Object obj);

// ActivityThread.java
@Override
void sendMessage(int what, Object obj)
{
    sendMessage(what, obj, 0.0.false);
}

private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async)
{.../ / create the message
    Message msg = Message.obtain();
    msg.what = what; // H.EXECUTE_TRANSACTION
    msg.obj = obj; // ClientTransaction
    msg.arg1 = arg1;
    msg.arg2 = arg2;
    if (async)
    {
        msg.setAsynchronous(true);
    }
    // the mH is the main thread handler that switches threads to perform ClientTransaction
    mH.sendMessage(msg);
}

// ActivityThread$H.java
@Override
public void handleMessage(Message msg)
{...switch (msg.what)
    {
        ......
        case EXECUTE_TRANSACTION:
            final ClientTransaction transaction = (ClientTransaction) msg.obj;
            // Call the transaction pool to process ClientTransaction
            mTransactionExecutor.execute(transaction);
            if (isSystem())
            {
                transaction.recycle();
            }
            break; . }... }// TransactionExecutor.java
public void execute(ClientTransaction transaction)
{
    final IBinder token = transaction.getActivityToken();
    // Execute the callback message LaunchActivityItem
    executeCallbacks(transaction);
    Execute the callback message ResumeActivityItem
    executeLifecycleState(transaction);
    mPendingActions.clear();
}
Copy the code

The callback messages LaunchActivityItem and ResumeActivityItem are executed in TransactionExecutor’s Execute function, respectively.

These are two different processes that need to be analyzed separately.

Perform LaunchActivityItem

// TransactionExecutor.java
public void executeCallbacks(ClientTransaction transaction)
{...// Get the number of callbacks in ClientTransaction
    final int size = callbacks.size();
    // Iterate over all callbacks in ClientTransaction
    for (int i = 0; i < size; ++i)
    {
        finalClientTransactionItem item = callbacks.get(i); . item.execute(mTransactionHandler, token, mPendingActions); . }}// LaunchActivityItem.java
public void execute(ClientTransactionHandler client, // client = ActivityThread IBinder token, PendingTransactionActions pendingActions)
{
    // Create an ActivityClientRecord object
    ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
            mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, 
            mPersistentState, mPendingResults, mPendingNewIntents, mIsForward,
            mProfilerInfo, client);
    // Call the handleLaunchActivity function for ActivityThread
    client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
}

// ActivityThread.java
public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent)
{...finalActivity a = performLaunchActivity(r, customIntent); . }private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent)
{
    // Get ActivityInfo, user stored code, AndroidManifes information
    ActivityInfo aInfo = r.activityInfo;
    if (r.packageInfo == null)
    {
        // Get the Apk description class
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                Context.CONTEXT_INCLUDE_CODE);
    }

    // Get the package name type information for the Activity
    ComponentName component = r.intent.getComponent();
    if (component == null) { component = r.intent.resolveActivity( mInitialApplication.getPackageManager()); r.intent.setComponent(component); }...// Create the Activity context
    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null; . java.lang.ClassLoader cl = appContext.getClassLoader();// Create an activity with Instrumentation (create using reflection)activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); .// Create an Application based on the package name
    Application app = r.packageInfo.makeApplication(false, mInstrumentation); .if(activity ! =null) {...// Add Window to the Activity
        Window window = null;
        if(r.mPendingRemoveWindow ! =null && r.mPreserveWindow)
        {
            window = r.mPendingRemoveWindow;
            r.mPendingRemoveWindow = null;
            r.mPendingRemoveWindowManager = null; }...// Execute the attach function of the Activity for initialization
        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); ./ / the else
        if (r.isPersistable())
        {
            mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
        }
        else
        {
            // Call back the onCreate function of the Activity with InstrumentationmInstrumentation.callActivityOnCreate(activity, r.state); }... }...return activity;
}

// Instrumentation.java
public void callActivityOnCreate(Activity activity, Bundle icicle)
{... activity.performCreate(icicle); . }// Activity.java
final void performCreate(Bundle icicle)
{
    performCreate(icicle, null);
}

final void performCreate(Bundle icicle, PersistableBundle persistentState)
{.../ / the else
    if(persistentState ! =null)
    {
        onCreate(icicle, persistentState);
    }
    else
    {
        // Call the onCreate function in the lifecycleonCreate(icicle); }... }Copy the code

After executing the LaunchActivityItem, an instance object of the target Activity is created and the onCreate function in the target Activity lifecycle is called back.

Perform ResumeActivityItem

// TransactionExecutor.java
private void executeLifecycleState(ClientTransaction transaction)
{...// lifecycleItem = ResumeActivityItemlifecycleItem.execute(mTransactionHandler, token, mPendingActions); . }// ResumeActivityItem.java
public void execute(ClientTransactionHandler client, // client = ActivityThread IBinder token, PendingTransactionActions pendingActions)
{...// Call the handleResumeActivity function of ActivityThread
    client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
            "RESUME_ACTIVITY"); . }// ActivityThread.java
public void handleResumeActivity(IBinder token, boolean finalStateRequest, 
        boolean isForward, String reason)
{...finalActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); . }public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
        String reason)
{
    finalActivityClientRecord r = mActivities.get(token); . r.activity.performResume(r.startsNotResumed, reason); .return r;
}

// Activity.java
final void performResume(boolean followedByPause, String reason)
{
    // Determine whether the Restart process needs to be executed
    performRestart(true /* start */, reason); .Instrumentation calls back the Activity's onResume function
    mInstrumentation.callActivityOnResume(this); . }// Instrumentation.java
public void callActivityOnResume(Activity activity)
{...// Callback the onResume function in the lifecycleactivity.onResume(); . }Copy the code

After executing the ResumeActivityItem, the onResume function in the target Activity lifecycle is called back.

conclusion

This article analyzes the complete startup process of the root Activity, and analyzes some of the code that makes sense to us developers.

Understanding the Activity startup process is a great help in understanding the Activity startup mode and Activity lifecycle. But the source code is still very large, there is no way to cover everything, I hope readers can refer to this article to try to read the source code, deepen understanding.

reference

Android Activity startup process (based on API28)

AMS startActivity()