review

ActivityManagerService is the activity management service. It manages the activities, services and other components that interact with the system. For convenience, we call it AMS for short. We know that an Activity goes through a series of life cycles during startup that reflect how AMS creates and manages an Activity while interacting with WindowManagerService. This makes starting an activity a very complex task. This article does not go into the details of the entire process, but covers the key parts of the activity launch process.

The startup mode of the Activity -Launcher

First of all, there are many possible ways to start an activity. For example, the most typical way is to click the icon on the Launcher to start the activity, or to start the activity within the application to jump, or to start the activity through ADB. However, the basic process is similar regardless of which way to start the activity. Here we use the Launcher as a standard scenario to describe what happens during an activity launch to make it appear in front of our eyes.

The Launcher is a standard system desktop application that manages all the installed apps in the system. These apps are displayed in a grid form in the Launcher. We click on an app icon to start the entire app and start its main activity.

FLAG_ACTIVITY_NEW_TASK indicates that we will create a new task stack for the application. This is followed by starting the specified activity, officially starting startActivity.

packages/apps/Launcher2/src/com/android/launcher2/Launcher.java

boolean startActivity(View v, Intent intent, Object tag) {
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    try {
        // Only launch using the new animation if the shortcut has not opted out (this is a
        // private contract between launcher and may be ignored in the future).
        booleanuseLaunchAnimation = (v ! =null) &&
                !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
        if (useLaunchAnimation) {
            ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0.0,
                    v.getMeasuredWidth(), v.getMeasuredHeight());
            startActivity(intent, opts.toBundle());
        } else {
            startActivity(intent);// Call the startActivity of the activity to start
        }
        return true;
    } catch (SecurityException e) {}
    return false;
}
Copy the code

An activity launched from the Launcher adds FLAG_ACTIVITY_NEW_TASK by default, which creates a new task stack for the application.

The requestCode we pass to startActivityForResult from the Launcher is -1, which means we don’t accept the return value of the activity.

Activity:   startActivity->startActivityForResult

1. [Activity.startActivityForResult]===>[Instrumention.execStartActivity]

public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
    ……
    Instrumentation.ActivityResult ar =
        mInstrumentation.execStartActivity(
            this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options); ... }Copy the code

ExecStartActivity parameter description, for Launcher:

  • Who: Indicates the application Launcher
  • MMainThread. GetApplicationThread () : ApplicationThread it is a Binder for the Launcher
  • Target: This represents the Activity Launcher
  • requestCode: -1
  • Intent: Indicates the intent of an Activity to start the application
  • options: null

The execStartActivity is invoked using the Instrumention

2.[Instrumention.execStartActivity]===>[AMS.startActivity]
public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) { IApplicationThread whoThread = (IApplicationThread) contextThread; ...try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess();
        // Start the Activity with AMS with binder calls
        intresult = ActivityManagerNative.getDefault() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target ! =null ? target.mEmbeddedID : null,
                    requestCode, 0.null.null, options);
            An error is reported if the Activity is not registered in the manifest
        checkStartActivityResult(result, intent);
    } catchRemoteException (e) {}...return null;
}
Copy the code

Instrumention uses ActivityManagerNative to fetch the AMS proxy, which is then used for IPC calls through Binder. We continue here with the implementation of startActivity in AMS, one of the many services in the SystemServer process, which is started in systemServer.java for details.

[AMS.startActivity]===>[AMS.startActivityAsUser]
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

@Override
public final int startActivity(IApplicationThread caller, String
callingPackage,Intent intent, String resolvedType, IBinder resultTo,String resultWho, int requestCode, int startFlags,
String profileFile, ParcelFileDescriptor profileFd, Bundle options){// Start the process at the AMS portal
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode,
            startFlags, profileFile, profileFd, options, UserHandle.getCallingUserId());
}
Copy the code

Here we make a note of the parameters passed:

  • Caller: An ApplicationThread that represents a Launcher object
  • CallingPackage: The package name of the Launcher that calls it
  • Intent: Indicates the Intent of the activity to start
  • ResolvedType: The MIME type specified in the Intent is usually not null
  • The -AppToken of the activityRecord represents the Launcher, which in fact represents the Launcher.
  • resultWho : null
  • requestCode:-1
  • startFlags : 0
  • profileFile:-1
  • profileFd:null
  • Options:null

[AMS.startActivityAsUser]===>[ASS.startActivityAsUser]
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo,
        String resultWho, int requestCode, int startFlags,
        String profileFile, ParcelFileDescriptor profileFd, Bundle options, int userId) {
    enforceNotIsolatedCaller("startActivity");
    userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,false.true."startActivity".null);
    // TODO: Switch to user app stacks here.
    //mStackSupervisor is an ActivityStackSupervisor that operates on ActivityStack by name
    ProfileFile is null profileFd is null
    return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
            resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
            null.null, options, userId);
}
Copy the code

AMS, as the manager of an activity, is lazy and doesn’t do anything. Almost all services are similar in that they don’t actually do anything, but instead delegate it to other “proxy” objects. The “proxy” object here is ActivityStackSupervisor, which by its name is responsible for monitoring and managing ActivityStack.

frameworks/base/services/java/com/android/server/am/ActivityStackSupervisor.java

final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
            String resultWho, int requestCode, int startFlags, String profileFile,
            ParcelFileDescriptor profileFd, WaitResult outResult, Configuration config,
            Bundle options, int userId) {...// Collect information about the target of the Intent.
    ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
            profileFile, profileFd, userId);Collect information about the Intent parameter into aInfo

    synchronized (mService) {
    int callingPid;//Launcher: The default is -1
    if (callingUid >= 0) {
        callingPid = -1;
    } else if (caller == null) {
        callingPid = Binder.getCallingPid();
        callingUid = Binder.getCallingUid();
    } else {
        callingPid = callingUid = -1;//Launcher:D}......// Continue calling startActivityLocked to start the process
    int res = startActivityLocked(caller, intent, resolvedType,
            aInfo, resultTo, resultWho, requestCode, callingPid, callingUid,
            callingPackage, startFlags, options, componentSpecified, null); ... }Copy the code

The startActivityMayWait method gets ActivityInfo from the intent of the activity to be started, and then sets callingPid and callingUid to -1. Call startActivityLocked further.

frameworks/base/services/java/com/android/server/am/ActivityStackSupervisor.java

final int startActivityLocked(IApplicationThread caller,
            Intent intent, String resolvedType, ActivityInfo aInfo, IBinder resultTo,
            String resultWho, int requestCode,
            int callingPid, int callingUid, String callingPackage, int startFlags, Bundle options,
            boolean componentSpecified, ActivityRecord[] outActivity) {

	ProcessRecord callerApp = null;
    if(caller ! =null) {// Validates the caller process for the application process in which the Launcher is located
        callerApp = mService.getRecordForAppLocked(caller);// Find the caller's ProcessRecord information in AMS
        if(callerApp ! =null) {
            callingPid = callerApp.pid;// The caller's process ID
            callingUid = callerApp.info.uid;// The caller's user ID}... } / Do some permission checkingfinal int startAnyPerm = mService.checkPermission(
            START_ANY_ACTIVITY, callingPid, callingUid);
    final int componentPerm = mService.checkComponentPermission(aInfo.permission, callingPid,
            callingUid, aInfo.applicationInfo.uid, aInfo.exported);
	
	
	// Create ActivityRecord for the new Activity. AcitivtyRecord is used to describe the Activity
    ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
            intent, resolvedType, aInfo, mService.mConfiguration,
            resultRecord, resultWho, requestCode, componentSpecified, this);
	
	 // Continue calling the startup process
    //Launcher:sourceRecord holds the entity information for the Launcher Activity. Note that the doResume parameter defaults to true
    err = startActivityUncheckedLocked(r, sourceRecord, startFlags, true, options);
	
}
Copy the code

The main things this method does are: 1. Initialize the caller’s process ID and user ID by looking for its ProcessRecord. 2. Perform some permissions checks, such as caller permissions and startup component permissions 3. An AtivityRecord is created for the activity to be started, and an appToken is created to represent the ActivityRecord, which indirectly represents the activity to be started. 4. Further calls startActivityUncheckedLocked to further start, here’s sourceRecord ActivityRecord for the Launcher. R is the activityRecord for the activity we want to start

final int startActivityUncheckedLocked(ActivityRecord r,
            ActivityRecord sourceRecord, int startFlags, boolean doResume,
            Bundle options) {...if(((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) ! =0 &&
	                (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
	                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
	                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
		
        if (r.resultTo == null) {
            //Launcher: Here we call findTaskLocked to find out if there is an instance of R, which should be null because it is loaded from a LauncherActivityRecord intentActivity = r.launchMode ! = ActivityInfo.LAUNCH_SINGLE_INSTANCE ? findTaskLocked(r) : findActivityLocked(intent, r.info); }}...if (r.resultTo == null&&! addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) ! =0) {//Launcher: true requires a new task
        targetStack = adjustStackFocus(r);
        moveHomeStack(targetStack.isHomeStack());
        if (reuseTask == null) { r.setTask(targetStack.createTaskRecord(getNextTaskId(), newTaskInfo ! =null? newTaskInfo : r.info, newTaskIntent ! =null ? newTaskIntent : intent,
                    true), null.true);// Create a TaskRecord and save it in r's Task member
        } else {
            r.setTask(reuseTask, reuseTask, true);
        }
        newTask = true; ... }... mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,intent, r.getUriPermissionsLocked()); targetStack.mLastPausedActivity =null;
	targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
	mService.setFocusedActivityLocked(r);
	
}
Copy the code

This step first finds a task for the activity to start, but when the activity is launched with a Launcher task that has not yet been created, you need to create a task for it and put it into r via setTask Settings. StartActivityLocked is then called and mLastPausedActivity is set to null, indicating that no activity is currently suspended. Set mFocusedActivity to the current activity, indicating a focus activity. For Launcher, newTask is true.

final void startActivityLocked(ActivityRecord r, boolean newTask,
            boolean doResume, boolean keepCurTransition, Bundle options) {
	TaskRecord rTask = r.task;// The TaskRecord stored in ActivityRecord
	final int taskId = rTask.taskId;
	if (taskForIdLocked(taskId) == null || newTask) {
	            insertTaskAtTop(rTask);
	            mWindowManager.moveTaskToTop(taskId);
	 }
	……
	task.addActivityToTop(r);// Put ActivityRecord at the top of the task stack
	task.setFrontOfTask();// Set task stack to foreground stack
	
	r.putInHistory();
	
	if(! isHomeStack() || numActivities() >0) {
		……
	}else{ mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen, (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) ! =0,          r.userId,r.info.configChanges);
	}
	if (doResume) {
	    mStackSupervisor.resumeTopActivitiesLocked();// Back to ActivityStackSupervisor}}Copy the code

This step first places the ActivityRecord (r) corresponding to the activity to be launched at the top of its TaskRecord, and then sets its Task as the foreground stack. AppWindowToken is then added to the Activity, which WMS uses to mark the window corresponding to the Activity on the AMS side. The last call resumeTopActivitiesLocked activity further processing stack.

boolean resumeTopActivitiesLocked(a) {
        return resumeTopActivitiesLocked(null.null.null);
    }

    boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target, Bundle targetOptions) {
        if (targetStack == null) {
            targetStack = getFocusedStack();
        }
        boolean result = false;
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = mStacks.get(stackNdx);
            if (isFrontStack(stack)) {
                if (stack == targetStack) {
                    result = stack.resumeTopActivityLocked(target, targetOptions);
                } else {
                    stack.resumeTopActivityLocked(null); }}}return result;
    }
Copy the code
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
	 ActivityRecord next = topRunningActivityLocked(null); ... mStackSupervisor.mStoppingActivities.remove(next); mStackSupervisor.mGoingToSleepActivities.remove(next); next.sleeping =false; mStackSupervisor.mWaitingVisibleActivities.remove(next); ...// Suspend the currently executing activity in preparation for the top of the stack to start
	boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving);
          if(mResumedActivity ! =null) {// The activity currently being executed
               pausing = true;
               startPausingLocked(userLeaving, false);/ / temporary activity}...if(prev ! =null) {}else{
		if (mNoAnimActivities.contains(next)) {// If next does not include an entry animation
		                anim = false;
		                mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
		            } else {
		                mWindowManager.prepareAppTransition(AppTransition.TRANSIT_ACTIVITY_OPEN, false);
		            }
	}
	
	ActivityStack lastStack = mStackSupervisor.getLastStack();
	if(next.app ! =null&& next.app.thread ! =null) {
		……
	}else{
		……
		mStackSupervisor.startSpecificActivityLocked(next, true.true); }}Copy the code

This set of methods is used to resume activities that started at the top of the task stack, where next is the activity that we want to execute, and it has been placed at the top of the task stack. If Next is already in the relevant sleep or stop queue, remove it and reset the sleeping state. This was all in preparation for the launch of next. The most important step here is to suspend the currently executing mResumedActivity in order to execute the activity at the top of the task stack. This is performed by startSpercificActivityLocked.

 void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
	if(app ! =null&& app.thread ! =null) {
		……
	}
	
	mService.startProcessLocked(r.processName, r.info.applicationInfo, true.0."activity", r.intent.getComponent(), false.false.true);
	
}
Copy the code

This method is used to start our specific activity. First, we get the ProcessRecord information for the activity. Since the process of the activity has not been created yet, we need to create a process for the activity.

private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr) {...// Create a new process for the service or activity using the Zygote process. After creation, call back to ActivityThread and execute its main method
    Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
            app.processName, uid, uid, gids, debugFlags, mountExternal,
            app.info.targetSdkVersion, app.info.seinfo, null); ... }Copy the code

This is done by communicating with the Zygote process over the socket. After zygote has created the process for the activity, it calls the Main method of the ActivityThread.

Let’s look at the Main method of ActivityThread

public static void main(String[] args) {
        ……
    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    AsyncTask.init();
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}
Copy the code

Once the process starts, you need to create an ActivityThread object to give to and call its Attach method. Much of the initial work is done in the ATTACH method. You can see from the main method that the main thread of the process is the UI thread.

private void attach(boolean system) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if(! System) {... IActivityManager mgr = ActivityManagerNative.getDefault();try {
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            // Ignore}}else{... }}Copy the code

The ATTACH method calls AMS’s attachApplicaton, where mAppThread is our ApplicationThread object, a binder service that is generated when the ActivityThread object is created and passed to AMS. This allows AMS to use its proxy, Binder, to communicate with applications. For example, the Binder object notifies the application of many of the activity’s life cycle events.

 @Override
public final void attachApplication(IApplicationThread thread) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid);// Further callBinder.restoreCallingIdentity(origId); }}Copy the code

private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) { app.makeActive(thread, mProcessStats); ... thread.bindApplication(processName, appInfo, providers, app.instrumentationClass, profileFile, profileFd, profileAutoStop, app.instrumentationArguments, app.instrumentationWatcher, app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace, isRestrictedBackupMode || ! normalMode, app.persistent,newConfiguration(mConfiguration), app.compat, getCommonServicesLocked(), mCoreSettingsObserver.getCoreSettingsLocked()); ...if (normalMode) {
	            try {
	                if (mStackSupervisor.attachApplicationLocked(app, mHeadless)) {
	                    didSomething = true; }}catch (Exception e) {
	                badApp = true; }}// Find any services that should be running in this process...
        if(! badApp) {try {
                didSomething |= mServices.attachApplicationLocked(app, processName);
            } catch (Exception e) {
                badApp = true; }}... }Copy the code

Here AMS does some initialization and then calls bindApplication on the application side. At this point, the Application creates an Application object for the Application, and AMS calls mStackSupervisor and attachApplicationLocked of mServices, respectively, to start acitivty or service waiting for startup. We’ll continue with the analysis

public final void bindApplication(String processName,
                ApplicationInfo appInfo, List<ProviderInfo> providers,
                ComponentName instrumentationName, String profileFile,
                ParcelFileDescriptor profileFd, boolean autoStopProfiler,
                Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
                IUiAutomationConnection instrumentationUiConnection, int debugMode,
                boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
                Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
                Bundle coreSettings) {

    ……
    sendMessage(H.BIND_APPLICATION, data);
  }
Copy the code

This will send the BIND_APPLICATION message through the H object which is actually a handler, which will call the handleBindApplication method to process the message.

private void handleBindApplication(AppBindData data) {
	……
	 Application app = data.info.makeApplication(data.restrictedBackupMode, null); mInitialApplication = app; ... mInstrumentation.callApplicationOnCreate(app); ... }Copy the code

The handleBindApplication on the application side creates an application object for the application and calls the onCreate callback.

 boolean attachApplicationLocked(ProcessRecord app, boolean headless) throws Exception {
        boolean didSomething = false;
        final String processName = app.processName;
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = mStacks.get(stackNdx);
            if(! isFrontStack(stack)) {continue;
            }
            ActivityRecord hr = stack.topRunningActivityLocked(null);
            if(hr ! =null) {
                if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                        && processName.equals(hr.processName)) {
                    try {
                        if (headless) {

                        } else if (realStartActivityLocked(hr, app, true.true)) {
                            didSomething = true; }}catch (Exception e) {
                        Slog.w(TAG, "Exception in new application when starting activity "
                              + hr.intent.getComponent().flattenToShortString(), e);
                        throwe; }}}}if(! didSomething) { ensureActivitiesVisibleLocked(null.0);
        }
        return didSomething;
    }
Copy the code

After the AMS callback completes the application initialization on the application side, attachApplicationLocked is further called to continue the activity. In this method, you first fetch the foreground ActivityStack, then locate the activity at the top of the task stack, and finally use realStartActivityLocked to actually start the activity hr represents.

frameworks/base/services/java/com/android/server/am/ActivityStackSupervisor.java
final boolean realStartActivityLocked(ActivityRecord r,
            ProcessRecord app, boolean andResume, boolean checkConfig)
            throws RemoteException {
	……
	mWindowManager.setAppVisibility(r.appToken, true); ... r.app = app; app.waitingToKill =null; r.launchCount++; r.lastLaunchTime = SystemClock.uptimeMillis(); ... app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
        System.identityHashCode(r), r.info,
        newConfiguration(mService.mConfiguration), r.compat, app.repProcState, r.icicle, results, newIntents, ! andResume, mService.isNextTransitionForward(), profileFile, profileFd, profileAutoStop); ... }Copy the code

At this point, WMS sets the app to visible, in this case with r.appToken as the key. This appToken is created when we create an ActivityRecord for our activity. It acts as a Binder to mark our activities on the WMS side and also to communicate with the WMS. App. Thread is our ApplicationThread, which is the binder server of the application after the process is created. It is mainly used by AMS to communicate with the application.

public final void scheduleLaunchActivity(Intent intent,            IBinder token, int ident,ActivityInfo info, 
    Configuration curConfig, CompatibilityInfo compatInfo,
    int procState, Bundle state, List<ResultInfo> pendingResults,
    List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,String profileName, ParcelFileDescriptor profileFd,
    boolean autoStopProfiler) {

    updateProcessState(procState, false);

    ActivityClientRecord r = new ActivityClientRecord();

    r.token = token;//token? This token is actually the appToken for ActivityRecord and represents the Activity to be started
    r.ident = ident;
    r.intent = intent;
    r.activityInfo = info;
    r.compatInfo = compatInfo;
    r.state = state;

    r.pendingResults = pendingResults;
    r.pendingIntents = pendingNewIntents;

    r.startsNotResumed = notResumed;
    r.isForward = isForward;

    r.profileFile = profileName;
    r.profileFd = profileFd;
    r.autoStopProfiler = autoStopProfiler;

    updatePendingConfiguration(curConfig);

    sendMessage(H.LAUNCH_ACTIVITY, r);
}
Copy the code

An ActivityClientRecord object is constructed in the scheduleLaunchActivity, H_LAUNCH_ACTIVITY is sent, and handleLaunchActivity is called.

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
	Activity a = performLaunchActivity(r, customIntent);
    if(a ! =null) {
        r.createdConfig = new Configuration(mConfiguration);
        Bundle oldState = r.state;
        // Proceed with the resume activity process
        handleResumeActivity(r.token, false, r.isForward, ! r.activity.mFinished && ! r.startsNotResumed); ... }... }Copy the code

So here we start loading the activity, so we start by calling performLaunchActivity, which calls callbacks like onCreate and onStart, and the handleResumeActivity displays the activity, And calls the onResume callback.

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
	……
	java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
	            // Create an instance of Activiactivity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); ...if(activity ! =null) {
        // Creating a context for the activity is actually contextImpl
        Context appContext = createBaseContextForActivity(r, activity);
        CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
        Configuration config = new Configuration(mCompatConfiguration);
        // Call attach to initialize the activity
        
        activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config);

        if(customIntent ! =null) {
            activity.mIntent = customIntent;
        }
        r.lastNonConfigurationInstances = null;
        activity.mStartedActivity = false;
        int theme = r.activityInfo.getThemeResource();
        if(theme ! =0) {
            activity.setTheme(theme);
        }

        activity.mCalled = false;
        / / callback 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;
        r.stopped = true;
        if(! r.activity.mFinished) { activity.performStart();/ / onStart callback
            r.stopped = false;
        }
        ……
    }
    r.paused = true;

    mActivities.put(r.token, r);
}
Copy the code

This method creates the Activity object and creates a context for it, actually a contextImpl, and sets the context into the activity by attaching it. Also set the activity to window, that is, PhoneWindow. Then call back onCreate, onStart, etc.

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
            boolean reallyResume) { ActivityClientRecord r = performResumeActivity(token, clearHide); ...if (r.window == null && !a.mFinished && willBeVisible) {
        r.window = r.activity.getWindow();
        View decor = r.window.getDecorView();Get decorView / /
        decor.setVisibility(View.INVISIBLE);
        ViewManager wm = a.getWindowManager();// Get WindowManager to WindowManagerImpl
        WindowManager.LayoutParams l = r.window.getAttributes();
        a.mDecor = decor;
        l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;//window type is used to measure the Z sequence
        l.softInputMode |= forwardBit;
        if (a.mVisibleFromClient) {
            a.mWindowAdded = true;
            wm.addView(decor, l);// The window will be added to the WMS}}... }Copy the code

At this point you actually add the activity’s corresponding window to the WMS, and the activity is displayed on the desktop.