“This is the 14th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”
Today is January 31, 2022, the Lunar New Year’s Eve, I wish all programmers brothers and sisters, the year of the Tiger is auspicious, huhu shengwei, everything goes well, good luck in the coming year!!
Analysis of the application Launcher startup process after the system starts
In the system startup process, through the Zygote process fork a SystemServer process, and in this process, started the system must be a variety of core services, among which AMS is an important one. After AMS starts the SystemServer process, it will call a systemReady function to complete some operations after the system starts, including the startup process of the application Launcher, and the code is as follows:
ActivityManagerService.java
The bootingSystemUser parameter indicates whether the current login user is a system user
if (bootingSystemUser) {
The mAtmInternal argument is obtained from the getService function of LocalServices
/ / but when ActivityTaskManagerService initialization LocalServiecs will pass the addService function to register the object
/ / this return mAtmInternal parameter is actually a ActivityTaskManagerService. LocalService object
mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
}
Copy the code
In light of above remark parsing, here will call ActivityTaskManagerService. LocalService. StartHomeOnAllDisplays function, therefore
ActivityTaskManagerService.java
public boolean startHomeOnAllDisplays(int userId, String reason) {
// mGlobalLock parameter lock, which is a WindowManagerGlobalLock object, is also used in other services to lock synchronization operations
synchronized (mGlobalLock) {
// The startHomeOnAllDisplays function of the mRootWindowContainer object is called
// The mRootWindowContainer parameter is the object corresponding to the mRoot parameter in WindowManagerService
The mRootWindowContainer argument is obtained by calling AMS's setWindowManager function and then ATMS.LocalServices' setWindowManager function
// Therefore, it is important to note that the mWmService parameter of the RootWindowContainer object corresponds to the WindowManagerService object
/ / mService parameters corresponding ActivityTaskManagerService object
returnmRootWindowContainer.startHomeOnAllDisplays(userId, reason); }}Copy the code
The RootWindowContainer class diagram is as follows:
classDiagram
WindowContainer <|-- RootWindowContainer
ActivityTaskManagerService -- RootWindowContainer : mStackSupervisor
Handler <|-- MyHandler
RootWindowContainer <-- MyHandler : mHandler
ActivityStackSupervisor <-- RootWindowContainer : mRootWindowContainer
MyHandler --* RootWindowContainer
class ActivityTaskManagerService {
#mStackSupervisor : ActivityStackSupervisor
}
class RootWindowContainer {
#mService : ActivityTaskManagerService
-mHandler : Handler
#mStackSupervisor : ActivityStackSupervisor
+setWindowManager(WindowManagerService)
}
class WindowContainer {
#mWmService : WindowManagerService
}
class ActivityStackSupervisor {
#mRootWindowContainer : RootWindowContainer
}
Based on the previous code, the startHomeOnAllDisplays function, which is the RootWindowContainer object, is called
RootWindowContainer.java
UserId = userhandle. USER_SYSTEM, reason = "systemReady"
boolean startHomeOnAllDisplays(int userId, String reason) {
boolean homeStarted = false;
GetChildCount getChildCount getChildCount getChildCount getChildCount getChildCount getChildCount getChildCount getChildCount getChildCount getChildCount getChildCount getChildCount getChildCount getChildCount getChildCount getChildCount getChildCount
// mChildren is a WindowList object containing data that is used when the setWindowManager function is called,
// The number of displays obtained from DisplayManagerService,
// The DisplayManagerService load default display device is described in this article
for (int i = getChildCount() - 1; i >= 0; i--) {
// Get the displayId for the new DisplayContent
final int displayId = getChildAt(i).mDisplayId;
// Call startHomeOnDisplay
homeStarted |= startHomeOnDisplay(userId, reason, displayId);
}
return homeStarted;
}
Copy the code
As you can see from the code, the main screen of the multiple Launcher is launched for multiple display devices. Of course, in this case, we only analyze the default display device, so
RootWindowContainer.java
boolean startHomeOnDisplay(int userId, String reason, int displayId) {
return startHomeOnDisplay(userId, reason, displayId, false /* allowInstrumenting */.false /* fromHomeKey */);
}
boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting, boolean fromHomeKey) {
// Fallback to top focused display or default display if the displayId is invalid.
// The displayId part obtained by DisplayManagerService is INVALID_DISPLAY, so the criteria are not met
if (displayId == INVALID_DISPLAY) {
finalActivityStack stack = getTopDisplayFocusedStack(); displayId = stack ! =null ? stack.getDisplayId() : DEFAULT_DISPLAY;
}
final DisplayContent display = getDisplayContent(displayId);
boolean result = false;
for (int tcNdx = display.getTaskDisplayAreaCount() - 1; tcNdx >= 0; --tcNdx) {
final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tcNdx);
/ / will call startHomeOnTaskDisplayArea function
result |= startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea,
allowInstrumenting, fromHomeKey);
}
return result;
}
boolean startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea,
boolean allowInstrumenting, boolean fromHomeKey) {
/ /... Function irrelevant code, omitted here
if (taskDisplayArea == getDefaultTaskDisplayArea()) {
// 1. Use the ATMS getHomeIntent function to obtain an Intent object
// This Intent object
// homeIntent.action = Intent.ACTION_MAIN
FLAG_DEBUG_TRIAGED_MISSING // Flags for homeIntent include intent.flag_debug_triaged_missing
// The category of homeIntent contains intent.category_HOME
homeIntent = mService.getHomeIntent();
// 2. Get an ActivityInfo object that contains startup information
aInfo = resolveHomeActivity(userId, homeIntent);
}
/ /... Function irrelevant code, omitted here
// Updates the home component of the intent.
homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
/ /... Condition judgment cannot be met, code omitted
// Update the reason for ANR debugging to verify if the user activity is the one that
// actually launched.
final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
aInfo.applicationInfo.uid) + ":" + taskDisplayArea.getDisplayId();
// 3. Use the startHomeActivity function of the ActivityStartController object
mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
taskDisplayArea);
return true;
}
Copy the code
As you can see from the above code, there are basically three things going on here
- The ATMS getHomeIntent function gets an Intent object that starts an Activity
- Get the ActivityInfo object for the startup screen using the resolveHomeActivity function
- The corresponding Activity is started using the startHomeActivity function of the ActivityStartController object
So let’s look at it one by one
Gets an Intent object that starts the Activity
Intent getHomeIntent(a) {
// Initializes an Intent object with the action value intent.action_main
Intent intent = newIntent(mTopAction, mTopData ! =null ? Uri.parse(mTopData) : null);
// Set the corresponding Component, null here
intent.setComponent(mTopComponent);
// Add flags,
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
if(mFactoryTest ! = FactoryTest.FACTORY_TEST_LOW_LEVEL) {/ / add a category
intent.addCategory(Intent.CATEGORY_HOME);
}
return intent;
}
Copy the code
As you can see, the code here is relatively simple: Initialize an Intent and set its parameters
Gets the ActivityInfo object for the startup screen
RootWindowContainer.java
ActivityInfo resolveHomeActivity(int userId, Intent homeIntent) {
final int flags = ActivityManagerService.STOCK_PM_FLAGS;
final ComponentName comp = homeIntent.getComponent(); // null
ActivityInfo aInfo = null;
try {
if(comp ! =null) {
/ /... Condition not met, code omitted
} else {
// Get the content type of the Intent, null
final String resolvedType =
homeIntent.resolveTypeIfNeeded(mService.mContext.getContentResolver());
/ / AppGlobals getPackageManager () function returns a PackageManagerService object
// This function iterates through all the applications in the system and retrieves the corresponding ResolveInfo object that meets the most criteria
final ResolveInfo info = AppGlobals.getPackageManager()
.resolveIntent(homeIntent, resolvedType, flags, userId);
// aInfo corresponds to ActivityInfo of ResolveInfo
if(info ! =null) { aInfo = info.activityInfo; }}}/ /... Catch exceptions, code omitted
aInfo = new ActivityInfo(aInfo);
aInfo.applicationInfo = mService.getAppInfoForUser(aInfo.applicationInfo, userId);
return aInfo;
}
Copy the code
The result is a corresponding ActivityInfo object with the most qualified application information
Start the corresponding Activity
/ / ATMS getActivityStartController function returns a ActivityStartController object
// This object is initialized in the ATMS initialize function
mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason, taskDisplayArea);
Copy the code
The ActivityStartController class diagram is shown below
classDiagram ActivityStarter *-- DefaultFactory ActivityStarter *-- Factory ActivityStartController <-- DefaultFactory : mFactory ActivityStartController <-- ActivityTaskManagerService : mService ActivityStartController <-- ActivityStackSupervisor : mSupervisor ActivityStartController <-- StartHandler : mHandler Handler <|-- StartHandler Factory <|-- DefaultFactory ActivityStartController *--StartHandler ActivityStartController --> DefaultFactory : mController ActivityTaskManagerService --> DefaultFactory : mService ActivityStackSupervisor --> DefaultFactory : mSupervisor <<interface>> Factory ActivityTaskManagerService <-- ActivityStackSupervisor : mSupervisor class ActivityTaskManagerService { +getActivityStartController() }
As you can see from the class diagram, the startHomeActivity function of the ActivityStartController object is called here
void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, TaskDisplayArea taskDisplayArea) {
final ActivityOptions options = ActivityOptions.makeBasic();
// Set the mode to full-screen
options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
if(! ActivityRecord.isResolverActivity(aInfo.name)) {// The resolver activity shouldn't be put in home stack because when the foreground is
// standard type activity, the resolver activity should be put on the top of current
// foreground instead of bring home stack to front.
options.setLaunchActivityType(ACTIVITY_TYPE_HOME);
}
final int displayId = taskDisplayArea.getDisplayId();
options.setLaunchDisplayId(displayId);
options.setLaunchTaskDisplayArea(taskDisplayArea.mRemoteToken
.toWindowContainerToken());
// The home activity will be started later, defer resuming to avoid unneccerary operations
// (e.g. start home recursively) when creating home stack.
mSupervisor.beginDeferResume();
final ActivityStack homeStack;
try {
// Create an ActivityStack object
// Make sure home stack exists on display area.
homeStack = taskDisplayArea.getOrCreateRootHomeTask(ON_TOP);
} finally {
mSupervisor.endDeferResume();
}
The obtainStarter function initializes an ActivityStarter object and sets its Intent and reason parameters
// When the ActivityStarter object is initialized, a Request object is initialized, and the setup functions here are used to set the parameters of the Request
// Finally run the Request through the execute function
mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
.setOutActivity(tmpOutRecord)
.setCallingUid(0)
.setActivityInfo(aInfo)
.setActivityOptions(options.toBundle())
.execute();
mLastHomeActivityStartRecord = tmpOutRecord[0];
/ /...
}
ActivityStarter.java
int execute(a) {
try {
/ /... Feature-independent code, omitted here
int res;
synchronized (mService.mGlobalLock) {
final booleanglobalConfigWillChange = mRequest.globalConfig ! =null&& mService.getGlobalConfiguration().diff(mRequest.globalConfig) ! =0;
final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();
if(stack ! =null) {
stack.mConfigWillChange = globalConfigWillChange;
}
/ /... Log printing, function irrelevant code, omitted here
// Call executeRequest to run the Request
res = executeRequest(mRequest);
/ /... Feature-independent code, omitted here
// Notify ActivityMetricsLogger that the activity has launched.
// ActivityMetricsLogger will then wait for the windows to be drawn and populate
// WaitResult.
// Notifies the Activity to start
mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
mLastStartActivityRecord);
return getExternalResult(mRequest.waitResult == null? res : waitForResult(res, mLastStartActivityRecord)); }}finally {
// Run completeonExecutionComplete(); }}Copy the code
As shown above, the executeRequest function is eventually called to continue running
ActivityStarter.java
private int executeRequest(Request request) {
/ /... Some condition check, here directly omit temporarily do not look
final ActivityRecord r = newActivityRecord(mService, callerApp, callingPid, callingUid, callingPackage, callingFeatureId, intent, resolvedType, aInfo, mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode, request.componentSpecified, voiceSession ! =null, mSupervisor, checkedOptions,
sourceRecord);
mLastStartActivityRecord = r;
/ /...
final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();
/ /...
mService.onStartActivitySetDidAppSwitch();
mController.doPendingActivityLaunches(false);
// startActivityUnchecked
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
restrictedBgActivity, intentGrants);
/ /...
return mLastStartActivityResult;
}
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity, NeededUriGrants intentGrants) {
/ /...
// Call startActivityInner
result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);
/ /...
return result;
}
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity, NeededUriGrants intentGrants) {
/ /...mTargetStack.startActivityLocked(mStartActivity, topStack ! =null ? topStack.getTopNonFinishingActivity() : null, newTask,
mKeepCurTransition, mOptions);
/ /...
mRootWindowContainer.updateUserStack(mStartActivity.mUserId, mTargetStack);
// Update the recent tasks list immediately when the activity starts
mSupervisor.mRecentTasks.add(mStartActivity.getTask());
mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(),
mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetStack);
return START_SUCCESS;
}
Copy the code
The startActivityInner function starts the application Launcher with the data contained in the ActivityInfo object. How to start the application Launcher will be discussed in the next article
conclusion
Let’s start by summarizing the process of starting the application Launcher
- In the SystemServer startOtherServices function, the systemReady function of ActivityManagerService is called to notify the system of the completion of startup
- Call the startHomeOnAllDisplays function of the ATMS service in the ams. systemReady function to start the load and startup process of the Launcher
- Call the RootWindowContainer object’s startHomeOnAllDisplays function, where the DisplayManagerService gets the corresponding display device ID (displayId). Then get need to display area, finally through RootWindowContainner startHomeOnTaskDisplayArea function to continue the boot process
- In the RootWindowContainner startHomeOnTaskDisplayArea function, through ATMS to ActivityStartController object, and call its startHomeActivity function, at the same time in this function, Apply a specific Intent attribute (Action =) to the Launcher Intent.action_main and intent.category_home) find the ActivityInfo for all the Launcher criteria in the system
- Corresponding ActiivtyInfo object based on the above, start the Launcher application in startHomeActivity ActivityStarterController object function
The sequence diagram corresponding to the above process is as follows: