### Why learn source code?

This is the third blog in a series of source code analysis posts, where I explain why you should do source code analysis for the Activity startup process.

Learning source code helps us learn some black technology, such as plug-in learning from time we need to learn Hook mechanism, but learning Hook mechanism when we need to master the Activity start process, message mechanism and so on.

### Analyze the startup process

When you call startActivity(Intent) to start an Activity, the Activity’s startActivityForResult method is called:

public void startActivityForResult(Intent intent, int requestCode, Bundle options) { if (mParent == null) { options = transferSpringboardActivityOptions(options); / / call the Instrumentation class execStartActivity method Instrumentation. ActivityResult ar = mInstrumentation. ExecStartActivity (this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); if (ar ! = null) {// If a result is required, Also need to send a message mMainThread. SendActivityResult (mToken, mEmbeddedID requestCode, ar. GetResultCode (), ar. GetResultData ()); } if (requestCode >= 0) { mStartedActivity = true; } cancelInputsAndStartExitTransition(options); } else { if (options ! = null) { mParent.startActivityFromChild(this, intent, requestCode, options); } else { mParent.startActivityFromChild(this, intent, requestCode); }}}Copy the code

This method actually calls the execStartActivity method of the Instrumentation class, which is related to the initialization of the Activity. The execStartActivity method for the Instrumentation class is as follows:

public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent Intent, int requestCode, Bundle options) {//IApplicationThread is an AIDL interface. The implementation class is an internal class within ActivityThread that allows ApplicationThread to communicate between processes and identify a process. IApplicationThread whoThread = (IApplicationThread) contextThread; / /... Omit some code try {intent. MigrateExtraStreamToClipData (); intent.prepareToLeaveProcess(who); //ActivityManagerNative is one half of an AIDL interface: Stub (stubs) int result = ActivityManagerNative. GetDefault () startActivity (whoThread, who getBasePackageName (), the 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

ActivityManagerNative is one half of an AIDL interface: Stub, which communicates with AMS. ActivityManagerNative also has an internal class ActivityManagerProxy. As shown below:

So at this point interprocess communication has begun, notifying AMS for subsequent processing. Analysis has been made before, through ActivityManagerNative getDefault (found) is essentially ActivityManagerNative communicate with AMS of an AIDL interface references:

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() { protected IActivityManager create() { IBinder b = ServiceManager.getService("activity"); IActivityManager am = asInterface(b); return am; }};Copy the code

It is ActivityManagerProxy, an inner class of ActivityManagerNative, that implements this interface:

class ActivityManagerProxy implements IActivityManager{
}
Copy the code

The ActivityManagerProxy writes data to the AMS IBinder. For example, when an Activity is started for interprocess communication, we put the data into a serializable Parcel object and write it to the IBinder driver.

Here is an implementation of startActivity in ActivityManagerProxy:

// Caller represents an application. For example, if you start an Activity on your desktop, caller represents a description of a Launcher. public int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); Transact (START_ACTIVITY_TRANSACTION, data, reply, 0); // Call transact to write data to the IBinder driver. // If there is an exception reply.readexception (); int result = reply.readInt(); // Recycle data to prevent memory leaks reply.recycle(); data.recycle(); return result; }Copy the code

The Binder driver calls back ActivityManagerNative’s (Stub) onTransact method, which is long and includes many other cases and extracts only a portion of the core code. According to our Transact code (START_ACTIVITY_TRANSACTION), we can filter out the following code:

@Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { case START_ACTIVITY_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder b = data.readStrongBinder(); / / convert IBinder interface to AIDL reference IApplicationThread app = ApplicationThreadNative. AsInterface (b); String callingPackage = data.readString(); // Omit some code to get parameters //ActivityManagerNative's real implementation class is AMS, Int result = startActivity(app, callingPackage, Intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, options); reply.writeNoException(); reply.writeInt(result); return true; }}Copy the code

The real implementation class of ActivityManagerNative is ActivityManagerService (AMS), which plays an important role in the creation, propagation, and lifecycle management of the four components. Here is the startActivity method that calls AMS:

@Override public final int startActivity(... {return startActivityAsUser(... Omit some arguments); }Copy the code

AMS’s startActivity calls the startActivityAsUser method:

@Override public final int startActivityAsUser(... Omit some parameters) {/ / information to start userId = mUserController handleIncomingUser (Binder. The getCallingPid (), Binder, getCallingUid (), userId, false, ALLOW_FULL_ONLY, "startActivity", null); / / here will call ActivityStarter startActivityMayWait method: return mActivityStarter. StartActivityMayWait (... Omit some arguments); }Copy the code

ActivityStackSupervisor is the stack management class of APP, which manages the stack problems of the four components. ActivityStarter is each stack of managed tasks. Task management, a Task may have multiple stacks, not to mention the current use, stopped stack, historical stack. ActivityStackSupervisor records a number of activities:

final ArrayList<ActivityRecord> mStoppingActivities = new ArrayList<>();
final ArrayList<ActivityRecord> mFinishingActivities = new ArrayList<>();
Copy the code

The startActivityMayWait method of ActivityStarter is called again:

final int startActivityMayWait(... Omit some parameters) {mSupervisor. MActivityMetricsLogger. NotifyActivityLaunching (); boolean componentSpecified = intent.getComponent() ! = null; Intent = new Intent(Intent); // The PMS (PackageManagerService) validates the Intent to see if the Activity is defined in the manifest. In the future we learn Hook mechanism from listing registration start the Activity when it is the key to ResolveInfo rInfo = mSupervisor. ResolveIntent (intent, resolvedType, userId); / / / / omit some code information extraction from the target Activity ActivityInfo aInfo = mSupervisor. ResolveActivity (intent, rInfo startFlags, profilerInfo); Synchronized (mService) {bind (mService) {bind (mService); Uid final int realCallingPid = Binder.getCallingPid(); final int realCallingUid = Binder.getCallingUid(); Final ActivityRecord[] outRecord = new ActivityRecord[1]; // Continue to call startActivityLocked: int res = startActivityLocked(... Omit some arguments); // omit some code}}Copy the code

The most important line in the above function is the following:

ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
Copy the code

The resolveIntent of ActivityStackSupervisor is called. The following method is called:

ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags) {
    try {
        return AppGlobals.getPackageManager().resolveIntent(intent, resolvedType,
                PackageManager.MATCH_DEFAULT_ONLY | flags
                | ActivityManagerService.STOCK_PM_FLAGS, userId);
    } catch (RemoteException e) {
    }
    return null;
}
Copy the code

The resolveIntent method is used to detect the Activity when it is launched. Here the PMS looks for manifest files to see if there is a registered Activity, especially if it is implicitly intended to start the Activity.

Let’s look at the definition of the getPackageManager method in AppGlobals, which returns the IPackageManager, which is an AIDL interface.

public static IPackageManager getPackageManager() {
    return ActivityThread.getPackageManager();
}
Copy the code

ActivityThread getPackageManager getPackageManager getPackageManager getPackageManager getPackageManager getPackageManager getPackageManager getPackageManager getPackageManager getPackageManager getPackageManager getPackageManager

public static IPackageManager getPackageManager() {
    IBinder b = ServiceManager.getService("package");
    sPackageManager = IPackageManager.Stub.asInterface(b);
    return sPackageManager;
}
Copy the code

The whole process is to get the PackageManager AIDL reference and then call its resolveIntent method. Who is the IPackageManager implementation class? Not PackageManager, because it’s just a separate class:

public abstract class PackageManager {
}
Copy the code

The real implementation class of IPackageManager is PackageManagerService (PMS), which is a system service:

public class PackageManagerService extends IPackageManager.Stub {
}
Copy the code

The resolveIntent method in PackageManagerService is implemented as follows:

@Override public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, Int userId) {try {// omit some code // find if the Activity represented by the Intent exists, The returned result may have more than one final List < ResolveInfo > query = queryIntentActivitiesInternal (intent, resolvedType, flags, userId); // Select the best (most conditional) Activity final ResolveInfo bestChoice = chooseBestActivity(Intent, resolvedType, flags, query, userId); return bestChoice; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); }}Copy the code

The PackageManagerService starts when the Android system starts and scans all installed application manifest files and saves them to memory. Here call queryIntentActivitiesInternal method to find accord with Intent filter conditions the Activity list. The implementation of this method is as follows:

private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, Intentcomponentname = intent.getComponent(); intentName = intent.getComponent(); // omit some code if (comp! = null) { final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); Final ActivityInfo ai = getActivityInfo(comp, flags, userId); if (ai ! = null) { final ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; // If the Activity can be found, it will be added to the list, and finally return list.add(ri); } return list; } // return result; }Copy the code

In the PackageManagerService, the resolveIntent method finally takes into account the priority of the Intent, which is to call chooseBestActivity and choose the best Activity:

  1. If there is only one query result, return 0; Otherwise, priorities need to be addressed.
  2. Otherwise, if we start only one Activity, it depends on the priority. (So the manifest file has the priority configuration).

Let’s look at the chooseBestActivity method for PMS a little bit:

private ResolveInfo chooseBestActivity(Intent intent, String resolvedType, int flags, List<ResolveInfo> query, int userId) { if (query ! = null) { final int N = query.size(); // If there is only one query result, return 0; If (N == 1) {return query.get(0); } else if (N > 1) { ResolveInfo r0 = query.get(0); ResolveInfo r1 = query.get(1); // If we start only one Activity, it depends on the priority. If (r0.priority! = r1.priority || r0.preferredOrder ! = r1.preferredOrder || r0.isDefault ! = r1.isDefault) { return query.get(0); } // omit some code}} return null; }Copy the code

That is, the system does a verification through the PMS to see if the Activity exists in the manifest file and returns the best one.

The PMS is primarily used to manage package information, which is stored in manifest files. For example, he goes back to the /data/data directory to scan. For example, in PMS construction you’ll find this code:

public PackageManagerService(Context context, Installer installer, boolean factoryTest, Boolean onlyCore) {synchronized (mPackages) {/ / need to scan the File dataDir = Environment. GetDataDirectory (); MAppInstallDir = new File(dataDir, "app"); //data/data/app: mAppInstallDir = new File(dataDir, "app"); mAppLib32InstallDir = new File(dataDir, "app-lib"); mEphemeralInstallDir = new File(dataDir, "app-ephemeral"); mAsecInternalPath = new File(dataDir, "app-asec").getPath(); MDrmAppPrivateInstallDir = new File(dataDir, "app-private"); //data/data/app-private: mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); if (! ScanDirLI mOnlyCore) {/ / call to scan scanDirLI (mEphemeralInstallDir, mDefParseFlags | PackageParser. PARSE_IS_EPHEMERAL, scanFlags | SCAN_REQUIRE_KNOWN, 0); }}}Copy the code

The scanDirLI method for PMS is as follows:

private void scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime) { final File[] files = dir.listFiles(); For (the File File: files) {/ / scanning, judge whether the APK final Boolean isPackage = (isApkFile (File) | | File. The isDirectory () &&! PackageInstallerService.isStageName(file.getName()); if (! isPackage) { continue; } try {// Then parse the manifest file of APK, The four components of information, such as permissions parsing out scanPackageTracedLI (file, parseFlags | PackageParser. PARSE_MUST_BE_APK, scanFlags, currentTime, null); } catch (PackageManagerException e) { } } }Copy the code

At startup, SystemServer will start the PMS, which will call the PMS main method to register itself with the ServiceManager: The ServiceManager is our service console, save all services “contact information”.

public static PackageManagerService main(... Omit some parameters) {PackageManagerServiceCompilerMapping. CheckProperties (); //new PMS, PackageManagerService m = new PackageManagerService(Context, Installer, factoryTest, onlyCore); m.enableSystemUserPackages(); / / register them into ServiceManager ServiceManager. The addService (" package ", m); return m; }Copy the code

If we go back to the startActivityMayWait method on ActivityStarter, we’ll find that startActivityLocked is called:

// Continue to call startActivityLocked: int res = startActivityLocked(... Omit some arguments);Copy the code

Here is the startActivityLocked method for ActivityStarter:

final int startActivityLocked(... Int err = activityManager.start_success; int err = activityManager.start_success; ProcessRecord callerApp = null; ProcessRecord callerApp = null; if (caller ! = null) { callerApp = mService.getRecordForAppLocked(caller); if (callerApp ! = null) { callingPid = callerApp.pid; callingUid = callerApp.info.uid; } else { err = ActivityManager.START_PERMISSION_DENIED; If (err == activityManager.start_success && Intent.getComponent () == null) {// Error: Error: error = activityManager.start_intent_not_resolved; } if (err == activityManager.start_success && aInfo == null) {// Error: Err = ActivityManager.start_class_not_found; err = activityManager.start_class_not_found; err = ActivityManager. If (build.permissions_review_required && aInfo! = null) { if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired( aInfo.packageName, UserId)) {}} // If there is no error message, an ActivityRecord is created to record various information about the Activity, such as which Activity to jump to when the result is returned. The process in which the Activity is started (for example, when you start an Activity without a process, you need to incubate a process if the process in the ActivityRecord is not started. ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage, Intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho, requestCode, componentSpecified, voiceSession ! = null, mSupervisor, container, options, sourceRecord); / / try to omit some code {mService. MWindowManager. DeferSurfaceLayout (); // Start err = startActivityUnchecked(... Omit some arguments); } finally { mService.mWindowManager.continueSurfaceLayout(); } postStartActivityUncheckedProcessing(r, err, stack.mStackId, mSourceRecord, mTargetStack); return err; }Copy the code

Call startActivityUnchecked to start the Activity without checking for anything else: This method handles the mode in which the Activity is started, such as whether a new stack of tasks needs to be created, whether existing Activity instances need to be reused in the stack, and so on. And the startup mode should match the flag, such as NEW_TASK. And the startup mode configuration in the manifest file takes precedence over flags.

private int startActivityUnchecked(... Omit some arguments) {// omit some code if (mReusedActivity! = null) { if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) ! = 0 | | mLaunchSingleInstance | | mLaunchSingleTask) {/ / query the Activity at the top of the final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked( mStartActivity, mLaunchFlags); if (top ! = null) { if (top.frontOfTask) { top.task.setIntent(mStartActivity); } ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task); top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage); }}} / / omit some code if (mStartActivity. PackageName = = null) {if (mStartActivity resultTo! = null && mStartActivity.resultTo.task.stack ! = null) { mStartActivity.resultTo.task.stack.sendActivityResultLocked( -1, mStartActivity.resultTo, mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED, null); } ActivityOptions.abort(mOptions); return START_CLASS_NOT_FOUND; } / / / / to omit some code calls the target Activity stack mTargetStack startActivityLocked method. The startActivityLocked (mStartActivity newTask, mKeepCurTransition, mOptions); // omit some code}Copy the code

####Activity Stack (Task) The Task stack houses ActivityRecord, which is a lifO data structure. For example, to start an Activity with a Launcher, you need to create a new task stack. When calling system applications, such as cameras, NEW_TASK is not specified, it will be launched in the task stack of its own APP. A special one is the singleton pattern, which creates a new task stack. Stacks are also sequential, so what we see is the stack being displayed, and when we exit the stack, the next stack will be displayed.

At the end of the above method, the startActivityLocked method of the target Activity stack is called:

/ / call the goal of the Activity stack mTargetStack startActivityLocked method. The startActivityLocked (mStartActivity newTask, mKeepCurTransition, mOptions);Copy the code
  1. ActivityStackSupervisor: A class that manages the stack of an APP, such as which task stack to display, which Activity stack to select, and flags for the Intent.
  2. ActivityStack: A stack of activities managed by ActivityStackSupervisor.

Let’s analyze ActivityStack’s startActivityLocked:

final void startActivityLocked(ActivityRecord r, boolean newTask, boolean keepCurTransition, ActivityOptions options) {// Find the task stack for the Activity to start, because each Activity must be assigned a task stack. Final int taskId = rtask.taskid; // mLaunchTaskBehind tasks get placed at the back of the task stack. if (! R.m LaunchTaskBehind && (taskForIdLocked (taskId = = null) | | newTask)) {/ / if not rear task (with some operation after certain Activity into the stack), then add the task stack to the top, That is, the focus stack // tells WindowManager to move tasks to the top, since the window display is controlled by WindowManager. And displays the Activity at the top of the task stack. insertTaskAtTop(rTask, r); mWindowManager.moveTaskToTop(taskId); } TaskRecord task = null; if (! NewTask) {// reuse the current Task if you don't need to start a newTask stack. for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { task = mTaskHistory.get(taskNdx); if (task.getTopActivity() == null) { // All activities in task are finishing. continue; } if (task == r.task) { if (! StartIt) {// If you don't need to start a new TASK stack, just add the Activity to the current top TASK and place it at the top task.addActivityToTop(r); // Add to rollback stack r.puinhistory (); } else if (task.numfullscreen > 0) {startIt = false; }} // If you need to create a new task stack, create a new one, and then add an Activity to notify WM, without looking at the code. if (task == r.task && mTaskHistory.indexOf(task) ! = (mTaskHistory.size() - 1)) { mStackSupervisor.mUserLeaving = false; } task = r.task; task.addActivityToTop(r); task.setFrontOfTask(); / /... If omitted some code (doResume) {mStackSupervisor. ResumeTopActivitiesLocked (this, r, options); }}Copy the code

Then call ActivityStackSupervisor resumeTopActivitiesLocked, continue to analyze below:

boolean resumeTopActivitiesLocked() {
    return resumeTopActivitiesLocked(null, null, null);
}
Copy the code

Based on the call chain, the following method is called:

boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target, If (isFrontStack(targetStack)) { / / call ActivityStack resumeTopActivityLocked method to find the need to suspend the Activity result = targetStack. ResumeTopActivityLocked (target, targetOptions); } // omit some code}Copy the code

ActivityStack resumeTopActivityLocked is as follows:

final boolean resumeTopActivityLocked(ActivityRecord prev) { return resumeTopActivityLocked(prev, null); } final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {/ / omit some code try {result = resumeTopActivityInnerLocked (prev, options); } finally { inResumeTopActivity = false; } return result; }Copy the code

Then call resumeTopActivityInnerLocked:

Final Boolean resumeTopActivityInnerLocked (ActivityRecord prev, Bundle options) {/ / / / to omit some code to find the first Activity has not been destroyed, Look up the array held by the member variable of the ActivityStackSupervisor. // The Activity found is ready to be paused in the future // All Activity stacks of our APP are managed by the ActivityStackSupervisor through process communication. ActivityRecord Next = topRunningActivityLocked(NULL); / / / / to omit some code needs to suspend the current Activity, removing from some state array mStackSupervisor. MStoppingActivities. Remove (next); mStackSupervisor.mGoingToSleepActivities.remove(next); next.sleeping = false; mStackSupervisor.mWaitingVisibleActivities.remove(next); // Call startPausingLocked to pause the top-most Activity, and by doing so, Resume Boolean dontWaitForPause = (Next-info.flag_reSUme_while_pausing)! = 0; boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause); if (mResumedActivity ! = null) { pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause); } / / omit some code ActivityStack lastStack = mStackSupervisor. GetLastStack (); // To start an Activity, you need to check whether the app and thread still exist. If they do not exist, you need to create a new process. // For example, start the Activity from the launcher if (next. App! = null && next.app.thread ! = null) {// No need to create a process} else {// The Activity to start has not started the corresponding process, need to start the process if (! next.hasBeenLaunched) { next.hasBeenLaunched = true; } else {/ / / / to omit some code to restart the process mStackSupervisor. StartSpecificActivityLocked (next, true, true); } return true; }Copy the code

StartPausingLocked:

final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming, Boolean dontWait) {// Find the last Activity to pause ActivityRecord prev = mResumedActivity; if (prev == null) { if (! resuming) { mStackSupervisor.resumeTopActivitiesLocked(); } return false; } // Check whether the previous Activity exists. If so, interprocess communication needs to be conducted and notify the app to stop the Activity. // The reason why each Activity needs an ActivityRecord is that each Activity needs an ActivityRecord. If (prev. App! = null && prev.app.thread ! = null) { try { EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY, prev.userId, System.identityHashCode(prev), prev.shortComponentName); mService.updateUsageStats(prev, false); // If so, interprocess communication is required, Notice that the app to stop the Activity prev. App. Thread. SchedulePauseActivity (prev. AppToken, prev. Finishing, userLeaving, prev.configChangeFlags, dontWait); } catch (Exception e) { mPausingActivity = null; mLastPausedActivity = null; mLastNoHistoryActivity = null; }} // omit some code}Copy the code

The schedulePauseActivity method initiates an interprocess communication that informs the process in which the Activity is to be stopped to suspend it. The schedulePauseActivity method is eventually called back inside that process’s ActivityThread: it essentially sends a message to the Handler and then calls it to stop the Activity.

public final void schedulePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges, boolean dontReport) { int seq = getLifecycleSeq(); // Omit some code sendMessage(finished? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY, token, (userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0), configChanges, seq); }Copy the code

This Handler will have the following case:

case PAUSE_ACTIVITY: { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause"); SomeArgs args = (SomeArgs) msg.obj; handlePauseActivity((IBinder) args.arg1, false, (args.argi1 & USER_LEAVING) ! = 0, args.argi2, (args.argi1 & DONT_REPORT) ! = 0, args.argi3); maybeSnapshot(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } break;Copy the code

HandlePauseActivity:

private void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges, boolean dontReport, int seq) { ActivityClientRecord r = mActivities.get(token); if (! checkAndUpdateLifecycleSeq(seq, r, "pauseActivity")) { return; } if (r ! = null) { if (userLeaving) { performUserLeavingActivity(r); } r.activity.mConfigChangeFlags |= configChanges; // Actually suspend Activity performPauseActivity(token, finished, R.isrehoneycomb (), "handlePauseActivity"); // Tell the activity manager we have paused. That is, stop and then feed back to the AMS activityPaused method if (! dontReport) { try { ActivityManagerNative.getDefault().activityPaused(token); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } mSomeActivitiesChanged = true; }}Copy the code

PerformPauseActivity:

final Bundle performPauseActivity(IBinder token, boolean finished, boolean saveState, String reason) { ActivityClientRecord r = mActivities.get(token); return r ! = null ? performPauseActivity(r, finished, saveState, reason) : null; }Copy the code

Then it calls performPauseActivity again:

final Bundle performPauseActivity(ActivityClientRecord r, boolean finished, Boolean saveState) {/ / omit some code try {/ / / / to omit some code to really stop the Activity mInstrumentation. CallActivityOnPause (state Richard armitage ctivity); EventLog.writeEvent(LOG_ON_PAUSE_CALLED, UserHandle.myUserId(), r.activity.getComponentName().getClassName()); if (! r.activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onPause()"); } } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { } }Copy the code

And then:

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

Finally, the onPause method of the Activity is called back

Final void performPause() {// omit some code onPause(); // omit some code}Copy the code

At the end of the handlePauseActivity:

// Tell the activity manager we have paused. That is, stop the Activity and then feed back to the AMS activityPaused method // this explains why the old onPause if (! dontReport) { try { ActivityManagerNative.getDefault().activityPaused(token); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } @Override public final void activityPaused(IBinder token) { final long origId = Binder.clearCallingIdentity(); Synchronized (this) {/ / AMS to start the stack at the top of the Activity ActivityStack stack. = ActivityRecord getStackLocked (token); if (stack ! = null) { stack.activityPausedLocked(token, false); } } Binder.restoreCallingIdentity(origId); }Copy the code

ActivityStackSupervisor and ActivityStack only manage the Activity stack and what the stack puts on it, but it’s the AMS service that really handles the four components. The previous series of operations just performed some stack management operations, and then told the APP process to suspend, and then the APP process told AMS to start the stack top Activity.

// The Activity has paused. Final void activityPausedLocked(IBinder token, boolean timeout) { final ActivityRecord r = isInStackLocked(token); if (r ! = null) { mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); If (mPausingActivity == r) {// Then call completePauseLocked, indicating that the last Activity has stopped completing, Then resume the Activity to start completePauseLocked(true); }}}Copy the code

Then call completePauseLocked, which means the last Activity has stopped and finished, and resume the Activity to start:

private void completePauseLocked(boolean resumeNext) { ActivityRecord prev = mPausingActivity; / / omit some code if (resumeNext) {/ / get the top task stack final ActivityStack topStack = mStackSupervisor. GetFocusedStack (); if (! mService.isSleepingOrShuttingDown()) { mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null); }} // omit some code}Copy the code

Then call:

boolean resumeTopActivitiesLocked() { return resumeTopActivitiesLocked(null, null, null); } boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target, Bundle targetOptions) {/ / omit some code if (isFrontStack (targetStack)) {result = targetStack. ResumeTopActivityLocked (target, targetOptions); } // omit some code}Copy the code

Will come back and call ActivityStack resumeTopActivityLocked, continue to call resumeTopActivityInnerLocked:

if (next.app ! = null && next.app.thread ! = null) {// no need to start the process} else {// Need to start the process if (! next.hasBeenLaunched) { next.hasBeenLaunched = true; } / / omit some code mStackSupervisor. StartSpecificActivityLocked (next, true, true); }Copy the code

Check whether the app process is started, for example, continuously.

Void startSpecificActivityLocked (ActivityRecord r, Boolean andResume, Boolean checkConfig) {/ / omit some code if (app! = null && app.thread ! = null) {} / / no need to start the process/process/start mService startProcessLocked (r.p rocessName, r.i show nfo. ApplicationInfo, true, 0, "activity", r.intent.getComponent(), false, false, true); }Copy the code

Call AMS’s method to start the process:

// When you see the hosting, Final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated, boolean keepIfLarge) { return startProcessLocked(... Omit some arguments); } final ProcessRecord startProcessLocked(... Omit some parameters) {long startTime = SystemClock. ElapsedRealtime (); ProcessRecord app; If (app == null) {checkTime(startTime, "startProcess: creating new process record"); app = newProcessRecordLocked(info, processName, isolated, isolatedUid); } // Start the process startProcessLocked(app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs); }Copy the code

Start the process:

private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) { long startTime = SystemClock.elapsedRealtime(); // omit some code try {if (! App. Isolated) {/ / / / to omit some code for PID, the UID gids. [0] = UserHandle getSharedAppGid (UserHandle. GetAppId (UID)); gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid)); } checkTime(startTime, "startProcess: building args"); if (mFactoryTest ! = FactoryTest.FACTORY_TEST_OFF) { if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL && mTopComponent ! = null / / get the package name && app. The processName. Equals (mTopComponent. GetPackageName ())) {uid = 0; } } int debugFlags = 0; if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) ! = 0) {/ / configuration process of Zygote debugFlags | = Zygote. DEBUG_ENABLE_DEBUGGER; // Also turn on CheckJNI for debuggable apps. It's quite // awkward to turn on otherwise. debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI; } / / omit some code / / android app. ActivityThread the entrance to a Java layer class if (entryPoint = = null) entryPoint = "android. App. ActivityThread"; / / Process to start the Process. ProcessStartResult startResult = Process. The start (entryPoint, app. ProcessName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet, app.info.dataDir, entryPointArgs); StringBuilder buf = mStringBuilder; buf.setLength(0); buf.append("Start proc "); buf.append(startResult.pid); buf.append(':'); buf.append(app.processName); buf.append('/'); Synchronized (mPidsSelfLocked) {this.mpidsselflocked. Put (startresult. pid, app); If (isActivityProcess) {// Assembles this information into a message that is processed by a Handler and then communicated to the underlying layer, Message MSG = mhandler. obtainMessage(PROC_START_TIMEOUT_MSG); msg.obj = app; mHandler.sendMessageDelayed(msg, startResult.usingWrapper ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT); } } } catch (RuntimeException e) { } }Copy the code

Finally, the ActivityThread will start. Start the main method of the ActivityThread:

Public static void main (String [] args) {/ / omit some code Environment. InitForCurrentUser (); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); // Attach the current process to the system thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } Looper.loop(); }Copy the code

As follows:

private void attach(boolean system) { sCurrentActivityThread = this; mSystemThread = system; if (! system) { final IActivityManager mgr = ActivityManagerNative.getDefault(); Try {// Call IActivityManager to bind Application via interprocess communication. The implementation class of IActivityManager is AMS. // After checking the implementation of AMS, attachApplicationLocked is called. AttachApplicationLocked ActivityStackSupervisor attachApplicationLocked MGR. attachApplication(mAppThread) } catch (RemoteException ex) {}}Copy the code

AMS’s attachApplicationLocked method has the following core code, and then calls ActivityStackSupervisor’s attachApplicationLocked:

// If the process is already started, And on top of the stack have a belongs to the process of the Activity need to start the if (normalMode) {try {the if (mStackSupervisor. AttachApplicationLocked (app)) {didSomething =  true; } } catch (Exception e) { Slog.wtf(TAG, "Exception thrown launching activities in " + app, e); badApp = true; }}Copy the code

The process is created without the need to start the Activity. The Activity is not yet associated with the process, so realStartActivityLocked:

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException { for (... Omitted) {ArrayList < ActivityStack > sports. = mActivityDisplays valueAt (displayNdx). MStacks; for (... Omitted) {ActivityRecord hr = stack. TopRunningActivityLocked (null). if (hr ! = null) { if (hr.app == null && app.uid == hr.info.applicationInfo.uid && processName.equals(hr.processName)) { try { // Continue to call realStartActivityLocked if (realStartActivityLocked(hr, app, true, true)) {didSomething = true; } } catch (RemoteException e) { } } } } } }Copy the code

RealStartActivityLocked has this statement:

app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration), r.compat, r.task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, newIntents, ! andResume, mService.isNextTransitionForward(), profilerInfo);Copy the code

Via interprocess communication, go back to the APP’s ActivityThread, send a message to H, and then launch:

case LAUNCH_ACTIVITY: {
    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

    r.packageInfo = getPackageInfoNoCheck(
            r.activityInfo.applicationInfo, r.compatInfo);
    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
} break;
Copy the code

And then:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String "reason) {/ / / / to omit some code to initialize the first window WindowManagerGlobal. The initialize (); // Then performLaunchActivity a = performLaunchActivity(r, customIntent); // omit some code}Copy the code

PerformLaunchActivity:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ActivityInfo aInfo = r.activityInfo; if (r.packageInfo == null) { r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE); } ComponentName component = r.intent.getComponent(); if (component == null) { component = r.intent.resolveActivity( mInitialApplication.getPackageManager()); r.intent.setComponent(component); } if (r.activityInfo.targetActivity ! = null) { component = new ComponentName(r.activityInfo.packageName, r.activityInfo.targetActivity); } Activity activity = null; Try {/ / to create Activity by means of reflection. Java lang. This cl = r.p. AckageInfo getClassLoader (); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); r.intent.prepareToEnterProcess(); if (r.state ! = null) { r.state.setClassLoader(cl); } } catch (Exception e) { } try { Application app = r.packageInfo.makeApplication(false, mInstrumentation); if (activity ! = null) {/ / omit some code int theme = state Richard armitage ctivityInfo. GetThemeResource (); if (theme ! = 0) {// Set the theme activity.setTheme(theme); } activity.mCalled = false; / / callback OnCreate if (r.i sPersistable ()) {mInstrumentation. CallActivityOnCreate (activity, r.s Tate, r.p ersistentState); } else { 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) {// call back onStart, onResum etc activity.performStart(); r.stopped = false; } } } catch (SuperNotCalledException e) { } catch (Exception e) { } return activity; }Copy the code

About newActivity:

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

### several related core classes

  1. ActivityManagerService (the local Stub is ActivityManagerNative) : A service in the system process that manages the life cycle of four components, etc.
  2. ActivityThread: Java layer entry functions for Android applications.
  3. PackageManagerService: scan and register the list.
  4. ActivityStackSupervisor: Manages all task stacks based on the stack model. Do YOU need to create a new task stack? And so on.
  5. ActivityStack: Task stack, which manages activities in the task stack.
  6. WindowManager: Only manages the UI rendering of the Activity on the current top stack.

The startup of the Activity is summarized as follows:

Here are some necessary notes for this diagram:

  1. This is the startup flow of MyActivity, which starts from the left and rotates counterclockwise. Application calls to Android System Service, and Android System Service calls to Application.
  2. Instrumentation is a member of the Activity and is represented here by aggregation. Instrumentation is used to record all operations of an Activity.
  3. Application and H are internal classes for ActivityThread
  4. ActivityManagerService, or AMS, is a core module of Android system services. Others are WindowsManagerService (WMS), PackageManagerService (PMS), NotificationManagerService (NMS) and so on. The main function of AMS is to manage application processes, components in application processes, and memory management.
  5. The figure above shows several distinct hierarchies of the Android system.

# # #

  1. A large number of C/S architecture, to the remote process unified management, so as to achieve multi-process, multi-window, orderly.
  2. The idea of modularity, different modules manage different things. Build packages into modules, such as a dedicated package for network access.
  3. Hierarchical thinking, you can’t manage everything in one class.

If you feel that my words are helpful to you, welcome to pay attention to my public number:

My group welcomes everyone to come in and discuss all kinds of technical and non-technical topics. If you are interested, please add my wechat huannan88 and I will take you into our group.