From f13851d6c1019e158fa018aea97fee498e7d42d1 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 22 Aug 2019 10:51:11 -0700 Subject: [PATCH] Skip some duplicated tasks when booting from non-system user. When Automotive boots, CarServiceHelperService "restarts" the system user in the background, to unlock it. Consequently, some boot tasks will be executed twice (triggered from UserController.startUser() and ActivityManager.systemReady()). In the long term, refactoring the boot sequence on headless-system mode should avoid these duplicated events, but for now, we need to tackle them case by case. Test: manual verification # adding system.out statements on automotive Bug: 139502237 Bug: 128904478 Bug: 138956267 Change-Id: Idd8beedf1ea034b47b9756b91404c5a043965c23 --- .../server/am/ActivityManagerService.java | 23 +++++++++++-------- .../com/android/server/am/UserController.java | 11 +++++++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5c0fe4e8bcc24..84f5530f31bc0 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 @@ public class ActivityManagerService extends IActivityManager.Stub } 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 b2c40ef897aa6..c2e3fcb377792 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -1745,13 +1745,24 @@ class UserController implements Handler.Callback { } void sendBootCompleted(IIntentReceiver resultTo) { + final boolean systemUserFinishedBooting; + // Get a copy of mStartedUsers to use outside of lock SparseArray 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); } }