Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 94f1a7cf authored by BK Choi's avatar BK Choi Committed by Android (Google) Code Review
Browse files

Merge "Send user starting broadcast for non-automotive devices in HSUM." into udc-dev

parents eaff32e1 602f6f26
Loading
Loading
Loading
Loading
+6 −22
Original line number Diff line number Diff line
@@ -8613,7 +8613,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        // On Automotive / Headless System User Mode, at this point the system user has already been
        // started and unlocked, and some of the tasks we do here have already been done. So skip
        // those in that case. The duplicate system user start is guarded in SystemServiceManager.
        // TODO(b/242195409): this workaround shouldn't be necessary once we move the headless-user
        // TODO(b/266158156): this workaround shouldn't be necessary once we move the headless-user
        // start logic to UserManager-land.
        mUserController.onSystemUserStarting();
@@ -8646,7 +8646,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            // Some systems - like automotive - will explicitly unlock system user then switch
            // to a secondary user.
            // TODO(b/242195409): this workaround shouldn't be necessary once we move
            // TODO(b/266158156): this workaround shouldn't be necessary once we move
            // the headless-user start logic to UserManager-land.
            if (isBootingSystemUser && !UserManager.isHeadlessSystemUserMode()) {
                t.traceBegin("startHomeOnAllDisplays");
@@ -8669,26 +8669,10 @@ public class ActivityManagerService extends IActivityManager.Stub
                final int callingPid = Binder.getCallingPid();
                final long ident = Binder.clearCallingIdentity();
                try {
                    Intent intent = new Intent(Intent.ACTION_USER_STARTED);
                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                            | Intent.FLAG_RECEIVER_FOREGROUND);
                    intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
                    broadcastIntentLocked(null, null, null, intent,
                            null, null, 0, null, null, null, null, null, OP_NONE,
                            null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
                            currentUserId);
                    intent = new Intent(Intent.ACTION_USER_STARTING);
                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                    intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
                    broadcastIntentLocked(null, null, null, intent, null,
                            new IIntentReceiver.Stub() {
                                @Override
                                public void performReceive(Intent intent, int resultCode,
                                        String data, Bundle extras, boolean ordered, boolean sticky,
                                        int sendingUser) {}
                            }, 0, null, null, new String[] {INTERACT_ACROSS_USERS}, null, null,
                            OP_NONE, null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
                            UserHandle.USER_ALL);
                    mUserController.sendUserStartedBroadcast(
                            currentUserId, callingUid, callingPid);
                    mUserController.sendUserStartingBroadcast(
                            currentUserId, callingUid, callingPid);
                } catch (Throwable e) {
                    Slog.wtf(TAG, "Failed sending first user broadcasts", e);
                } finally {
+93 −31
Original line number Diff line number Diff line
@@ -365,13 +365,13 @@ class UserController implements Handler.Callback {
    private volatile ArraySet<String> mCurWaitingUserSwitchCallbacks;

    /**
     * Messages for for switching from {@link android.os.UserHandle#SYSTEM}.
     * Messages for switching from {@link android.os.UserHandle#SYSTEM}.
     */
    @GuardedBy("mLock")
    private String mSwitchingFromSystemUserMessage;

    /**
     * Messages for for switching to {@link android.os.UserHandle#SYSTEM}.
     * Messages for switching to {@link android.os.UserHandle#SYSTEM}.
     */
    @GuardedBy("mLock")
    private String mSwitchingToSystemUserMessage;
@@ -384,6 +384,16 @@ class UserController implements Handler.Callback {

    private final LockPatternUtils mLockPatternUtils;

    // TODO(b/266158156): remove this once we improve/refactor the way broadcasts are sent for
    //  the system user in HSUM.
    @GuardedBy("mLock")
    private boolean mIsBroadcastSentForSystemUserStarted;

    // TODO(b/266158156): remove this once we improve/refactor the way broadcasts are sent for
    //  the system user in HSUM.
    @GuardedBy("mLock")
    private boolean mIsBroadcastSentForSystemUserStarting;

    volatile boolean mBootCompleted;

    /**
@@ -635,7 +645,7 @@ class UserController implements Handler.Callback {
                // user transitions to RUNNING_LOCKED.  However, in "headless system user mode", the
                // system user is explicitly started before the device has finished booting.  In
                // that case, we need to wait until onBootComplete() to send the broadcast.
                if (!(UserManager.isHeadlessSystemUserMode() && uss.mHandle.isSystem())) {
                if (!(mInjector.isHeadlessSystemUserMode() && uss.mHandle.isSystem())) {
                    // ACTION_LOCKED_BOOT_COMPLETED
                    sendLockedBootCompletedBroadcast(resultTo, userId);
                }
@@ -1823,15 +1833,17 @@ class UserController implements Handler.Callback {
                needStart = false;
            }

            if (needStart) {
                // Send USER_STARTED broadcast
                Intent intent = new Intent(Intent.ACTION_USER_STARTED);
                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                        | Intent.FLAG_RECEIVER_FOREGROUND);
                intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                mInjector.broadcastIntent(intent,
                        null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                        null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid, userId);
            // In most cases, broadcast for the system user starting/started is sent by
            // ActivityManagerService#systemReady(). However on some HSUM devices (e.g. tablets)
            // the user switches from the system user to a secondary user while running
            // ActivityManagerService#systemReady(), thus broadcast is not sent for the system user.
            // Therefore we send the broadcast for the system user here as well in HSUM.
            // TODO(b/266158156): Improve/refactor the way broadcasts are sent for the system user
            // in HSUM. Ideally it'd be best to have one single place that sends this notification.
            final boolean isSystemUserInHeadlessMode = (userId == UserHandle.USER_SYSTEM)
                    && mInjector.isHeadlessSystemUserMode();
            if (needStart || isSystemUserInHeadlessMode) {
                sendUserStartedBroadcast(userId, callingUid, callingPid);
            }
            t.traceEnd();

@@ -1845,23 +1857,9 @@ class UserController implements Handler.Callback {
                t.traceEnd();
            }

            if (needStart) {
            if (needStart || isSystemUserInHeadlessMode) {
                t.traceBegin("sendRestartBroadcast");
                Intent intent = new Intent(Intent.ACTION_USER_STARTING);
                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                mInjector.broadcastIntent(intent,
                        null, new IIntentReceiver.Stub() {
                            @Override
                            public void performReceive(Intent intent, int resultCode,
                                    String data, Bundle extras, boolean ordered,
                                    boolean sticky,
                                    int sendingUser) throws RemoteException {
                            }
                        }, 0, null, null,
                        new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
                        null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
                        UserHandle.USER_ALL);
                sendUserStartingBroadcast(userId, callingUid, callingPid);
                t.traceEnd();
            }
        } finally {
@@ -2283,6 +2281,62 @@ class UserController implements Handler.Callback {
        EventLogTags.writeAmSwitchUser(newUserId);
    }

    // The two methods sendUserStartedBroadcast() and sendUserStartingBroadcast()
    // could be merged for better reuse. However, the params they are calling broadcastIntent()
    // with are different - resultCode receiver, permissions, ordered, and userId, etc. Therefore,
    // we decided to keep two separate methods for better code readability/clarity.
    // TODO(b/266158156): Improve/refactor the way broadcasts are sent for the system user
    // in HSUM. Ideally it'd be best to have one single place that sends this notification.
    /** Sends {@code ACTION_USER_STARTED} broadcast. */
    void sendUserStartedBroadcast(@UserIdInt int userId, int callingUid, int callingPid) {
        if (userId == UserHandle.USER_SYSTEM) {
            synchronized (mLock) {
                // Make sure that the broadcast is sent only once for the system user.
                if (mIsBroadcastSentForSystemUserStarted) {
                    return;
                }
                mIsBroadcastSentForSystemUserStarted = true;
            }
        }
        final Intent intent = new Intent(Intent.ACTION_USER_STARTED);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                | Intent.FLAG_RECEIVER_FOREGROUND);
        intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
        mInjector.broadcastIntent(intent, /* resolvedType= */ null, /* resultTo= */ null,
                /* resultCode= */ 0, /* resultData= */ null, /* resultExtras= */ null,
                /* requiredPermissions= */ null, AppOpsManager.OP_NONE, /* bOptions= */ null,
                /* ordered= */ false, /* sticky= */ false, MY_PID, SYSTEM_UID,
                callingUid, callingPid, userId);
    }

    /** Sends {@code ACTION_USER_STARTING} broadcast. */
    void sendUserStartingBroadcast(@UserIdInt int userId, int callingUid, int callingPid) {
        if (userId == UserHandle.USER_SYSTEM) {
            synchronized (mLock) {
                // Make sure that the broadcast is sent only once for the system user.
                if (mIsBroadcastSentForSystemUserStarting) {
                    return;
                }
                mIsBroadcastSentForSystemUserStarting = true;
            }
        }
        final Intent intent = new Intent(Intent.ACTION_USER_STARTING);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
        intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
        mInjector.broadcastIntent(intent, /* resolvedType= */ null,
                new IIntentReceiver.Stub() {
                    @Override
                    public void performReceive(Intent intent, int resultCode,
                            String data, Bundle extras, boolean ordered,
                            boolean sticky,
                            int sendingUser) throws RemoteException {
                    }
                }, /* resultCode= */ 0, /* resultData= */ null, /* resultExtras= */ null,
                new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE, /* bOptions= */ null,
                /* ordered= */ true, /* sticky= */ false, MY_PID, SYSTEM_UID,
                callingUid, callingPid, UserHandle.USER_ALL);
    }

    void sendUserSwitchBroadcasts(int oldUserId, int newUserId) {
        final int callingUid = Binder.getCallingUid();
        final int callingPid = Binder.getCallingPid();
@@ -2568,7 +2622,7 @@ class UserController implements Handler.Callback {
        for (int i = 0; i < startedUsers.size(); i++) {
            int userId = startedUsers.keyAt(i);
            UserState uss = startedUsers.valueAt(i);
            if (!UserManager.isHeadlessSystemUserMode()) {
            if (!mInjector.isHeadlessSystemUserMode()) {
                finishUserBoot(uss, resultTo);
            } else {
                if (userId == UserHandle.USER_SYSTEM) {
@@ -2589,9 +2643,9 @@ class UserController implements Handler.Callback {
        mInjector.reportCurWakefulnessUsageEvent();
    }

    // TODO(b/242195409): remove this method if initial system user boot logic is refactored?
    // TODO(b/266158156): remove this method if initial system user boot logic is refactored?
    void onSystemUserStarting() {
        if (!UserManager.isHeadlessSystemUserMode()) {
        if (!mInjector.isHeadlessSystemUserMode()) {
            // Don't need to call on HSUM because it will be called when the system user is
            // restarted on background
            mInjector.onUserStarting(UserHandle.USER_SYSTEM);
@@ -3059,6 +3113,10 @@ class UserController implements Handler.Callback {
            pw.println("  mMaxRunningUsers:" + mMaxRunningUsers);
            pw.println("  mUserSwitchUiEnabled:" + mUserSwitchUiEnabled);
            pw.println("  mInitialized:" + mInitialized);
            pw.println("  mIsBroadcastSentForSystemUserStarted:"
                    + mIsBroadcastSentForSystemUserStarted);
            pw.println("  mIsBroadcastSentForSystemUserStarting:"
                    + mIsBroadcastSentForSystemUserStarting);
            if (mSwitchingFromSystemUserMessage != null) {
                pw.println("  mSwitchingFromSystemUserMessage: " + mSwitchingFromSystemUserMessage);
            }
@@ -3749,6 +3807,10 @@ class UserController implements Handler.Callback {
            }, /* message= */ null);
        }

        boolean isHeadlessSystemUserMode() {
            return UserManager.isHeadlessSystemUserMode();
        }

        boolean isUsersOnSecondaryDisplaysEnabled() {
            return UserManager.isVisibleBackgroundUsersEnabled();
        }
+30 −0
Original line number Diff line number Diff line
@@ -133,6 +133,7 @@ public class UserControllerTest {
    private static final int TEST_USER_ID1 = 101;
    private static final int TEST_USER_ID2 = 102;
    private static final int TEST_USER_ID3 = 103;
    private static final int SYSTEM_USER_ID = UserHandle.SYSTEM.getIdentifier();
    private static final int NONEXIST_USER_ID = 2;
    private static final int TEST_PRE_CREATED_USER_ID = 103;

@@ -230,6 +231,31 @@ public class UserControllerTest {
        verifyUserAssignedToDisplay(TEST_USER_ID, Display.DEFAULT_DISPLAY);
    }

    @Test
    public void testStartUser_sendsNoBroadcastsForSystemUserInNonHeadlessMode() {
        setUpUser(SYSTEM_USER_ID, UserInfo.FLAG_SYSTEM, /* preCreated= */ false,
                UserManager.USER_TYPE_FULL_SYSTEM);
        mockIsHeadlessSystemUserMode(false);

        mUserController.startUser(SYSTEM_USER_ID, USER_START_MODE_FOREGROUND);

        assertWithMessage("Broadcasts for starting the system user in non-headless mode")
                .that(mInjector.mSentIntents).isEmpty();
    }

    @Test
    public void testStartUser_sendsBroadcastsForSystemUserInHeadlessMode() {
        setUpUser(SYSTEM_USER_ID, UserInfo.FLAG_SYSTEM, /* preCreated= */ false,
                UserManager.USER_TYPE_SYSTEM_HEADLESS);
        mockIsHeadlessSystemUserMode(true);

        mUserController.startUser(SYSTEM_USER_ID, USER_START_MODE_FOREGROUND);

        assertWithMessage("Broadcasts for starting the system user in headless mode")
                .that(getActions(mInjector.mSentIntents)).containsExactly(
                        Intent.ACTION_USER_STARTED, Intent.ACTION_USER_STARTING);
    }

    @Test
    public void testStartUser_displayAssignmentFailed() {
        doReturn(UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE)
@@ -999,6 +1025,10 @@ public class UserControllerTest {
        }
    }

    private void mockIsHeadlessSystemUserMode(boolean value) {
        when(mInjector.isHeadlessSystemUserMode()).thenReturn(value);
    }

    private void mockIsUsersOnSecondaryDisplaysEnabled(boolean value) {
        when(mInjector.isUsersOnSecondaryDisplaysEnabled()).thenReturn(value);
    }