I’m participating in nuggets Creators Camp # 4, click here to learn more and learn together!

Summary of the application process startup process

In the previous analysis of the three articles Launcher application startup process (top), Launcher application startup process (middle) and Launcher application startup process (bottom), the code flow of the application process Launcher has been analyzed once. This article will summarize the overall process mentioned above

Launcher Application process starts

In the startup process of Android system, the first process is zygote, in zygote will split a system_server process, and after the system_server process will start various services, etc. This initializes the ActivityManagerService (AMS) and finally starts AMS by calling AMS’s systemReady function. In the systemReady function, By calling the ActivityTaskManagerService startHomeOnAllDisplays function (ATMS)

mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
Copy the code

MAtmInternal parameter is a ActivityTaskManagerInternal object, on the class diagram of the structure is as follows

classDiagram
ActivityTaskManagerInternal <|-- LocalService
ActivityTaskManagerService *-- LocalService
class ActivityTaskManagerInternal {
    +startHomeOnAllDisplays(int userId, String reason)* boolean
}
class ActivityTaskManagerService {
    ~LocalService
}
class LocalService {
    <<final>>
	+startHomeOnAllDisplays(int userId, String reason) boolean
}

In terms of the structure of the class diagram, ActivityTaskManagerInternal class is an abstract class, and startHomeOnAllDisplays functions is an abstract method, inheritance of the class LocalService implements the abstract function, And LocalService is an internal class of ATMS

And you know from the initialization of the ATMS service that the object’s mAtmInternal parameter is an instance of ATMS.LocalService

RootWindowContainer object function call

The RootWindowContainer object is an important class in windowing. It inherits from the WindowContainer object, and its class diagram structure is shown below

classDiagram WindowToken <|-- ActivityRecord AppFreezeListener <|.. ActivityRecord WindowManagerService *-- AppFreezeListener WindowContainer <|-- WindowToken ConfigurationContainer <|-- WindowContainer Animatable <|.. WindowContainer Freezable <|.. WindowContainer TransactionReadyListener <|.. WindowContainer Comparable <|.. WindowContainer <<interface>> Animatable <<interface>> Freezable <<interface>> TransactionReadyListener <<interface>> Comparable SurfaceFreezer *-- Freezable BLASTSyncEngine *-- TransactionReadyListener <<abstract>> ConfigurationContainer  Task <|-- ActivityStack WindowContainer <|-- Task WindowContainer <|-- DisplayContent DisplayContentInfo <|-- DisplayContent <<interface>> DisplayContentInfo WindowManagerPolicy <|-- DisplayContentInfo <<interface>> WindowManagerPolicy WindowContainer <|-- RootWindowContainer class AppFreezeListener { <<interface>> #onAppFreezeTimeout() void } class ActivityRecord { -Task task #asActivityRecord() ActivityRecord #getTask() Task } class WindowContainer { #asActivityRecord() ActivityRecord } class ConfigurationContainer { #getChildCount()* int #getChildAt(int index) * E #getParent()* ConfigurationContainer } class Animatable { #start() void #stop() void #isRunning() boolean }

The startHomeOnAllDisplays function of ATMS.LocalService calls the startHomeOnAllDisplays function of the RootWindowContainer object, which gets all display devices supported on the current device system. Get its DisplayId for each device and call the startHomeOnDisplay function of the RootWindowContainer object

In startHomeOnDisplay function can obtain corresponding Display device of the Display area, and call its startHomeOnTaskDisplayArea function, in this function,

  1. The ATMS getHomeIntent function retrieves the Intent Intent to look for, and the system-supported ActivityInfo is found based on that Intent
  2. At the same time, call the startHomeActivity function of the ActivityStartController object to officially start the corresponding Activity process
boolean startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea,
        boolean allowInstrumenting, boolean fromHomeKey) {
    / /...
    Intent homeIntent = null;
    ActivityInfo aInfo = null;
    if (taskDisplayArea == getDefaultTaskDisplayArea()) {
        homeIntent = mService.getHomeIntent();
        aInfo = resolveHomeActivity(userId, homeIntent);
    }
    / /...
    mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
            taskDisplayArea);
    return true;
}
Copy the code

ActivityStarter

The ActivityStartController object is an Activity starter that sends the requested Activity to the ActivityStarter for processing and starting. It also adds the necessary logical information to these activities, which is done in the startHomeActivity function of the ActivityStartController object

  1. Set conditional ActivityOptions for the Activity to be launched
  2. The generated ActivityInfo is then handed to ActivityStarter for processing
void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, TaskDisplayArea taskDisplayArea) {
    final ActivityOptions options = ActivityOptions.makeBasic();
    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());

    / /...

    mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
            .setOutActivity(tmpOutRecord)
            .setCallingUid(0)
            .setActivityInfo(aInfo)
            .setActivityOptions(options.toBundle())
            .execute();
    / /...
}
Copy the code

After the ActivityStarter object is initialized, the execute function is called to run and start the ActivityInfo object. The ActivityStarter class contains an internal class Request. This class mainly contains all the data requested to be started when ActivityStarter starts.

The request is then run by calling its executeRequest function, in this function

  1. Set the necessary parameters for the startup using the ActivityOptions and ActivityInfo parameters added above
  2. Next, initialize an ActivityRecord object that contains all the Activity information and call the startActivityUnchecked function
  3. After the startActivityUnchecked function is called, the ActivityRecord that will be launched is added to the Activity stack via ActivityStack’s startActivityLocked function, Thus in the last call RootWindowContainer resumeFocusedStacksTopActivities function to launch this Activity
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);
    if (mDoResume) {
        / /...
        if(! mTargetStack.isTopActivityFocusable() || (topTaskActivity ! =null&& topTaskActivity.isTaskOverlay() && mStartActivity ! = topTaskActivity)) {/ /...
        } else {
            / /...mRootWindowContainer.resumeFocusedStacksTopActivities( mTargetStack, mStartActivity, mOptions); }}/ /...
    return START_SUCCESS;
}
Copy the code

Resume Activity startup in RootWindowContainer

RootWindowContainer resumeFocusedStacksTopActivities function, the main call resumeTopActivityUncheckedLocked ActivityStack object function, Further call resumeTopActivityInnerLocked function, and finally into ActivityStackSupervisor startSpecificActivity function

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    / /...

    if (next.attachedToProcess()) {
        / /...
    } else {
        / /...
        mStackSupervisor.startSpecificActivity(next, true.true);
    }
    return true;
}
Copy the code

Use the startSpecificActivity function of ActivityStackSupervisor to start the process Launcher

void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
    / /...
    mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}
Copy the code

Launcher The application process starts

StartProcessAsync function of ATMS

void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop, String hostingType) {
    try {
        / /...
        // Post message to start process to avoid possible deadlock of calling into AMS with the
        // ATMS lock held.
        final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,
                mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,
                isTop, hostingType, activity.intent.getComponent());
        mH.sendMessage(m);
    } finally{ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); }}Copy the code

The PooledLambda obtainMessage function initializes a PooledRunnable object by initializing a Message object and processing the Message via sendMessage of the ams.h object. And set it to the Callback of the generated Message object

The class diagram is structured as follows

classDiagram
PooledLambda <|-- PooledRunnable
Runnable <|-- PooledRunnable
ThrowingRunnable <|-- PooledRunnable
TraceNameSupplier <|-- PooledRunnable
<<interface>>PooledRunnable
<<interface>>PooledLambda
<<interface>>Runnable
<<interface>>ThrowingRunnable
<<interface>>TraceNameSupplier

PooledRunnable is a thread inherited from Runnable

The sendMessage function of ams. H will add the above generated Message object to MessageQueue and distribute these messages to ams. H for processing through the dispatchMessage function

If a Message containing a Callback is not null, the Handler object’s handleCallback is called to run the Callback directly.

To call the startProcess function of the mAmInternal parameter of ATMS, mAmInternal is an instance of ActivityManagerInternal.

The ActivityManagerInternal class structure is shown below

classDiagram
ActivityManagerInternal <|-- LocalService
<<abstract>> ActivityManagerInternal
<<final>> LocalService
ActivityManagerService *-- LocalService
class ActivityManagerInternal {
	+startProcess(String, ApplicationInfo, boolean, boolean, String, ComponentName)* void
}
class LocalService {
	+startProcess(String, ApplicationInfo, boolean, boolean, String, ComponentName) void
}

As a result, the startProcess function of ams. LocalService is eventually called, and the process. start function is finally called in the startProcess function of the ProcessList object to generate a Process from zygote and start it

@Override
public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead,
        boolean isTop, String hostingType, ComponentName hostingName) {
    try {
        / /...
        synchronized (ActivityManagerService.this) {
            / /...
            startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */.new HostingRecord(hostingType, hostingName, isTop),
                    ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */.false /* isolated */.true /* keepIfLarge */); }}/ /...
}

final ProcessRecord startProcessLocked(String processName,
        ApplicationInfo info, boolean knownToBeDead, int intentFlags,
        HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
        boolean isolated, boolean keepIfLarge) {
    return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
            hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
            keepIfLarge, null /* ABI override */.null /* entryPoint */.null /* entryPointArgs */.null /* crashHandler */);
}

/ /... Overloaded function elision

boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app,
            int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal,
            String seInfo, String requiredAbi, String instructionSet, String invokeWith,
            long startTime) {
    / /...
    if (mService.mConstants.FLAG_PROCESS_START_ASYNC) {
        / /...
    } else {
        try {
            final Process.ProcessStartResult startResult = startProcess(hostingRecord,
                    entryPoint, app,
                    uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo,
                    requiredAbi, instructionSet, invokeWith, startTime);
            handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
                    startSeq, false);
        }
        / /...}}private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
            ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags,
            int mountExternal, String seInfo, String requiredAbi, String instructionSet,
            String invokeWith, long startTime) {
    / /...
    startResult = Process.start(entryPoint,
            app.processName, uid, uid, gids, runtimeFlags, mountExternal,
            app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
            app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,
            isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap,
            whitelistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
            new String[]{PROC_START_SEQ_IDENT + app.startSeq});
    / /...
}
Copy the code

The Launcher application process is created and started

Sequence diagram of the application process startup process

feeling

Because I am analyzing this process while working, and the application process Launcher is very complicated (for my personal feelings), there are many code branches in the analysis process, and the detailed parameters and results are not clear, which not only takes a long time, but also makes slow progress. Therefore, I would like to share my real feelings as follows

  1. For source code analysis, branches and complex structure of the module, you need to add some log or debug data to assist the analysis, and can not take it for granted that a branch should go to or should not go to, so easy to go astray
  2. Source analysis means need to strengthen, a lot of very useful debugging tools, such AS AS DEBUG function, source view tools, flow charts and other tools to help source analysis need to strengthen the application
  3. Source code analysis process, sometimes need to trace the source, sometimes need to browse with, degree to grasp