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

Commit d5647900 authored by Adam Bodnar's avatar Adam Bodnar
Browse files

Ensure the game mode setting doesn't conflict with available modes

If for any reason a game no longer supports a game mode, we need to make
sure we reset the configured mode in the user settings.

Bug: b/187082027

Test: atest com.android.server.app.GameManagerServiceTests

Change-Id: I73e4f71172ee84913431ed3c20ec420c04dcdbe4
parent 25ad0530
Loading
Loading
Loading
Loading
+76 −17
Original line number Diff line number Diff line
@@ -56,7 +56,6 @@ import android.os.ShellCallback;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.KeyValueListParser;
import android.util.Slog;

@@ -363,19 +362,42 @@ public final class GameManagerService extends IGameManagerService.Stub {
                    || (mPerfModeOptedIn && gameMode == GameManager.GAME_MODE_PERFORMANCE);
        }

        public @GameMode int[] getAvailableGameModes() {
            ArraySet<Integer> modeSet = new ArraySet<>(mModeConfigs.keySet());
        private int getAvailableGameModesBitfield() {
            int field = 0;
            for (final int mode : mModeConfigs.keySet()) {
                field |= modeToBitmask(mode);
            }
            if (mBatteryModeOptedIn) {
                modeSet.add(GameManager.GAME_MODE_BATTERY);
                field |= modeToBitmask(GameManager.GAME_MODE_BATTERY);
            }
            if (mPerfModeOptedIn) {
                modeSet.add(GameManager.GAME_MODE_PERFORMANCE);
                field |= modeToBitmask(GameManager.GAME_MODE_PERFORMANCE);
            }
            // The lowest bit is reserved for UNSUPPORTED, STANDARD is supported if we support any
            // other mode.
            if (field > 1) {
                field |= modeToBitmask(GameManager.GAME_MODE_STANDARD);
            } else {
                field |= modeToBitmask(GameManager.GAME_MODE_UNSUPPORTED);
            }
            if (modeSet.size() > 0) {
                modeSet.add(GameManager.GAME_MODE_STANDARD);
                return modeSet.stream().mapToInt(Integer::intValue).toArray();
            return field;
        }
            return new int[]{GameManager.GAME_MODE_UNSUPPORTED};

        /**
         * Get an array of a package's available game modes.
         */
        public @GameMode int[] getAvailableGameModes() {

            int modesBitfield = getAvailableGameModesBitfield();
            int sigBits = Integer.bitCount(modesBitfield);
            int[] modes = new int[sigBits];
            int i = 0;
            for (int mode = 0; mode < sigBits; ++mode) {
                if (((modesBitfield >> mode) & 1) != 0) {
                    modes[i++] = mode;
                }
            }
            return modes;
        }

        /**
@@ -696,6 +718,14 @@ public final class GameManagerService extends IGameManagerService.Stub {
        }
    }

    private int modeToBitmask(@GameMode int gameMode) {
        return (1 << gameMode);
    }

    private boolean bitFieldContainsModeBitmask(int bitField, @GameMode int gameMode) {
        return (bitField & modeToBitmask(gameMode)) != 0;
    }

    /**
     * @hide
     */
@@ -703,8 +733,8 @@ public final class GameManagerService extends IGameManagerService.Stub {
    public void updateConfigsForUser(int userId, String ...packageNames) {
        try {
            synchronized (mDeviceConfigLock) {
                for (String packageName : packageNames) {
                    GamePackageConfiguration config =
                for (final String packageName : packageNames) {
                    final GamePackageConfiguration config =
                            new GamePackageConfiguration(packageName, userId);
                    if (config.isValid()) {
                        if (DEBUG) {
@@ -718,13 +748,42 @@ public final class GameManagerService extends IGameManagerService.Stub {
                    }
                }
            }
            for (String packageName : packageNames) {
                synchronized (mLock) {
            for (final String packageName : packageNames) {
                if (mSettings.containsKey(userId)) {
                        GameManagerSettings userSettings = mSettings.get(userId);
                        updateCompatModeDownscale(packageName,
                                userSettings.getGameModeLocked(packageName));
                    int gameMode = getGameMode(packageName, userId);
                    int newGameMode = gameMode;
                    // Make sure the user settings and package configs don't conflict. I.e. the
                    // user setting is set to a mode that no longer available due to config/manifest
                    // changes. Most of the time we won't have to change anything.
                    GamePackageConfiguration config;
                    synchronized (mDeviceConfigLock) {
                        config = mConfigs.get(packageName);
                    }
                    if (config != null) {
                        int modesBitfield = config.getAvailableGameModesBitfield();
                        // Remove UNSUPPORTED to simplify the logic here, since we really just
                        // want to check if we support selectable game modes
                        modesBitfield &= ~modeToBitmask(GameManager.GAME_MODE_UNSUPPORTED);
                        if (!bitFieldContainsModeBitmask(modesBitfield, gameMode)) {
                            if (bitFieldContainsModeBitmask(modesBitfield,
                                    GameManager.GAME_MODE_STANDARD)) {
                                // If the current set mode isn't supported, but we support STANDARD,
                                // then set the mode to STANDARD.
                                newGameMode = GameManager.GAME_MODE_STANDARD;
                            } else {
                                // If we don't support any game modes, then set to UNSUPPORTED
                                newGameMode = GameManager.GAME_MODE_UNSUPPORTED;
                            }
                        }
                    } else if (gameMode != GameManager.GAME_MODE_UNSUPPORTED) {
                        // If we have no config for the package, but the configured mode is not
                        // UNSUPPORTED, then set to UNSUPPORTED
                        newGameMode = GameManager.GAME_MODE_UNSUPPORTED;
                    }
                    if (newGameMode != gameMode) {
                        setGameMode(packageName, newGameMode, userId);
                    }
                    updateCompatModeDownscale(packageName, gameMode);
                }
            }
        } catch (Exception e) {
+56 −4
Original line number Diff line number Diff line
@@ -299,11 +299,13 @@ public class GameManagerServiceTests {
    public void testGameMode() {
        GameManagerService gameManagerService = new GameManagerService(mMockContext);
        gameManagerService.onUserStarting(USER_ID_1);

        gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
        mockModifyGameModeGranted();

        assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
                gameManagerService.getGameMode(mPackageName, USER_ID_1));
        // We need to make sure the mode is supported before setting it.
        mockDeviceConfigAll();
        gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
        gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1);
        assertEquals(GameManager.GAME_MODE_STANDARD,
                gameManagerService.getGameMode(mPackageName, USER_ID_1));
@@ -370,11 +372,13 @@ public class GameManagerServiceTests {
     */
    @Test
    public void testGameModeMultipleUsers() {
        mockModifyGameModeGranted();
        mockDeviceConfigAll();
        GameManagerService gameManagerService = new GameManagerService(mMockContext);
        gameManagerService.onUserStarting(USER_ID_1);
        gameManagerService.onUserStarting(USER_ID_2);

        mockModifyGameModeGranted();
        gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
        gameManagerService.updateConfigsForUser(USER_ID_2, mPackageName);

        // Set User 1 to Standard
        gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1);
@@ -603,4 +607,52 @@ public class GameManagerServiceTests {
                gameManagerService.getConfig(mPackageName);
        assertNull(config.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE));
    }

    /**
     * Ensure that, if a game no longer supports any game modes, we set the game mode to
     * UNSUPPORTED
     */
    @Test
    public void testUnsetInvalidGameMode() throws Exception {
        mockDeviceConfigNone();
        mockModifyGameModeGranted();
        GameManagerService gameManagerService = new GameManagerService(mMockContext);
        gameManagerService.onUserStarting(USER_ID_1);
        gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
        gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
        assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
                gameManagerService.getGameMode(mPackageName, USER_ID_1));
    }

    /**
     * Ensure that, if a game no longer supports a specific game mode, but supports STANDARD, we set
     * the game mode to STANDARD.
     */
    @Test
    public void testResetInvalidGameMode() throws Exception {
        mockDeviceConfigPerformance();
        mockModifyGameModeGranted();
        GameManagerService gameManagerService = new GameManagerService(mMockContext);
        gameManagerService.onUserStarting(USER_ID_1);
        gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1);
        gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
        assertEquals(GameManager.GAME_MODE_STANDARD,
                gameManagerService.getGameMode(mPackageName, USER_ID_1));
    }

    /**
     * Ensure that if a game supports STANDARD, but is currently set to UNSUPPORTED, we set the game
     * mode to STANDARD
     */
    @Test
    public void testSetValidGameMode() throws Exception {
        mockDeviceConfigPerformance();
        mockModifyGameModeGranted();
        GameManagerService gameManagerService = new GameManagerService(mMockContext);
        gameManagerService.onUserStarting(USER_ID_1);
        gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_UNSUPPORTED, USER_ID_1);
        gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
        assertEquals(GameManager.GAME_MODE_STANDARD,
                gameManagerService.getGameMode(mPackageName, USER_ID_1));
    }
}