The preceding section describes the startup process of an android application, that is, the startup process of the default activity of the application. Generally, this default activity is started in new processes and tasks; this article will continue to analyze the source code of the process of starting a non-default activity in the application. This non-default activity is generally started in the original process and task.
Here, we are like the source code analysis in the Android Application Startup Process in the previous article, in the previous article, we used a brief introduction to the activity Startup Process of the Android Application and an example of the learning plan to analyze the process of starting a non-default activity within the application.
The process of starting a non-default activity inside the application is roughly the same as that of starting the default activity of another application in the application initiator launcher. Therefore, this section does not analyze each step in detail like the source code analysis in the startup process of the android application. We focus on the differences.
Recall the application activity used in the introduction to the activity Startup Process of the Android Application and the learning plan. It contains two activities: mainactivity and subactivity. The former is the default activity of the application, the latter is a non-default activity. Start mainactivity. You can start subactivity within the application by clicking the button on the interface.
Let's take a look at the application configuration file androidmanifest. XML to see how these two activities are configured:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="shy.luo.activity" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".SubActivity" android:label="@string/sub_activity"> <intent-filter> <action android:name="shy.luo.activity.subactivity"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity> </application> </manifest>
Here, we can clearly see that mainactivity is configured as the default activity of the application, and subactivity can use the name "Shy. luo. activity. subactivity is implicitly started. Let's take a look at src/shy/LUO/activity/mainactivity. the content of the Java file clearly shows how subactivity is started implicitly:
public class MainActivity extends Activity implements OnClickListener { ...... @Override public void onClick(View v) { if(v.equals(startButton)) { Intent intent = new Intent("shy.luo.activity.subactivity"); startActivity(intent); } } }
Here, we first create an intent named "Shy. Luo. activity. subactivity" and use this intent as the parameter to call the startactivity function to implicitly start subactivity.
With this background knowledge, let's take a look at the sequence diagram of the subactivity startup process:
Click to view the chart
Compared with the mainactivity startup process described earlier, the process of creating a new process in the middle is missing. Next, we will analyze in detail the differences between subactivity and mainactivity startup, for more information, see the source code analysis of the Android app startup process.
Step 1. activity. startactivity
This step is roughly the same as step 2 in the source code analysis of the android application startup process in the previous article, by specifying the name "Shy. luo. activity. to tell the application framework layer that it needs to start subactivity implicitly. The difference is that the input parameter intent does not have the intent. flag_activity_new_task flag, indicating that the subactivity and the mainactivity that starts it run in the same task.
Step 2. activity. startactivityforresult
This step is consistent with Step 3 in the source code analysis of the android application startup process in the previous article.
Step 3. instrumentation.exe cstartactivity
This step is consistent with Step 4 in the source code analysis of the android application startup process in the previous article.
Step 4. activitymanagerproxy. startactivity
This step is consistent with Step 5 in the source code analysis of the android application startup process in the previous article.
Step 5. activitymanagerservice. startactivity
This step is consistent with Step 6 in the source code analysis of the android application startup process in the previous article.
Step 6. activitystack. startactivitymaywait
This step is consistent with Step 7 in the source code analysis of the android application startup process in the previous article.
Step 7. activitystack. startactivitylocked
This step is consistent with Step 8 in the source code analysis of the android application startup process in the previous article.
Step 8. activitystack. startactivityuncheckedlocked
This step is different from step 9 in the previous article on source code analysis during Android app startup, mainly because the activity to be started is running in the same task as the activity to be started, let's take a closer look. This function is defined in the frameworks/base/services/Java/COM/Android/Server/AM/activitystack. Java file:
public class ActivityStack {......final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord, Uri[] grantedUriPermissions, int grantedMode, boolean onlyIfNeeded, boolean doResume) {final Intent intent = r.intent;final int callingUid = r.launchedFromUid;int launchFlags = intent.getFlags();......if (sourceRecord == null) { ......} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { ......} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE ......}if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { ......}boolean addingToTask = false;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.packageName != null) { // If the activity being launched is the same as the one currently // at the top, then we need to check if it should only be launched // once. ActivityRecord top = topRunningNonDelayedActivityLocked(notTop); if (top != null && r.resultTo == null) { if (top.realActivity.equals(r.realActivity)) { ...... } }} else { ......}boolean newTask = false;// Should this be considered a new task?if (r.resultTo == null && !addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {......} else if (sourceRecord != null) {......// An existing activity is starting this new activity, so we want// to keep the new one in the same task as the one that is starting// it.r.task = sourceRecord.task;......} else { ......}......startActivityLocked(r, newTask, doResume);return START_SUCCESS;}......}
Here, the intent flag is intent. flag_activity_new_task is not set in the configuration file andriodmanifest. in XML, subactivity does not configure the Startup Mode launchmode, so it defaults to the standard mode, that is, activityinfo. launch_multiple. Therefore, the following if statement will not be executed:
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) {...... }
Therefore, the variable addingtotask is false.
Continue to look down:
if (r.packageName != null) {// If the activity being launched is the same as the one currently// at the top, then we need to check if it should only be launched// once. ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);if (top != null && r.resultTo == null) { if (top.realActivity.equals(r.realActivity)) {...... }} }
Check whether the activity to be started is the activity at the top of the current stack. If so, you do not need to restart it in some cases. The toprunningnondelayedactivitylocked function returns the current
The activity at the top of the stack is mainactivity, and the activity to be started is subactivity. Therefore, the two are not equal, so the if statement in the stack is skipped.
Run the following command:
// Should this be considered a new task? if (r.resultTo == null && !addingToTask&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {...... } else if (sourceRecord != null) {......// An existing activity is starting this new activity, so we want// to keep the new one in the same task as the one that is starting// it.r.task = sourceRecord.task;...... } else {...... }
The identifier intent of the intent parameter. flag_activity_new_task is not set. The sourcerecord here is the activity currently executing the start activity operation. Here it is mainactivity. Therefore, it is not null, so the task to which mainactivity belongs is set to R. task, where R is subactivity. Here, we know that subactivity and mainactivity are running in the same task, and the value of the variable newtask is false.
Finally, the function is added to startactivitylocked (R, newtask, and doresume) for further processing. This function is also defined in the frameworks/base/services/Java/COM/Android/Server/AM/activitystack. Java file:
public class ActivityStack {......private final void startActivityLocked(ActivityRecord r, boolean newTask,boolean doResume) {final int NH = mHistory.size();int addPos = -1;if (!newTask) {// If starting in an existing task, find where that is...boolean startIt = true;for (int i = NH-1; i >= 0; i--) {ActivityRecord p = (ActivityRecord)mHistory.get(i);if (p.finishing) {continue;}if (p.task == r.task) {// Here it is! Now, if this is not yet visible to the// user, then just add it without starting; it will// get started when the user navigates back to it.addPos = i+1;if (!startIt) {mHistory.add(addPos, r);r.inHistory = true;r.task.numActivities++;mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,r.info.screenOrientation, r.fullscreen);if (VALIDATE_TOKENS) {mService.mWindowManager.validateAppTokens(mHistory);}return;}break;}if (p.fullscreen) {startIt = false;}}}......// Slot the activity into the history stack and proceedmHistory.add(addPos, r);r.inHistory = true;r.frontOfTask = newTask;r.task.numActivities++;......if (doResume) {resumeTopActivityLocked(null);}}......}
Newtask is set to false and doresume is set to true. When newtask is false, it indicates that the activity to be started is run in the original task. If the original task is invisible to the user, the task does not need to be executed, because even if the activity is started, the user cannot see it. It is better to save it and wait until the next task is visible to the user before it is started. Here, the original task, that is, the task running mainactivity, is currently visible to the user, so it will continue to be executed.
The subsequent execution adds the subactivity to the top of the stack through mhistroy. Add (addpos, R), and then calls resumetopactivitylocked for further operations.
Step 9. activitystack. resumetopactivitylocked
This step is consistent with Step 10 in the source code analysis of the android application startup process in the previous article.
However, when executing this function, the activity currently at the top of the stack is subactivity, and the member variable mresumedactivity of activitystack points to mainactivity.
Step 10. activitystack. startpausinglocked
This step is consistent with Step 11 in the source code analysis of the android application startup process in the previous article.
From here, activitymanagerservice notifies mainactivity to enter the paused status.
Step 11. applicationthreadproxy. schedulepauseactivity
This step is consistent with Step 12 in the source code analysis of the android application startup process in the previous article.
Step 12. applicationthread. schedulepauseactivity
This step is consistent with Step 13 in the source code analysis of the android application startup process in the previous article.
Step 13. activitythread. queueorsendmessage
This step is consistent with Step 14 in the source code analysis of the android application startup process in the previous article.
Step 14. H. handlemessage
This step is consistent with Step 15 in the source code analysis of the android application startup process in the previous article.
Step 15. activitythread. handlepauseactivity
This step is consistent with Step 16 in the source code analysis of the android application startup process in the previous article.
Step 16. activitymanagerproxy. activitypaused
This step is consistent with step 17 in the source code analysis of the android application startup process in the previous article.
Step 17. activitymanagerservice. activitypaused
This step is consistent with step 18 in the source code analysis of the android application startup process in the previous article.
Step 18. activitystack. activitypaused
This step is consistent with step 19 in the source code analysis of the android application startup process in the previous article.
Step 19. activitystack. completepauselocked
This step is consistent with step 20 in the source code analysis of the android application startup process in the previous article.
At this point, mainactivity enters the paused state, and subactivity is started as follows.
Step 20. activitystack. resumetopactivitylokced
This step is consistent with step 21 in the source code analysis of the android application startup process in the previous article.
Step 21. activitystack. startspecificactivitylocked
This step is different from step 22 in the source code analysis of the android application startup process in the previous article. Here, it will not call mservice. startprocesslocked creates a new process to start a new activity. Let's take a look at the implementation of this function, this function is defined in frameworks/base/services/Java/COM/Android/Server/AM/activitystack. in the Java file:
public class ActivityStack {......private final 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); ...... if (app != null && app.thread != null) { try { realStartActivityLocked(r, app, andResume, checkConfig); return; } catch (RemoteException e) { ...... } } ......} ......}
Because it is not the first time to start the activity of the application (mainactivity is the first activity started by the application), the following statement:
ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid);
The retrieved app is not null. In the source code analysis of the android application startup process in the previous article, we introduced androidmanifest in the activity application. in the xml configuration file, the process attribute of the application tag is not specified, so the system uses the package name by default. Here is "Shy. luo. activity. Each application has its own uid. Therefore, the UID + process combination can create a globally unique processrecord. This processrecord was created when mainactivity was started. Therefore, it is retrieved and saved in the variable app. Note that we can also go to androidmanifest. in the xml configuration file, specify the subactivity process attribute value, so that subactivity can be started in another process, but few applications will do so. We will not consider this situation.
The thread of this app was created when mainactivity was started. Therefore, the realstartactivitylocked function is called directly to start the new activity, information about the new activity is saved in parameter R.
Step 22. activitystack. realstartactivitylocked
This step is consistent with step 28 in the source code analysis of the android application startup process in the previous article.
Step 23. applicationthreadproxy. schedulelaunchactivity
This step is consistent with step 29 in the source code analysis of the android application startup process in the previous article.
Step 24. applicationthread. schedulelaunchactivity
This step is consistent with step 30 in the source code analysis of the android application startup process in the previous article.
Step 25. activitythread. queueorsendmessage
This step is consistent with step 31 in the source code analysis of the android application startup process in the previous article.
Step 26. H. handlemessage
This step is consistent with step 32 in the source code analysis of the android application startup process in the previous article.
Step 27. activitythread. handlelaunchactivity
This step is consistent with step 33 in the source code analysis of the android application startup process in the previous article.
Step 28. activitythread. initialize mlaunchactivity
This step is consistent with step 34 in the source code analysis of the android application startup process in the previous article. However, the class to be loaded from the classloader is shy. Luo. activity. subactivity.
Step 29. subacitiviy. oncreate
This function is defined in the packages/experimental/activity/src/shy/LUO/activity/subactivity. Java file. This is our custom app project file:
public class SubActivity extends Activity implements OnClickListener {......@Overridepublic void onCreate(Bundle savedInstanceState) {......Log.i(LOG_TAG, "Sub Activity Created.");}......}
In this way, subactivity is started inside the application activity.
There are many steps to start a new activity in the application, but the whole process is divided into the following four stages:
1. Step 1-Step 10: The mainactivity of the application notifies activitymanagerservice through the inter-process communication mechanism of the binder, and starts a new activity;
2. Step 11-Step 15: activitymanagerservice notifies mainactivity to enter the paused state through the inter-process communication mechanism of binder;
III. step 16-step 22: mainactivity notifies activitymanagerservice through the binder inter-process communication mechanism. It is ready to enter the paused status, activitymanagerservice prepares to start a new activity in the process and task where mainactivity is located;
4. Step 23-step 29: activitymanagerservice notifies the activitythread of the mainactivity through the communication mechanism between processes of the binder. Now everything is ready, and it can actually start the activity.
Compared with the default activity in the source code analysis of the Android app startup process in the previous article, the process of starting a new activity in the app is less than that of creating a new process in the middle, this is because the new activity is executed in existing processes and tasks, and there is no need to create new processes and tasks.
The binder inter-process communication mechanism is also involved in many aspects. For more information, see the Introduction and learning plan of the android inter-process communication (IPC) mechanism binder.
Here, we hope that you can analyze the source code of the Android app startup process and carefully compare the differences between the default and non-default activity startup processes of the app to better understand the activity.
Finally, in this article and above, we have mentioned the concept of task in Android applications many times. It is neither the process we understand in Linux ), it is not a thread. It is an abstraction of a series of operations that a user needs to perform to accomplish a specific goal. This is a very important concept. It defines the boundaries of applications from the perspective of user experience, greatly facilitating developers to build their own applications using ready-made components (activities, like building blocks, it also shields applications from the underlying processes, that is, the activities in a task can all be running in the same process, it can also run in different processes. For details about the concept of tasks in Android applications, refer to the official documentation "tasks.
Lao Luo's Sina Weibo: http://weibo.com/shengyangluo. welcome to the attention!