Related articles Android system startup process series Android application process series Android in-depth analysis of the four major components of Android AMS series
preface
As for AMS, the original plan was to write only one article to introduce it, but AMS has so many functions that one article is far from enough. In this article we continue to look at ActivityTask and Activity stack management related to AMS.
1.ActivityStack
ActivityStack is a stack-related class by name, but it is a management class that manages the various states of all activities in the system. It is managed by an ActivityStackSupervisor, which is created in the constructor in AMS. frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public ActivityManagerService(Context systemContext) {... mStackSupervisor =new ActivityStackSupervisor(this); . }Copy the code
1.1 ActivityStack instance type
There are multiple ActivityStack instances in ActivityStackSupervisor, as shown below. frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
public final class ActivityStackSupervisor implements DisplayListener {... ActivityStack mHomeStack; ActivityStack mFocusedStack;privateActivityStack mLastFocusedStack; . }Copy the code
MHomeStack is used to store the stack of activities in the Launcher App, and mFocusedStack represents the stack that is currently receiving input or starting the next Activity. MLastFocusedStack represents the stack of activities that received input previously.
The ActivityStack method is provided by ActivityStackSupervisor. For example, to get the mFocusedStack, just call the getFocusedStack method of ActivityStackSupervisor: frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
ActivityStack getFocusedStack(a) {
return mFocusedStack;
}Copy the code
1.2 ActivityState
ActivityStack stores all of the Activity’s states through enumerations, as shown below. frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
enum ActivityState {
INITIALIZING,
RESUMED,
PAUSING,
PAUSED,
STOPPING,
STOPPED,
FINISHING,
DESTROYING,
DESTROYED
}Copy the code
It’s easy to know what these states mean by their names. Application ActivityState scene there will be many, such as the following code: frameworks/base/services/core/Java/com/android/server/am/ActivityManagerService. Java
@Override
public void overridePendingTransition(IBinder token, String packageName,
int enterAnim, int exitAnim) {...if (self.state == ActivityState.RESUMED
|| self.state == ActivityState.PAUSING) {/ / 1
mWindowManager.overridePendingAppTransition(packageName,
enterAnim, exitAnim, null); } Binder.restoreCallingIdentity(origId); }}Copy the code
Switch overridePendingTransition method is used to set the Activity of the animation, Note 1 can see only as ActivityState RESUMED state or PAUSING for object will invoke the WMS type mWindowManager overridePendingAppTransition approach to switch the animation.
1.3 Activities in special states
There are activities defined in ActivityStack in special states, as shown below.
ActivityRecord mPausingActivity = null;// The Activity is being paused
ActivityRecord mLastPausedActivity = null;// The last Activity that was paused
ActivityRecord mLastNoHistoryActivity = null;// The last Activity with no history
ActivityRecord mResumedActivity = null;// The Activity is already resumed
ActivityRecord mLastStartedActivity = null;// The Activity that was last started
ActivityRecord mTranslucentActivityWaiting = null;// Uppermost Activity passed to the ConvertToalways methodCopy the code
These special states are of the ActivityRecord type, which records all information about an Activity. From a stack perspective (the Activity task stack is a hypothetical model), one or more ActivityRecords form a TaskRecord, which records the Activity stack, ActivityStack contains one or more TaskRecords.
1.4 Maintained ArrayList
ActivityStack maintains a number of ArrayLists. The main types of arrayLists are ActivityRecord and TaskRecord. The TaskRecord is used to record activities’ tasks.
ArrayList | The element type | instructions |
---|---|---|
mTaskHistory | TaskRecord | All tasks that were not destroyed |
mLRUActivities | ActivityRecord | For running activities, the first entry in the list is the least recently used element |
mNoAnimActivities | ActivityRecord | Activities that do not consider converting animations |
mValidateAppTokens | TaskGroup | Use to validate the application token with the window manager |
2. The Activity stack management
We know that activities are managed by a task stack, but the task stack is an imaginary model that doesn’t really exist. Stack management is built on this imaginary model, with stack management, we can operate on applications, applications can reuse their own applications and activities of other applications, saving resources. For example, if we use a social application, the contact details screen of the application provides the email address of the contact, and when we click on the email, we will jump to the email sending screen.
The activities in social applications and system Email are in different application processes, and with stack management, you can move the sending Email interface to the top of the stack where the details interface is in social applications to operate across processes. For more flexible stack management, The Android system provides many configurations, which are described below.
2.1 Launch Mode
Launch Mode is familiar. It is used to set the launching Mode of an Activity. Regardless of the launching Mode, the Activity will be at the top of the Activity stack. There are four types:
- Standerd: Default mode, each time an Activity is started, a new Activity instance is created.
- SingleTop: If the Activity to be started is already at the top of the stack, the Activity is not recreated and its onNewIntent method is called. If the Activity you want to start is not at the top of the stack, an instance of that Activity is recreated.
- SingleTask: If the Activity to be started already exists on the stack to which it wants to belong, the Activity instance is not created, all activities on the stack are removed from the stack, and the Activity’s onNewIntent method is called. If the Activity you want to start does not exist in the stack it wants to belong to, and the stack does, an instance of the Activity is recreated. If the stack you want to start the Activity to belong to does not exist, you first create a new stack, then create an instance of the Activity and push it into the new stack.
- SingleInstance: Similar to singleTask, except that when an Activity is started, it is first created on a new stack, and then an instance of the Activity is created and pushed onto the new stack, where only one instance of the Activity exists.
2.2 the Intent of the FLAG
A number of flags are defined in the Intent. Several of these flags can also set the launching Mode of the Activity. If the Launch Mode of the Activity conflicts with the FLAG setting, the FLAG setting prevails.
- FLAG_ACTIVITY_SINGLE_TOP: Same as singleTop in Launch Mode.
- FLAG_ACTIVITY_NEW_TASK: same as singleTask in Launch Mode.
- FLAG_ACTIVITY_CLEAR_TOP: There is no corresponding Mode in Launch Mode. If the Activity to be launched already exists on the stack, all activities above it are removed from the stack. SingleTask has the effect of this bit by default.
In addition to these three flags, there are several other flags that are helpful in analyzing stack management.
- FLAG_ACTIVITY_NO_HISTORY: Once an Activity exits, it does not exist in the stack. Similarly, you can set “Android :noHistory” in androidmanifest.xml.
- FLAG_ACTIVITY_MULTIPLE_TASK: It needs to be used in conjunction with FLAG_ACTIVITY_NEW_TASK to be effective. The system starts a new stack to hold the newly launched Activity.
- FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS: Activities are not placed in the Recently launched Activities list.
- FLAG_ACTIVITY_BROUGHT_TO_FRONT: This flag bit is not usually set by code in the application, but is automatically added when Launch Mode is singleTask.
- FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY: This flag bit is usually not set by code in the application, but is started from history (long press the Home button to bring it up).
- FLAG_ACTIVITY_CLEAR_TASK: To be effective, FLAG_ACTIVITY_NEW_TASK must be used in conjunction with FLAG_ACTIVITY_NEW_TASK to clear all other activities in the stack associated with the Activity being started.
Next, through the system source code to check the application of FLAG, in Android deep four components (a) application startup process (later), the root Activity will call AMS startActivity method, The startActivityUnchecked method of ActivityStarter is called through the layers of calls, as shown in the sequence diagram below.
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor);/ / 1
computeLaunchingTaskFlags();/ / 2
computeSourceStack();
mIntent.setFlags(mLaunchFlags);/ / 3. }Copy the code
Note 1 is used to initialize the various configurations used to start an Activity. These configurations are reset before initialization, including ActivityRecord, Intent, TaskRecord, and LaunchFlags. Note 2 the computeLaunchingTaskFlags methods are used to calculate the start of the FLAG, and to give mLaunchFlags calculating the value of the assignment. In comment 3, set mLaunchFlags to the Intent to specify how the Activity starts. And then to check computeLaunchingTaskFlags method.
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java
private void computeLaunchingTaskFlags(a) {...if (mInTask == null) {/ / 1
if (mSourceRecord == null) {/ / 2
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {/ / 3
Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
"Intent.FLAG_ACTIVITY_NEW_TASK for: "+ mIntent); mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; }}else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {/ / 4
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
} else if (mLaunchSingleInstance || mLaunchSingleTask) {/ / 5mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; }}}Copy the code
If the TaskRecord mInTask in comment 1 is null, the stack to which the Activity is to be added does not exist. Therefore, the main problem solved in this snippet of code is how to calculate the startup FLAG if the stack to which the Activity is to be added does not exist. In note 2, mSourceRecord of type ActivityRecord is used to describe an “initial Activity.” What is an “initial Activity”? For example, ActivityA starts ActivityB, and ActivityA is the initial Activity. If the conditions for both annotation 2 and annotation 3 are met, a new stack is created. In comment 4, if the stack on which the “initial Activity” is located allows only one instance of the Activity, then you need to create a new stack as well. At note 5, if Launch Mode is set to singleTask or singleInstance, a new stack will also be created.
2.3 taskAffinity
You can set Android :taskAffinity in androidmanifest.xml to specify which stack an Activity wants to belong to. By default, all activities in the same application have the same taskAffinity. TaskAffinity works in two situations.
- TaskAffinity works with FLAG_ACTIVITY_NEW_TASK or singleTask. If the taskAffinity of the newly launched Activity is the same as the taskAffinity of the stack (the taskAffinity of the stack depends on the taskAffinity of the root Activity), it is added to the stack. If not, a new stack is created.
- TaskAffinity works with allowTaskReparenting. If allowTaskReparenting is true, the Activity has the ability to shift. Take the previous email as an example. When a social application starts an Activity that sends emails, the Activity that sends emails is in the same stack as the social application. If the sending Activity’s allowTaskReparenting is set to true, then the email program’s stack is in the foreground, At this point, the Activity sending the mail is moved from the social application stack to the stack of its more closely related mail application (taskAffinity).
Then look at the taskAffinity application using the system source code. ActivityStackSupervisor’s findTaskLocked method is used to find the stack that best matches the Activity, and ultimately ActivityStack’s findTaskLocked method is called. frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
void findTaskLocked(ActivityRecord target, FindTaskResult result) {...for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {/ / 1
final TaskRecord task = mTaskHistory.get(taskNdx);/ / 2.else if(! isDocument && ! taskIsDocument && result.r ==null && task.canMatchRootAffinity()) {
if (task.rootAffinity.equals(target.taskAffinity)) {/ / 3
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
result.r = r;
result.matchedByRootAffinity = true; }}else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: "+ task); }}Copy the code
The logic of this method is more complex, and the section related to taskAffinity is captured here. Note 1 iterates through the mTaskHistory list, which contains the TaskRecord element to store tasks that have not been destroyed. Comment 2 shows information about a Task. Note 3 compares Task rootAffinity (initial taskAffinity) with taskAffinity (target Activity). If the matchedByRootAffinity attribute of FindTaskResult is set to true, a matching Task is found.
Reference materials “in-depth understanding of Android volume two” “in-depth understanding of Android kernel design ideas” second edition “Android development art exploration” ActivityRecord, TaskRecord, ActivityStack
Welcome to pay attention to my wechat public number, the first time to get blog updates, as well as more system of Android related original technology dry goods. Scan the qr code below or long press to identify the QR code, you can follow.