Merge "Skip some duplicated tasks when booting from non-system user."
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5c0fe4e..84f5530 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9154,20 +9154,25 @@
                 }
                 t.traceEnd();
             }
-            t.traceBegin("startHomeOnAllDisplays");
-            mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
-            t.traceEnd();
+            // Automotive will re-start system user as background (so its unlocked), then start a
+            // full user as foreground. Hence, we need to skip some steps that would otherwise be
+            // done twice.
+            // TODO(b/138956267): this workdound shouldn't be necessary once we move the
+            // headless-user start logic to UserManager-land
+            final boolean bootingSystemUser = currentUserId == UserHandle.USER_SYSTEM;
+
+            if (bootingSystemUser) {
+                t.traceBegin("startHomeOnAllDisplays");
+                mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
+                t.traceEnd();
+            }
 
             t.traceBegin("showSystemReadyErrorDialogs");
             mAtmInternal.showSystemReadyErrorDialogsIfNeeded();
             t.traceEnd();
 
-            // Some systems - like automotive - will explicitly unlock system user then switch
-            // to a secondary user. Hence, we don't want to send duplicate broadcasts for the
-            // system user here.
-            boolean sendSystemUserBroadcasts = currentUserId == UserHandle.USER_SYSTEM;
 
-            if (sendSystemUserBroadcasts) {
+            if (bootingSystemUser) {
                 t.traceBegin("sendUserStartBroadcast");
                 final int callingUid = Binder.getCallingUid();
                 final int callingPid = Binder.getCallingPid();
@@ -9208,7 +9213,7 @@
             mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
             t.traceEnd();
 
-            if (sendSystemUserBroadcasts) {
+            if (bootingSystemUser) {
                 t.traceBegin("sendUserSwitchBroadcasts");
                 mUserController.sendUserSwitchBroadcasts(-1, currentUserId);
                 t.traceEnd();
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 8448042..2b4cc3c 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1744,13 +1744,24 @@
     }
 
     void sendBootCompleted(IIntentReceiver resultTo) {
+        final boolean systemUserFinishedBooting;
+
         // Get a copy of mStartedUsers to use outside of lock
         SparseArray<UserState> startedUsers;
         synchronized (mLock) {
+            systemUserFinishedBooting = mCurrentUserId != UserHandle.USER_SYSTEM;
             startedUsers = mStartedUsers.clone();
         }
         for (int i = 0; i < startedUsers.size(); i++) {
             UserState uss = startedUsers.valueAt(i);
+            if (systemUserFinishedBooting && uss.mHandle.isSystem()) {
+                // Automotive will re-start system user as background, which in turn will call
+                // finishUserboot(). Hence, we need to check it here to avoid calling it twice.
+                // TODO(b/138956267): this workdound shouldn't be necessary once we move the
+                // headless-user start logic to UserManager-land
+                Slog.d(TAG, "sendBootCompleted(): skipping on non-current system user");
+                continue;
+            }
             finishUserBoot(uss, resultTo);
         }
     }