above

  • Android System Revealed (1) -Activity startup process (1)
  • Android System Revealed (1) -Activity startup process (1)
  • Android System Disclosure (2) -Service startup process
  • Android System Revealed (3) – Overview of Android system startup

preface

The last step in starting the Android system is to start the Launcher

What is the Launcher



If you don’t know what a Launcher is, look at this page and you’ll know it. A Launcher is a desktop.

The ICONS on the desktop are the launcher, and we can start the corresponding application with these ICONS.

The Launcher to start

Because each version of the difference is relatively large, so separate several versions of the analysis, do not want to see the source code students can directly see the end of the summary

Android 8 or 9

Let’s start with the overall sequence diagram:

The Zygote process starts the SystemServer process, and the entry to start the Launcher is the AMS systemReady method, which is called in the SystemServer startOtherServices method

As follows:

frameworks/base/services/java/com/android/server/SystemServer.java

public final class SystemServer {
    private void run(a) {...// Start services.
        try {
            t.traceBegin("StartServices");
            startBootstrapServices(t);
            startCoreServices(t);
            startOtherServices(t);
        } catch (Throwable ex) {
            Slog.e("System"."* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
            Slog.e("System"."************ Failure starting system services", ex);
            throw ex;
        } finally {
            t.traceEnd(); // StartServices}... }private void startOtherServices(@NonNull TimingsTraceAndSlog t) {... mActivityManagerService.systemReady(() -> { Slog.i(TAG,"Making services ready");
            t.traceBegin("StartActivityManagerReadyPhase"); mSystemServiceManager.startBootPhase(t, SystemService.PHASE_ACTIVITY_MANAGER_READY); . }... }}Copy the code

Take a look at the systemReady implementation

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
        ...
        mStackSupervisor.resumeFocusedStackTopActivityLocked();
        mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
        traceLog.traceEnd(); // ActivityManagerStartApps
        traceLog.traceEnd(); // PhaseActivityManagerReady
}

Copy the code

You can see that this is the ActivityStackSupervisor


frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

boolean resumeFocusedStackTopActivityLocked( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) { if (! readyToResume()) { return false; } if (targetStack ! = null && isFocusedStack(targetStack)) { return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); }... return false; }Copy the code

The back is called ActivityStack resumeTopActivityUncheckedLocked method


frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) { if (mStackSupervisor.inResumeTopActivity) { // Don't even start recursing. return false; } boolean result = false; try { // Protect against recursion. mStackSupervisor.inResumeTopActivity = true; result = resumeTopActivityInnerLocked(prev, options); } finally { mStackSupervisor.inResumeTopActivity = false; }... return result; } private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { ... return isOnHomeDisplay() && mStackSupervisor.resumeHomeStackTask(prev, "prevFinished"); . }Copy the code

ActivityStack eventually calls the ActivityStackSupervisor’s resumeHomeStackTask method

frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

boolean resumeHomeStackTask(ActivityRecord prev, String reason) { ... mHomeStack.moveHomeStackTaskToTop(); ActivityRecord r = getHomeActivity(); final String myReason = reason + " resumeHomeStackTask"; // Only resume home activity if isn't finishing. if (r ! = null && ! r.finishing) { moveFocusableActivityStackToFrontLocked(r, myReason); return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null); } return mService.startHomeActivityLocked(mCurrentUser, myReason); }Copy the code

Finally, back to AMS, call AMS’s startHomeActivityLocked method

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

boolean startHomeActivityLocked(int userId, FactoryTest == factorytest.factory_test_low_level && mTopAction == null) {// We are running in factory test mode, but unable to find // the factory test app, so just sit around displaying the // error message and don't try to start anything. return false; } Intent intent = getHomeIntent(); ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId); if (aInfo ! = null) { intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name)); // Don't do this if the home app is currently being // instrumented. aInfo = new ActivityInfo(aInfo); aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId); ProcessRecord app = getProcessRecordLocked(aInfo.processName, aInfo.applicationInfo.uid, true); if (app == null || app.instr == null) { intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid); // For ANR debugging to verify if the user activity is the one that actually // launched. final String myReason = reason  + ":" + userId + ":" + resolvedUserId; mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason); } } else { Slog.wtf(TAG, "No home screen found for " + intent, new Throwable()); } return true; } Intent getHomeIntent() { Intent intent = new Intent(mTopAction, mTopData ! = null ? Uri.parse(mTopData) : null); intent.setComponent(mTopComponent); intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING); if (mFactoryTest ! = FactoryTest.FACTORY_TEST_LOW_LEVEL) { intent.addCategory(Intent.CATEGORY_HOME); } return intent; }Copy the code

Here an Intent is launched, and you can see the list configuration of the Launcher from the source code

packages/apps/Launcher3/AndroidManifest.xml

<? The XML version = "1.0" encoding = "utf-8"? > <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.launcher3"> <application android:backupAgent="com.android.launcher3.LauncherBackupAgent" android:fullBackupOnly="true" android:fullBackupContent="@xml/backupscheme" android:hardwareAccelerated="true" android:icon="@drawable/ic_launcher_home" android:label="@string/derived_app_name" android:theme="@style/LauncherTheme" android:largeHeap="@bool/config_largeHeap" android:restoreAnyVersion="true" android:supportsRtl="true" > <activity android:name="com.android.launcher3.Launcher" android:launchMode="singleTask" android:clearTaskOnLaunch="true" android:stateNotNeeded="true" android:windowSoftInputMode="adjustPan|stateUnchanged" android:screenOrientation="nosensor" android:configChanges="keyboard|keyboardHidden|navigation" android:resizeableActivity="true" android:resumeWhilePausing="true" android:taskAffinity="" android:enabled="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.HOME" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.MONKEY"/> </intent-filter> </activity> </application> </manifest>Copy the code

Finally, use ActivityStarter to start the Launcher. For details, see Starting an Activity

frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) { mSupervisor.moveHomeStackTaskToTop(reason); mLastHomeActivityStartResult = startActivityLocked(null /*caller*/, intent, null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/, null /*voiceSession*/, null /*voiceInteractor*/, null /*resultTo*/, null /*resultWho*/, 0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/, null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/, 0 /*startFlags*/, null /*options*/, false /*ignoreTargetSecurity*/, false /*componentSpecified*/, mLastHomeActivityStartRecord /*outActivity*/, null /*inTask*/, "startHomeActivity: " + reason); . }Copy the code

summary

  • Use AMS to start the Launcher in SystemServer
  • AMS call ActivityStackSupervisor resumeFocusedStackTopActivityLocked method
  • I went through the ActivityStackSupervisor -> ActivityStack -> ActivityStackSupervisor ->AMS process, did some stack-related work in between, and finally came back to AMS
  • AMS calls ActivityStarter to start the Launcher Activity

It is recommended to look back at the sequence diagram after reading the source code, which will be more clear

Android 10

Sequence diagram:

Like Android 8, it starts from AMS, Different android to a 10 ActivityTaskManagerInternal mAtmInternal type of service frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

@VisibleForTesting public ActivityTaskManagerInternal mAtmInternal; public ActivityManagerService(Context systemContext, ActivityTaskManagerService atm) { ... mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class); } public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) { ... t.traceBegin("resumeTopActivities"); mAtmInternal.resumeTopActivities(false /* scheduleIdle */); t.traceEnd(); . }Copy the code

Where we see mAtmInternal, LocalServices class is a class and object of key/value pairs, and ActivityTaskManagerInternal is an abstract class, We find it only derived class ActivityTaskManagerService. LocalService

frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java


public class ActivityTaskManagerService extends IActivityTaskManager.Stub {

    RootActivityContainer mRootActivityContainer;
    final class LocalService extends ActivityTaskManagerInternal {
        @Override
        public void resumeTopActivities(boolean scheduleIdle) {
            synchronized(mGlobalLock) { mRootActivityContainer.resumeFocusedStacksTopActivities(); . }}}}Copy the code

Call the RootActivityContainer resumeFocusedStacksTopActivities method here

frameworks/base/services/core/java/com/android/server/wm/RootActivityContainer.java

boolean resumeFocusedStacksTopActivities() { return resumeFocusedStacksTopActivities(null, null, null); } boolean resumeFocusedStacksTopActivities( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) { ... for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { ... if (! resumedOnDisplay) { final ActivityStack focusedStack = display.getFocusedStack(); if (focusedStack ! = null) { focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions); } } } return result; }Copy the code

Next came ActivityStack

frameworks/base/services/core/java/com/android/server/wm/ActivityStack.java

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) { ... result = resumeTopActivityInnerLocked(prev, options); . } private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { .... if (! hasRunningActivity) { // There are no activities left in the stack, let's look somewhere else. return resumeNextFocusableActivityWhenStackIsEmpty(prev, options); }... }Copy the code
 private boolean resumeNextFocusableActivityWhenStackIsEmpty(ActivityRecord prev,
            ActivityOptions options) {
        ...
        return mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId);
    }
Copy the code

And call the RootActivityContainer resumeHomeActivity resumeNextFocusableActivityWhenStackIsEmpty method

frameworks/base/services/core/java/com/android/server/wm/RootActivityContainer.java

 boolean resumeHomeActivity(ActivityRecord prev, String reason, int displayId) {

        ...
        return startHomeOnDisplay(mCurrentUser, myReason, displayId);
    }
Copy the code
  boolean startHomeOnDisplay(int userId, String reason, int displayId) {
        return startHomeOnDisplay(userId, reason, displayId, false /* allowInstrumenting */,
                false /* fromHomeKey */);
    }
Copy the code

So in startHomeOnDisplay, we get homeIntent, and then we go to the last line:

boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting, boolean fromHomeKey) { ... Intent homeIntent = null; ActivityInfo aInfo = null; if (displayId == DEFAULT_DISPLAY) { homeIntent = mService.getHomeIntent(); aInfo = resolveHomeActivity(userId, homeIntent); } else if (shouldPlaceSecondaryHomeOnDisplay(displayId)) { Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, displayId); aInfo = info.first; homeIntent = info.second; }... / / start HomeActivity mService is ActivityTaskManagerService mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason, displayId); return true; }Copy the code

MService. GetActivityStartController () get ActivityStartController

frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java

private ActivityStartController mActivityStartController; ActivityStartController getActivityStartController() { return mActivityStartController; } public void initialize(IntentFirewall intentFirewall, PendingIntentController intentController, Looper looper) { ... mActivityStartController = new ActivityStartController(this); . }Copy the code

Finally, use the ActivityStartController to start the Launcher

frameworks/base/services/core/java/com/android/server/wm/ActivityStartController.java

void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, TaskDisplayArea taskDisplayArea) { ... mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason) .setOutActivity(tmpOutRecord) .setCallingUid(0) .setActivityInfo(aInfo) .setActivityOptions(options.toBundle()) .execute(); mLastHomeActivityStartRecord = tmpOutRecord[0]; . if (homeStack.mInResumeTopActivity) { mSupervisor.scheduleResumeTopActivities(); }}Copy the code

    ActivityStarter obtainStarter(Intent intent, String reason) {
        return mFactory.obtain().setIntent(intent).setReason(reason);
    }
Copy the code

The resulting process can be referenced to the start of the Activity

summary

  • Use AMS to start the Launcher in SystemServer
  • AMS call ActivityTaskManagerInternal resumeTopActivities method
  • Display the relevant things in RootActivityContainer, then use ActivityStack to do some stack-related work, and then go back to RootActivityContainer
  • Start the LauncherActivity with ActivityStartController

It is recommended to look back at the sequence diagram after reading the source code, which will be more clear

Android 11

Sequence diagram:



The Launcher for Android 11 is similar to Android 10

Call resumeTopActivities in AMS just like Android 10

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

@VisibleForTesting public ActivityTaskManagerInternal mAtmInternal; public ActivityManagerService(Context systemContext, ActivityTaskManagerService atm) { ... mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class); } public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) { ... t.traceBegin("resumeTopActivities"); mAtmInternal.resumeTopActivities(false /* scheduleIdle */); t.traceEnd(); . }Copy the code

The difference is that Android11 uses RootWindowContainer instead of RootActivityContainer to start the Launcher

frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java


public class ActivityTaskManagerService extends IActivityTaskManager.Stub {

    RootWindowContainer mRootWindowContainer;
    final class LocalService extends ActivityTaskManagerInternal {
        @Override
        public void resumeTopActivities(boolean scheduleIdle) {
            synchronized (mGlobalLock) {
                10 for mRootActivityContainer / /
                mRootWindowContainer.resumeFocusedStacksTopActivities();
                if (scheduleIdle) {
                    mStackSupervisor.scheduleIdle();
                }
            }
        }
    }
}
Copy the code

The following code is a bit different. When ActivityStack is not present in ActivityDisplay, focusedStack == null, Android 11 starts the resumeHomeActivity method directly

frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

boolean resumeFocusedStacksTopActivities() { return resumeFocusedStacksTopActivities(null, null, null); } boolean resumeFocusedStacksTopActivities( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) { ... for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { ... if (! resumedOnDisplay) { final ActivityStack focusedStack = display.getFocusedStack(); if (focusedStack ! = null) { result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions); } else if (targetStack == null) { result |= resumeHomeActivity(null /* prev */, "no-focusable-task", display.getDefaultTaskDisplayArea()); } } } return result; }Copy the code

This process is similar to Android 10 and is handled using ActivityStack

frameworks/base/services/core/java/com/android/server/wm/ActivityStack.java

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) { ... result = resumeTopActivityInnerLocked(prev, options); . } private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { .... if (! hasRunningActivity) { // There are no activities left in the stack, let's look somewhere else. return resumeNextFocusableActivityWhenStackIsEmpty(prev, options); }... }Copy the code
 private boolean resumeNextFocusableActivityWhenStackIsEmpty(ActivityRecord prev,
            ActivityOptions options) {
        ...
        return mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId);
    }
Copy the code

You end up back in RootWindowContainer’s resumeHomeActivity method

frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

boolean resumeHomeActivity(ActivityRecord prev, String reason, TaskDisplayArea taskDisplayArea) { if (! mService.isBooting() && ! mService.isBooted()) { // Not ready yet! return false; } if (taskDisplayArea == null) { taskDisplayArea = getDefaultTaskDisplayArea(); } final ActivityRecord r = taskDisplayArea.getHomeActivity(); final String myReason = reason + " resumeHomeActivity"; // Only resume home activity if isn't finishing. if (r ! = null && ! r.finishing) { r.moveFocusableActivityToTop(myReason); return resumeFocusedStacksTopActivities(r.getRootTask(), prev, null); } return startHomeOnTaskDisplayArea(mCurrentUser, myReason, taskDisplayArea, false /* allowInstrumenting */, false /* fromHomeKey */); }Copy the code

Go to startHomeOnTaskDisplayArea methods (the method name is not the same as before)

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); } else if (shouldPlaceSecondaryHomeOnDisplayArea(taskDisplayArea)) { Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, taskDisplayArea); aInfo = info.first; homeIntent = info.second; } if (aInfo == null || homeIntent == null) { return false; } if (! canStartHomeOnDisplayArea(aInfo, taskDisplayArea, allowInstrumenting)) { return false; } // Updates the home component of the intent. homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name)); homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK); // Updates the extra information of the intent. if (fromHomeKey) { homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true); mWindowManager.cancelRecentsAnimation(REORDER_KEEP_IN_PLACE, "startHomeActivity"); } final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId( aInfo.applicationInfo.uid) + ":" + taskDisplayArea.getDisplayId(); / / start HomeActivity mService is ActivityTaskManagerService mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason, taskDisplayArea); return true; }Copy the code

RootWindowContainer starts with ActivityStartControlle. This process is similar to that of Android 10.

frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java

private ActivityStartController mActivityStartController; ActivityStartController getActivityStartController() { return mActivityStartController; } public void initialize(IntentFirewall intentFirewall, PendingIntentController intentController, Looper looper) { ... mActivityStartController = new ActivityStartController(this); . }Copy the code

frameworks/base/services/core/java/com/android/server/wm/ActivityStartController.java

void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, TaskDisplayArea taskDisplayArea) { ... mSupervisor.beginDeferResume(); final ActivityStack homeStack; try { // Make sure home stack exists on display area. homeStack = taskDisplayArea.getOrCreateRootHomeTask(ON_TOP); } finally { mSupervisor.endDeferResume(); } mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason) .setOutActivity(tmpOutRecord) .setCallingUid(0) .setActivityInfo(aInfo) .setActivityOptions(options.toBundle()) .execute(); mLastHomeActivityStartRecord = tmpOutRecord[0]; if (homeStack.mInResumeTopActivity) { mSupervisor.scheduleResumeTopActivities(); }}Copy the code

    ActivityStarter obtainStarter(Intent intent, String reason) {
        return mFactory.obtain().setIntent(intent).setReason(reason);
    }
Copy the code

summary

  • Other than the RootActivityContainer job being replaced by RootWindowContainer, the rest of the process doesn’t change much from Android 10

The Launcher to start the Activity

The Launcher startActivitySafely way start Activity packages/apps/Launcher3 / SRC/com/android/Launcher3 / Launcher. Java

public boolean startActivitySafely(View v, Intent intent, ItemInfo item) { ... Intent.addflags (intent.flag_activity_new_task); . try { ... startActivity(intent, optsBundle); . } catch (ActivityNotFoundException|SecurityException e) { Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e); } return false; }Copy the code

conclusion

Compare the sequence diagrams for several versions

  • Android 8 or 9

  • Android 10

  • Android 11

Android 10 changes a lot

It can be summarized as follows

  • First use AMS in SystemServer to start the Launcher
  • If Android 8-9
    • AMS call ActivityStackSupervisor resumeFocusedStackTopActivityLocked method
    • I went through the ActivityStackSupervisor -> ActivityStack -> ActivityStackSupervisor ->AMS process, did some stack-related work in between, and finally came back to AMS
    • AMS calls ActivityStarter to start the Launcher Activity
  • If Android is 10-11
    • AMS call ActivityTaskManagerInternal resumeTopActivities method

    • Display the relevant things in RootActivityContainer (Android11 for RootWindowContainer), then use ActivityStack to handle some stack-related work, Call the resumeHomeActivity method of RootActivityContainer. (In Android11, if ActivityStack is not found, call resumeHomeActivity directly.)

    • Use ActivityStartController to start the Launcher Activity