Analyze the startup process of Android Activity
Regarding the startup process of Android Activity, I have read the source code in the Android source code for a long time. The following is the Activity startup process I have compiled and shared with you:
Activity is one of the four major components of Android and is also the most basic component, responsible for all functions of interacting with users. The startup process of Activity is not a mysterious thing. Next, let’s simply analyze the startup process of Activity from the perspective of source code.
The root activity generally refers to the MainActivity in our project, which represents an Android application and is usually started in a new process. In the Android system, all Activity components are saved on the stack. We start a new Activity component and are located on top of the previous Activity. So what is the process for us to open an App from the desktop (Launcher), as shown below:
(1) Launcher sends a request to the ActivityManagerService to start MainActivity;
(2) ActivityManagerService first saves the relevant information of MainActivity, and then sends a request to Launcher to make it enter the aborted state;
(3) After the Launcher receives the aborted state, it will want the ActivityManagerService to send a request that has entered the aborted state, so that the ActivityManagerService can continue to execute the operation of starting MainActivity;
(4) ActivityManagerService checks the process used to run MainActivity. If it does not exist, a new process will be started;
(5) After the new application process is started, a request for startup completion will be sent to the ActivityManagerService to facilitate the ActivityManagerService to continue to execute the operation of starting MainActivity;
(6) ActivityManagerService sends MainActivity-related information saved in step (2) to the newly created process, so that the process can start the MainActivity component.
boolean startActivitySafely(Intent intent, Object tag) { (Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivity(intent); return true; } catch (ActivityNotFoundException e) {} }
When we click on the application icon on Launcher, the startActivitySafely method is called. The activity information that needs to be started is stored in the intent, including action, category, etc. So how does Launcher obtain this information in the intent? First, when the system starts, it will start a management service called PackageManagerService, and install the application in the system through it. In this process, PackageManagerService will parse the application's configuration file to obtain component information in the program (including Activity, Service, Broadcast, etc.), and then PackageManagerService will query all activities with action "" and category ", then create a shortcut icon for each application and associate the program information with it. In the above code, the startup flag of the Activity is set to "Intent.FLAG_ACTIVITY_NEW_TASK", so that it can be started in a new task.
@Override public void startActivity(Intent intent, @Nullable Bundle options) { if (options != null) { startActivityForResult(intent, -1, options); } else { startActivityForResult(intent, -1); } }
Call startActivityForResult, and the second parameter (requestCode) is -1, which means that the result does not need to be passed back when the Activity is closed.
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) { if (mParent == null) { //The mParent of general activities is null ar = (this, (), mToken, this,intent, requestCode, options); if (ar != null) { //Send the result, that is, onActivityResult will be called (mToken, mEmbeddedID, requestCode, (), ()); } if (requestCode >= 0) { mStartedActivity = true; } final View decor = mWindow != null ? () : null; if (decor != null) { (); } } else { //In the Activity inside the ActivityGroup, the internal processing logic is similar to the above if (options != null) { (this, intent, requestCode, options); } else { (this, intent, requestCode); } } if (options != null && !isTopOfTask()) { (this, options); } }
It is not difficult to find that in the end, it is actually called to start the Activity. The mInstrumentation type is Instrumentation, which is used to monitor the interaction between the program and the system. mInstrumentation performs the startup operation of the Activity on behalf of the person, so that it can monitor this interactive process.
mMainThread is type ActivityThread, which is used to describe an application process. Every time the system starts a program, it will load an instance of ActivityThread in it, and save the instance in the Activity member variable mMainThread, and () is used to obtain a local Binder object with type ApplicationThread inside it. The type of mToken is IBinder, which is a Binder proxy object. I only think of a local Binder object with type ActivityRecord in the ActivityManagerService. Each startup activity has a corresponding ActivityRecord object in the ActivityManagerService, which is used to maintain the operating status and information of the Activity.
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { IApplicationThread whoThread = (IApplicationThread) contextThread; if (mActivityMonitors != null) { synchronized (mSync) { final int N = (); for (int i=0; i<N; i++) { //First search to see if this activity exists final ActivityMonitor am = (i); if ((who, null, intent)) { ++; if (()) { return requestCode >= 0 ? () : null; } break; } } } } try { (); (); int result = ().startActivity(whoThread, (), intent, (()),token, target != null ? : null, requestCode, 0, null, options); //This is where the activity is really opened, and its core function is completed in whoThread. checkStartActivityResult(result, intent); // Handle various exceptions, such as ActivityNotFound } catch (RemoteException e) { } return null; }
As shown in the above code, you can see that by obtaining a proxy object of the ActivityManagerService through (), then calling its startActivity method to notify the ActivityManagerService to start the Activity.
There are a series of processes in the middle. Following the source code, it is not difficult to find that in the end, it is called ApplicationThread's scheduleLaunchActivity to start the Activity.
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state, PersistableBundle persistentState, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) { updateProcessState(procState, false); ActivityClientRecord r = new ActivityClientRecord(); = token; = ident; = intent; = referrer; = voiceInteractor; = info; = compatInfo; = state; = persistentState; = pendingResults; = pendingNewIntents; = notResumed; = isForward; = profilerInfo; updatePendingConfiguration(curConfig); sendMessage(H.LAUNCH_ACTIVITY, r); }
The main thing that the above code does is to construct an ActivityClientRecord, and then call sendMessage to send a message. In the corresponding process of the application, each Activity component is described using an ActivityClientRecord object, which is stored in the member variable mActivities of the ActivityThread class. So how does Handler handle this message?
switch () { // Message type case LAUNCH_ACTIVITY: { (Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); final ActivityClientRecord r = (ActivityClientRecord) ; = getPackageInfoNoCheck( , ); handleLaunchActivity(r, null); // Process messages (Trace.TRACE_TAG_ACTIVITY_MANAGER); } break; case RELAUNCH_ACTIVITY: { (Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart"); ActivityClientRecord r = (ActivityClientRecord); handleRelaunchActivity(r); (Trace.TRACE_TAG_ACTIVITY_MANAGER); } break; case PAUSE_ACTIVITY: (Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause"); handlePauseActivity((IBinder), false, (msg.arg1&1) != 0, msg.arg2, (msg.arg1&2) != 0); maybeSnapshot(); (Trace.TRACE_TAG_ACTIVITY_MANAGER); break; ... ... }
First convert the obj in msg into an ActivityClientRecord object, and then call to get a LoaderApk object and save it in the member variable packageInfo of the ActivityClientRecord object. The Loader object is used to describe a loaded APK file. Finally, call handleLaunchActivity to start the Activity component.
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) { unscheduleGcIdler(); mSomeActivitiesChanged = true; if ( != null) { (); (); } handleConfigurationChanged(null, null); if (localLOGV) ( TAG, "Handling launch of " + r); (); Activity a = performLaunchActivity(r, customIntent); // performLaunchActivity truly completes the call of activity, Activity is instantiated, onCreate is called if (a != null) { = new Configuration(mConfiguration); Bundle oldState = ; handleResumeActivity(, false, , // Call the Resume of the Activity instance (visible on the user interface) ! && !); if (! && ) { try { = false; (); // When finishing, adjust onPause first if (()) { = oldState; } if (!) { throw new SuperNotCalledException( "Activity " + ().toShortString() + " did not call through to ()"); } } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { if (!(, e)) { throw new RuntimeException( "Unable to pause activity " + ().toShortString() + ": " + (), e); } } = true; } } else { try { () // The same principle as finishActivity .finishActivity(, Activity.RESULT_CANCELED, null, false); } catch (RemoteException ex) { } } }
At this point, it will be very clear. After holding my breath, did you suddenly relax?~ Let’s take a look at what performLaunchActivity does~~ The performLaunchActivity function loads the derived class of the user-defined Activity and executes its onCreate function, which will return this Activity object.
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ActivityInfo aInfo = ; if ( == null) { = getPackageInfo(, , Context.CONTEXT_INCLUDE_CODE); } //Fetch the startup parameters of the target activity from the intent (package name, class name, etc.) ComponentName component = (); if (component == null) { component = ( ()); (component); } if ( != null) { component = new ComponentName(, ); } Activity activity = null; try { cl = (); // Load the Activity class file into memory activity = ( // Create an Activity instance cl, (), ); (()); (cl); (); if ( != null) { (cl); } } catch (Exception e) { if (!(activity, e)) { throw new RuntimeException( "Unable to instantiate activity " + component + ": " + (), e); } } try { Application app = (false, mInstrumentation); if (localLOGV) (TAG, "Performing launch of " + r); if (localLOGV) ( TAG, r + ": app=" + app + ", appName=" + () + ", pkg=" + () + ", comp=" + ().toShortString() + ", dir=" + ()); if (activity != null) { Context appContext = createBaseContextForActivity(r, activity); // Initialize the Context object as the context of the Activity CharSequence title = (()); Configuration config = new Configuration(mCompatConfiguration); if (DEBUG_CONFIGURATION) (TAG, "Launching activity " + + " with config " + config); (appContext, this, getInstrumentation(), , , app, , , title, , , , config, , ); if (customIntent != null) { = customIntent; } = null; = false; int theme = (); if (theme != 0) { (theme); } = false; if (()) { //The following is to call the onCreate method of the activity (activity, , ); } else { (activity, ); } // At this point, the Activity startup process ends, and its life cycle is managed by ApplicationThread if (!) { throw new SuperNotCalledException( "Activity " + ().toShortString() + " did not call through to ()"); } = activity; = true; if (!) { (); = false; } if (!) { if (()) { if ( != null || != null) { (activity, , ); } } else if ( != null) { (activity, ); } } if (!) { = false; if (()) { (activity, , ); } else { (activity, ); } if (!) { throw new SuperNotCalledException( "Activity " + ().toShortString() + " did not call through to ()"); } } } = true; (, r); // Save the ActivityRecord object in the mActivities of ActivityThread } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { if (!(activity, e)) { throw new RuntimeException( "Unable to start activity " + component + ": " + (), e); } } return activity; }
The token in ActivityRecord is a Binder proxy object. Like the ActivityClientRecord object, it is used to describe the initiated Activity components, but the former is used in the ActivityManagerService, and the latter is used in the application process.
At this point, the startup process of the Activity has been analyzed. The startup process of MainActivity can actually be considered as the startup process of the application.
The startup process of the sub-Activity and the startup process of the root Activity are also similar, the process is as follows:
(1) MainActivity sends an automatic ChildActivity request to the ActivityManagerService;
(2) ActivityManagerService first saves the ChildActivity information, and then sends an aborted request to MainActivity;
(3) MainActivity receives a request and enters an aborted state, telling ActivityManagerService to facilitate ActivityManagerService to continue to execute the operation of starting ChildActivity
(4) ActivityManagerService checks whether the process running by ChildActivity exists. If it exists, it will send ChildActivity information to it for startup.
In terms of source code, the principles are similar, and they are slightly simpler than those of MainActivity. I will not explain them in detail here. You can read the source code according to the previous steps.
Thank you for reading, I hope it can help you. Thank you for your support for this site!