Homelauncher launch


This article explains the relevant knowledge of launcher startup and corrects the mistakes in some articles on the Internet

This article isChicken egg seriesThe fifth article, the last one, can finally end the series.

  1. Data reporting process of Linux input system
  2. Android inputmanager analysis
  3. AMS startActivity()
  4. Activity display process carding
  5. Homelauncher launch

[Code: Android 11]


[Code: Android 8.1]



Search online information, many articles say that the launcher is started in

ActivityManagerService.systemReady() --> startHomeActivityLocked()

It started when it was started. Is this right? This is actually right and wrong (maybe the version they analyzed is too old).

Say it’s wrong. Let’s talk about it later. Let’s take a brief look at the process code first.

AMS (activitymanagerservice) systemready() is called when systemserver startotherservices(). The process is summarized as follows:

main(String[] args)
  + new SystemServer().run();
      + startBootstrapServices(t);
      + startCoreServices(t);
      + startOtherServices(t);
          + mActivityManagerService.systemReady(() -> {
                ... // the callback parameter will start the system UI, and you can pay attention to it if necessary
                startSystemUi(context, windowManagerF);

For the < Android 10 version, AMS systemready() further uses starthomeactivitylocked(), and some articles think that the launcher is started here

public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
        startHomeActivityLocked(currentUserId, "systemReady");

boolean startHomeActivityLocked(int userId, String reason) {
    // home intent
    Intent intent = getHomeIntent();
    //Get which application the intent should start
    ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
    if (aInfo != null) {
            //Start the activity. The subsequent process is similar to the application startup process. I won't talk about it
            mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);

For detailed code explanation, you can search relevant articles on the Internet. There are many on the Internet,



Is it really over?

I always thought it was like this before. I thought that others had written a lot of such articles, and I didn’t mean much to have more than one, so I wanted to use the method of reverse analysis. As a result, this analysis found something wrong

backward analysis

The so-called reverse analysis is that I assume I don’t know the answer and don’t know how the framework works. Start with the launcher’s oncreate() to see if I can get the same result

The method used is also very simple, that is, print the call stack, then look at the code, continue to analyze, continue to print the call stack… Repeat

Specifically, the common stack printing methods of Android Java layer are as follows:

  • Throwable
Log.i(TAG, Log.getStackTraceString(new Throwable()));
  • Exception
Exception e = new Exception("testandroid this is a log");  
That is, it is simplified to
new Exception("testandroid this is a log").printStackTrace();
  • RuntimeException
RuntimeException callStack = new RuntimeException("callstack:  ");  
Log.e(TAG, "testandroid this is a log: ", callStack);

Then let’s fight. First add the log in the launcher,
be careful:
The code I use in actual combat is the source code of Android 8.1, because I only have the development machine of this platform at present
Stack is not important, just look at the analysis method

@@ -350,6 +350,13 @@ public class Launcher extends BaseActivity
     protected void onCreate(Bundle savedInstanceState) {
+        RuntimeException callStack = new RuntimeException("callstack:  ");
+        callStack.fillInStackTrace();
+        Log.e(TAG,"testandroid this is a log: ", callStack);

The printed stack is as follows:

Launcher: testandroid this is a log: 
Launcher: java.lang.RuntimeException: callstack:
Launcher:  at com.android.launcher3.Launcher.onCreate(Launcher.java:354)
Launcher:  at android.app.Activity.performCreate(Activity.java:7082)
Launcher:  at android.app.Activity.performCreate(Activity.java:7073)
Launcher:  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1215)
Launcher:  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2737)
Launcher:  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2862)
Launcher:  at android.app.ActivityThread.-wrap11(Unknown Source:0)
Launcher:  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1595)
Launcher:  at android.os.Handler.dispatchMessage(Handler.java:106)
Launcher:  at android.os.Looper.loop(Looper.java:164)
//Activitythread. Main() function. Through the analysis of AMS startactivity() chapter, we can know that this function will be called after passing zyogote fork
Launcher:  at android.app.ActivityThread.main(ActivityThread.java:6524)
Launcher:  at java.lang.reflect.Method.invoke(Native Method)
Launcher:  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
Launcher:  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

When the first log was added, some problems were found,

Question 1:
Because our code has a startup wizard, it is found that oncreate() of the launcher is called only after the startup wizard is completed

I also added log in AMS starthomeactivitylocked(). Systemready() is called, but there is no oncreate() of the launcher. It only occurs after problem 1

I’ll finish the reverse analysis first and then look back at these two problems

From the above stack, the application has been transferred to activitythread. Main (). If you go along this analysis, it may be difficult. This requires some background knowledge
When analyzing AMS startactivity(), we know that the application will request zyogote fork application through zygoteprocess. Start(),

public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int runtimeFlags, int mountExternal,
                              int targetSdkVersion,
                              ......) {
    //Note that processclass is "Android. App. Activitythread"
    return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, zygoteArgs);

Strat() will call startviazygote() and we will add itStarting the application process call stack should be in the following places

    private Process.ProcessStartResult startViaZygote(final String processClass,....
+        RuntimeException callStack = new RuntimeException("callstack:  ");
+        callStack.fillInStackTrace();
         //Print out the nicename to see which application to start
+        Log.e(LOG_TAG, "testandroid this is a log: " + processClass + " niceName:" + niceName + " ", callStack);

Its stack is as follows

//Com.android.launcher3 launch
ZygoteProcess: testandroid this is a log: android.app.ActivityThread niceName:com.android.launcher3
ZygoteProcess: java.lang.RuntimeException: callstack:
ZygoteProcess:     at android.os.ZygoteProcess.startViaZygote(ZygoteProcess.java:346)
ZygoteProcess:     at android.os.ZygoteProcess.start(ZygoteProcess.java:208)
ZygoteProcess:     at android.os.Process.start(Process.java:462)
ZygoteProcess:     at com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:4007)
ZygoteProcess:     at com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:3829)
ZygoteProcess:     at com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:3715)
ZygoteProcess:     at com.android.server.am.ActivityStackSupervisor.startSpecificActivityLocked(ActivityStackSupervisor.java:1599)
ZygoteProcess:     at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:2755)
ZygoteProcess:     at com.android.server.am.ActivityStack.resumeTopActivityUncheckedLocked(ActivityStack.java:2268)
ZygoteProcess:     at com.android.server.am.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java:2102)
ZygoteProcess:     at com.android.server.am.ActivityStack.completePauseLocked(ActivityStack.java:1499)
ZygoteProcess:     at com.android.server.am.ActivityStack.activityPausedLocked(ActivityStack.java:1426)
// activityPaused
ZygoteProcess:     at com.android.server.am.ActivityManagerService.activityPaused(ActivityManagerService.java:7691)
//Binder communication, call stack broken
ZygoteProcess:     at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:317)
ZygoteProcess:     at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2980)

Here, ontransactd () is a binder communication, so you need to know who calls the binder function on the binder proxy side, and then add a log there

By searching the code, fortunately, there is only one place where you can add a log

private void handlePauseActivity(IBinder token, boolean finished,....
                  //Call activitypaused() to add logs here,

Because there is a handler in the middle, the stack information will be broken,For the stack break caused by handler message, we can only analyze the code to see who gave it in sendmessage()
The specific process will not be described in the log. The process is
schedulePauseActivity() --> sendMessage(PAUSE_ACTIVITY_FINISHING/PAUSE_ACTIVITY) --> handlePauseActivity() --> ActivityManager.getService().activityPaused(token);

Further stacks are as follows:

//It is called through activitystack.java schedulepauseactivity
ActivityManager: testandroid ActivityStack.java schedulePauseActivity java.lang.Throwable
ActivityManager:   at com.android.server.am.ActivityStack.startPausingLocked(ActivityStack.java:1359)
ActivityManager:   at com.android.server.am.ActivityStack.finishActivityLocked(ActivityStack.java:3821)
ActivityManager:   at com.android.server.am.ActivityStack.finishActivityLocked(ActivityStack.java:3763)
ActivityManager:   at com.android.server.am.ActivityStack.requestFinishActivityLocked(ActivityStack.java:3611)
//Who is calling finishactivity()?
ActivityManager:   at com.android.server.am.ActivityManagerService.finishActivity(ActivityManagerService.java:5283)

The last of the stack isfinishActivity()So who’s calling?
There are several places where finishactivity () can be called. You can add code in various places, and finally call finishactivity. Java finish ()
The code is as follows:

private void finish(int finishTask) {
            if (ActivityManager.getService()
                    .finishActivity(mToken, resultCode, resultData, finishTask)) {

The stack is as follows:

Activity.java finish()
System.err: java.lang.Exception: testandroid Activity.java finish
System.err:    at android.app.Activity.finish(Activity.java:5562)
System.err:    at android.app.Activity.finish(Activity.java:5600)
System.err:    at com.android.settings.FallbackHome.maybeFinish(FallbackHome.java:129)
System.err:    at com.android.settings.FallbackHome.-wrap0(Unknown Source:0)
System.err:    at com.android.settings.FallbackHome$1.onReceive(FallbackHome.java:106)

So far, we finally see thatFallbackhome onreceive() calls finish() before launching the launcher

Let’s look at the code (analysis and comments):

protected void onCreate(Bundle savedInstanceState) {
    //Registered the receiver unlocked by the user
    registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
    //Note that maybefinish here does not invoke the launcher

private BroadcastReceiver mReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        //After receiving the user unlock, call maybefinish ()

private void maybeFinish() {
    //Whether the user is unlocked. If the user is not unlocked during oncreate() -- > maybefinish(), nothing will be done
    if (getSystemService(UserManager.class).isUserUnlocked()) {
        final Intent homeIntent = new Intent(Intent.ACTION_MAIN)
            Log.d(TAG, "User unlocked and real home found; let's go!");
                    SystemClock.uptimeMillis(), false);
            //Call finish to end your activity

At this time, things became clearer,
Fallbackhome onreceive() calls finish() when receiving the user unlock broadcast, and starts the launcher only when its own activity exits

Does starthomeactivitylocked () have no effect at all when the launcher starts?

Logs found:

ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher} from uid 0

Then find the location of the code and find that there is actually a call through the print stack

ActivityManager: ActivityStarter.java testandroid this is a log:
ActivityManager: java.lang.RuntimeException: callstack:
ActivityManager:   at com.android.server.am.ActivityStarter.startActivity(ActivityStarter.java:331)
ActivityManager:   at com.android.server.am.ActivityStarter.startActivityLocked(ActivityStarter.java:283)
ActivityManager:   at com.android.server.am.ActivityStarter.startHomeActivityLocked(ActivityStarter.java:655)
ActivityManager:   at com.android.server.am.ActivityManagerService.startHomeActivityLocked(ActivityManagerService.java:4241)
ActivityManager:   at com.android.server.am.ActivityStackSupervisor.resumeHomeStackTask(ActivityStackSupervisor.java:781)
ActivityManager:   at com.android.server.am.ActivityStack.resumeTopActivityInNextFocusableStack(ActivityStack.java:2779)
ActivityManager:   at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:2326)
ActivityManager:   at com.android.server.am.ActivityStack.resumeTopActivityUncheckedLocked(ActivityStack.java:2268)
ActivityManager:   at com.android.server.am.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java:2107)
ActivityManager:   at com.android.server.am.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java:2091)
ActivityManager:   at com.android.server.am.ActivityStack.finishCurrentActivityLocked(ActivityStack.java:3943)
ActivityManager:   at com.android.server.am.ActivityStack.completePauseLocked(ActivityStack.java:1458)
ActivityManager:   at com.android.server.am.ActivityStack.activityPausedLocked(ActivityStack.java:1426)
ActivityManager:   at com.android.server.am.ActivityManagerService.activityPaused(ActivityManagerService.java:7686)
ActivityManager:   at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:317)
ActivityManager:   at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2980)


Let’s go back to question 1

Because our code has a startup wizard, it is found that oncreate() of the launcher is called only after the startup wizard is completed

The default startup wizard for Android is provision, and its code is also very simple, mainly
Set some database values — > disable yourself, and then you won’t find yourself when home intent — > end yourself

protected void onCreate(Bundle icicle) {
    Settings.Global.putInt(getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 1);
    Settings.Secure.putInt(getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 1);
    Settings.Secure.putInt(getContentResolver(), Settings.Secure.TV_USER_SETUP_COMPLETE, 1);

    // remove this activity from the package manager.
    //Disable the activity
    PackageManager pm = getPackageManager();
    ComponentName name = new ComponentName(this, DefaultActivity.class);
    pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,

    // terminate the activity.
    //End the activity

Home intent priority issues

AMS systemready() — > obtained when starthomeactivitylocked() is fallbackhome

boolean startHomeActivityLocked(int userId, String reason) {
    //Get home intent
    Intent intent = getHomeIntent();
    //Get which application the intent should start
    ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
    if (aInfo != null) {
            mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);

Log (there are other activities responding to home in the system, which are not listed here, mainly depending on these three):

ActivityManager: startHomeActivityLocked ?? act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.settings/.FallbackHome
//After the startup wizard is set, the defaultactivity will be disabled, and the startup will not match again
ActivityManager: startHomeActivityLocked ?? act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.provision/.DefaultActivity
ActivityManager: startHomeActivityLocked ?? act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher

But after looking at its priority setting,

<activity android:name=".FallbackHome"
    ... // fallbackhome priority - 1000
    <intent-filter android:priority="-1000">

<activity android:name="DefaultActivity"
... // defaultactivity priority 3
    <intent-filter android:priority="3">

Fallbackhome priority – 1000, minimum
Defaultactivity priority 3
Launcher3 is not set

Theoretically, when there is a boot wizard, it should match defaultactivity, and then restart should match launcher3,
So why is systemready() called fallbackhome, or why is fallbackhome always matched first?
Logically, it has the lowest priority and should be matched finally

The resolveactivityinfo() process is as follows:

resolveActivityInfo() / ActivityManagerService.java
  + AppGlobals.getPackageManager().resolveIntent()
      + resolveIntent() / PackageManagerService.java 
          + resolveIntentInternal()
              +Queryintentactivitiesinternal() // query all qualified activities
              |   + result = filterIfNotSystemUser(mActivities.queryIntent(.....))
              |       + super.queryIntent(....) / class ActivityIntentResolver
              |           + buildResolveList(....firstTypeCut, finalList, userId); / IntentResolver.java
              +Choosebestactivity() // select the best one

In the above process, all qualified activities will be queried first, and then the best one will be selected. If necessary, you can view the selection rules here
It was thought that defaultactivity / launcher3 was not the best when it was choosebestactivity(), and the log confirmed that there was only fallbackhome at the beginning of queryinntactivitiesinternal()

Direct start

After buildresolvelist (), you can take a brief look at the investigation process and comments, because the code is always changing and doesn’t make much sense. The main thing is to mention the following investigation results and findingsDirect startSuch a new thing to me

private void buildResolveList(Intent intent, FastImmutableArraySet<String> categories,
        boolean debug, boolean defaultOnly, String resolvedType, String scheme,
        F[] src, List<R> dest, int userId) {
        match = filter.match(action, resolvedType, scheme, data, categories, TAG);
        if (match >= 0) {
            //Open the log here and find that the fallbackhome defaultactivity launcher actually has a match at the beginning
            if (debug) Slog.v(TAG, "  Filter matched!  match=0x" +
                    Integer.toHexString(match) + " hasDefault="
                    + filter.hasCategory(Intent.CATEGORY_DEFAULT));
            if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {
                //But the last two return null
                final R oneResult = newResult(filter, match, userId);
                if (oneResult != null) {
                    //If it is not null, it will be added to dest

For activity intent, NEWRESULT is implemented in
final class ActivityIntentResolver
        extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {

    protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
            int match, int userId) {
        if (!sUserManager.exists(userId)) return null;
        //The return here is null, because defaultactivity will disable itself after setting, so it can be understood that it does not match when restarting,
        //But why did the launcher match after fallbackhome? You can continue the investigation
        if (!mSettings.isEnabledAndMatchLPr(info.activity.info, mFlags, userId)) {
            return null;

boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
    final PackageSetting ps = mPackages.get(componentInfo.packageName);
    if (ps == null) return false;

    final PackageUserState userState = ps.readUserState(userId);
    //False is returned here
    return userState.isMatch(componentInfo, flags);

public boolean isMatch(ComponentInfo componentInfo, int flags) {
    final boolean isSystemApp = componentInfo.applicationInfo.isSystemApp();
    final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
    if (!isAvailable(flags)
            && !(isSystemApp && matchUninstalled)) return false;
    //Enable judgment
    if (!isEnabled(componentInfo, flags)) return false;
    if ((flags & MATCH_SYSTEM_ONLY) != 0) {
        if (!isSystemApp) {
            return false;

    final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
            && !componentInfo.directBootAware;
    final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
            && componentInfo.directBootAware;
    //For the launcher, it returns false at the beginning of startup, and then returns true
    return matchesUnaware || matchesAware;

See the last direct_ BOOT_ UNAWARE DIRECT_ BOOT_ Aware componentinfo.directbootwar what is this?

This is actually the judgment of directly starting the application,

The direct startup data can be viewed as follows:
In short, it is a program that can run when unlocked, such as taking photos when unlocked

The setting of fallbackhome supports direct startup, but the launcher does not. Therefore, fallbackhome will always be matched first, and the launcher will have a chance to match after unlocking

<application android:label="@string/settings_label"
        ... // the settings of fallbackhome support direct startup      


  1. The response to home intent has priority, so when AMS systemready() calls start home, it does not necessarily start the launcher. It may be the launcher only after the home activities of other priorities respond
  2. Generally speaking, the launcher is started only when settings fallbackhome calls finish() to end itself after listening to the unlock
  3. Because the settings support direct startup, but the launcher does not, the launcher will not match the home intent when it is not unlocked
  4. Priority of some home intent
package activity priority
com.android.settings CryptKeeper 10
com.android.provision DefaultActivity 3
com.android.launcher3 Launcher default
com.android.settings FallbackHome -1000
  1. Android 11 AMS systemread() starthomeondisplay() process is simple:
public void systemReady(final Runnable goingCallback, @NonNull TimingsTraceAndSlog t) {
  +// goingcallback callback, where systemui will be started
  | if (goingCallback != null) goingCallback.run();
  + // start user
  | mSystemServiceManager.startUser(t, currentUserId);
  +// start the persistent application
  | startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
  +// start home on all screens, 
  | mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
  |// matminternal is of activitytaskmanagerinternal type, which is finally implemented in
  | // ActivityTaskManagerService.java
  + // final class LocalService extends ActivityTaskManagerInternal
      + mRootWindowContainer.startHomeOnDisplay(...) / ActivityTaskManagerService.java
          + startHomeOnTaskDisplayArea(...) / RootWindowContainer.java
              + if (taskDisplayArea == getDefaultTaskDisplayArea()) {
              |     homeIntent = mService.getHomeIntent();
              |// get the activity of the default screen home intent
              |     aInfo = resolveHomeActivity(userId, homeIntent);
              | } else if (shouldPlaceSecondaryHomeOnDisplayArea(taskDisplayArea)) {
              |// get the activity of home intent on the second screen
              |     Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, taskDisplayArea);
              + mService.getActivityStartController().startHomeActivity(...)
                  | ActivityStartController.java
                  | void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason,
                  |         TaskDisplayArea taskDisplayArea) {...
                  |// multi screen related, which screen to start to set
                  |     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();