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

Commit 16ff8bfa authored by Adam Bookatz's avatar Adam Bookatz
Browse files

Reschedule bg stop if profile has alarm/audio

We avoid stopping a background user if it is playing audio or has an
upcoming alarm. But, currently, if its profile has audio/alarm, we still
may stop the parent, which will automatically stop the profile too.
We now make sure that if the profile shouldn't be stopped, we also don't
stop the parent (and therefore don't wind up indirectly stopping the
profile).

Bug: 401340391
Bug: 330351042
Test: UserControllerTest
Flag: android.multiuser.schedule_stop_of_background_user
Change-Id: I2341891ff193cbbb86cb2b0371e3a7b858c020bb
parent 0d9fb182
Loading
Loading
Loading
Loading
+33 −9
Original line number Diff line number Diff line
@@ -2720,18 +2720,13 @@ class UserController implements Handler.Callback {
            Slogf.i(TAG, "User %d is scheduled for bg stopping later, so wait until then", userId);
            return;
        }
        if (avoidStoppingUserDueToUpcomingAlarm(userId)) {
            // We want this user running soon for alarm-purposes, so don't stop it now. Reschedule.
            Slogf.d(TAG, "User %d will fire an alarm soon, so reschedule bg stopping", userId);
            rescheduleStopOfBackgroundUser(userId);
            return;
        }
        if (mInjector.getAudioManagerInternal().isUserPlayingAudio(userId)) {
            // User is audible (even if invisibly, e.g. via an alarm), so don't stop it. Reschedule.
            Slogf.d(TAG, "User %d is playing audio, so reschedule bg stopping", userId);
        if (avoidStoppingUserRightNow(userId)) {
            Slogf.d(TAG, "Rescheduling bg stopping of user %d because it (or its profile) should "
                    + "not be stopped right now ", userId);
            rescheduleStopOfBackgroundUser(userId);
            return;
        }

        synchronized (mLock) {
            if (getCurrentOrTargetUserIdLU() == userId) {
                // User is (somehow) already in the foreground, or we're currently switching to it.
@@ -2754,6 +2749,35 @@ class UserController implements Handler.Callback {
        }
    }

    /**
     * Returns whether to avoid stopping the given user because, even though it may only be in the
     * background, it (or {@link #getUsersToStopLU(int) a user that would stop if it stopped}) is
     * still currently useful (e.g. playing audio, or has an upcoming alarm).
     *
     * Makes requests of other services, so don't call while holding a lock.
     */
    private boolean avoidStoppingUserRightNow(@UserIdInt int userId) {
        final int[] usersThatWouldStop;
        synchronized (mLock) {
            usersThatWouldStop = getUsersToStopLU(userId);
        }
        for (int relatedUserId : usersThatWouldStop) {
            if (avoidStoppingUserDueToUpcomingAlarm(relatedUserId)) {
                // We want this user running soon for alarm-purposes, so don't stop it now.
                Slogf.d(TAG, "Avoid stopping user %d because user %d will fire an alarm soon",
                        userId, relatedUserId);
                return true;
            }
            if (mInjector.getAudioManagerInternal().isUserPlayingAudio(relatedUserId)) {
                // User is audible (even if invisibly, e.g. via an alarm), so don't stop it.
                Slogf.d(TAG, "Avoid stopping user %d because user %d is playing audio",
                        userId, relatedUserId);
                return true;
            }
        }
        return false;
    }

    /**
     * Returns whether we should avoid stopping the user now due to it having an alarm set to fire
     * soon.