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

Commit 07dcf25b authored by Felipe Leme's avatar Felipe Leme
Browse files

Added options to not stop previous users on switch.

On automotive (or on any device that sets
config_multiuserDelayUserDataLocking to true), the current foreground
user and its profiles are stopped when the system switches to a
different user, which causes CTS tests that switch users to fail (as
the test process dies when the user is switched).

This CL addes a new system property (fw.stop_bg_users_on_switch) that
allow tests to override this behavior. It also:

- Splits mDelayUserDataLocking logic into 2 variables (the other is
  mStopBackgroundUsersOnSwitch, which is the one that can be changed)
- Adds more optional logging.

Test: adb shell setprop fw.stop_bg_users_on_switch 0 && \
adb shell dumpsys activity users | grep shouldStopBackgroundUsersOnSwitch
Test: atest android.car.apitest.CarUserManagerTest#testLifecycleListener

Bug: 180515783
Bug: 180515783

Change-Id: I02bbe7b502c94f02a94965b8ff25915b6b55ae1b
parent 5a347637
Loading
Loading
Loading
Loading
+34 −18
Original line number Diff line number Diff line
@@ -334,13 +334,15 @@ class UserController implements Handler.Callback {
    volatile boolean mBootCompleted;

    /**
     * In this mode, user is always stopped when switched out but locking of user data is
     * In this mode, user is always stopped when switched out (unless overridden by the
     * {@code fw.stop_bg_users_on_switch} system property) but locking of user data is
     * postponed until total number of unlocked users in the system reaches mMaxRunningUsers.
     * Once total number of unlocked users reach mMaxRunningUsers, least recently used user
     * will be locked.
     */
    @GuardedBy("mLock")
    private boolean mDelayUserDataLocking;

    /**
     * Keep track of last active users for mDelayUserDataLocking.
     * The latest stopped user is placed in front while the least recently stopped user in back.
@@ -406,10 +408,9 @@ class UserController implements Handler.Callback {
        }
    }

    private boolean isDelayUserDataLockingEnabled() {
        synchronized (mLock) {
            return mDelayUserDataLocking;
        }
    private boolean shouldStopBackgroundUsersOnSwitch() {
        int property = SystemProperties.getInt("fw.stop_bg_users_on_switch", -1);
        return property == -1 ? mDelayUserDataLocking : property == 1;
    }

    void finishUserSwitch(UserState uss) {
@@ -1041,6 +1042,11 @@ class UserController implements Handler.Callback {

    void finishUserStopped(UserState uss, boolean allowDelayedLocking) {
        final int userId = uss.mHandle.getIdentifier();
        if (DEBUG_MU) {
            Slog.i(TAG, "finishUserStopped(%d): allowDelayedLocking=%b", userId,
                    allowDelayedLocking);
        }

        EventLog.writeEvent(EventLogTags.UC_FINISH_USER_STOPPED, userId);
        final boolean stopped;
        boolean lockUser = true;
@@ -1153,11 +1159,9 @@ class UserController implements Handler.Callback {
                Slog.i(TAG, "finishUserStopped, stopping user:" + userId
                        + " lock user:" + userIdToLock);
            } else {
                Slog.i(TAG, "finishUserStopped, user:" + userId
                        + ",skip locking");
                Slog.i(TAG, "finishUserStopped, user:" + userId + ", skip locking");
                // do not lock
                userIdToLock = UserHandle.USER_NULL;

            }
        }
        return userIdToLock;
@@ -1192,6 +1196,7 @@ class UserController implements Handler.Callback {
    }

    private void forceStopUser(@UserIdInt int userId, String reason) {
        if (DEBUG_MU) Slog.i(TAG, "forceStopUser(%d): %s", userId, reason);
        mInjector.activityManagerForceStopPackage(userId, reason);
        if (mInjector.getUserManager().isPreCreated(userId)) {
            // Don't fire intent for precreated.
@@ -1370,6 +1375,7 @@ class UserController implements Handler.Callback {

    private boolean startUserInternal(@UserIdInt int userId, boolean foreground,
            @Nullable IProgressListener unlockListener, @NonNull TimingsTraceAndSlog t) {
        if (DEBUG_MU) Slog.i(TAG, "Starting user %d%s", userId, foreground ? " in foreground" : "");
        EventLog.writeEvent(EventLogTags.UC_START_USER_INTERNAL, userId);

        final int callingUid = Binder.getCallingUid();
@@ -1790,20 +1796,28 @@ class UserController implements Handler.Callback {
        mUserSwitchObservers.finishBroadcast();
    }

    private void stopBackgroundUsersIfEnforced(int oldUserId) {
    private void stopBackgroundUsersOnSwitchIfEnforced(@UserIdInt int oldUserId) {
        // Never stop system user
        if (oldUserId == UserHandle.USER_SYSTEM) {
            return;
        }
        // If running in background is disabled or mDelayUserDataLocking mode, stop the user.
        boolean disallowRunInBg = hasUserRestriction(UserManager.DISALLOW_RUN_IN_BACKGROUND,
                oldUserId) || isDelayUserDataLockingEnabled();
        boolean hasRestriction =
                hasUserRestriction(UserManager.DISALLOW_RUN_IN_BACKGROUND, oldUserId);
        synchronized (mLock) {
            // If running in background is disabled or mStopBackgroundUsersOnSwitch mode,
            // stop the user.
            boolean disallowRunInBg = hasRestriction || shouldStopBackgroundUsersOnSwitch();
            if (!disallowRunInBg) {
                if (DEBUG_MU) {
                    Slog.i(TAG, "stopBackgroundUsersIfEnforced() NOT stopping %d and related users",
                            oldUserId);
                }
                return;
            }
        synchronized (mLock) {
            if (DEBUG_MU) Slog.i(TAG, "stopBackgroundUsersIfEnforced stopping " + oldUserId
                    + " and related users");
            if (DEBUG_MU) {
                Slog.i(TAG, "stopBackgroundUsersIfEnforced() stopping %d and related users",
                        oldUserId);
            }
            stopUsersLU(oldUserId, /* force= */ false, /* allowDelayedLocking= */ true,
                    null, null);
        }
@@ -1904,7 +1918,7 @@ class UserController implements Handler.Callback {
        mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
        mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG, newUserId, 0));
        stopGuestOrEphemeralUserIfBackground(oldUserId);
        stopBackgroundUsersIfEnforced(oldUserId);
        stopBackgroundUsersOnSwitchIfEnforced(oldUserId);
    }

    private void moveUserToForeground(UserState uss, int oldUserId, int newUserId) {
@@ -2594,6 +2608,8 @@ class UserController implements Handler.Callback {
            pw.println("  mTargetUserId:" + mTargetUserId);
            pw.println("  mLastActiveUsers:" + mLastActiveUsers);
            pw.println("  mDelayUserDataLocking:" + mDelayUserDataLocking);
            pw.println("  shouldStopBackgroundUsersOnSwitch:"
                    + shouldStopBackgroundUsersOnSwitch());
            pw.println("  mMaxRunningUsers:" + mMaxRunningUsers);
            pw.println("  mUserSwitchUiEnabled:" + mUserSwitchUiEnabled);
            pw.println("  mInitialized:" + mInitialized);