From 8e04d2c1007fa621e7df87be2d12e5f31a27212c Mon Sep 17 00:00:00 2001 From: Xiang Wang Date: Tue, 2 Aug 2022 11:02:46 -0700 Subject: [PATCH 1/4] Check if it's game package before updating configs Rename "invalid config" to "inactive config and gate the warning behind DEBUG flag, as it's expected for games to opt in game modes Bug: b/240335717 Test: atest GameManagerServiceTests Change-Id: I0aae9bb4c68e01a8d4797fd6595535467f7d1fe6 Merged-In: I0aae9bb4c68e01a8d4797fd6595535467f7d1fe6 --- .../server/app/GameManagerService.java | 30 ++++++++++++------- .../server/app/GameManagerServiceTests.java | 26 ++++++++-------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index 15c569e246f7c..9a40a61ec3632 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -333,7 +333,7 @@ public final class GameManagerService extends IGameManagerService.Stub { removeMessages(POPULATE_GAME_MODE_SETTINGS, msg.obj); final int userId = (int) msg.obj; final String[] packageNames = getInstalledGamePackageNames(userId); - updateConfigsForUser(userId, packageNames); + updateConfigsForUser(userId, false /*checkGamePackage*/, packageNames); break; } case SET_GAME_STATE: { @@ -402,7 +402,8 @@ public final class GameManagerService extends IGameManagerService.Stub { @Override public void onPropertiesChanged(Properties properties) { final String[] packageNames = properties.getKeyset().toArray(new String[0]); - updateConfigsForUser(ActivityManager.getCurrentUser(), packageNames); + updateConfigsForUser(ActivityManager.getCurrentUser(), true /*checkGamePackage*/, + packageNames); } @Override @@ -717,7 +718,7 @@ public final class GameManagerService extends IGameManagerService.Stub { mFps = fpsStr; } - public boolean isValid() { + public boolean isActive() { return (mGameMode == GameManager.GAME_MODE_STANDARD || mGameMode == GameManager.GAME_MODE_PERFORMANCE || mGameMode == GameManager.GAME_MODE_BATTERY) @@ -809,15 +810,15 @@ public final class GameManagerService extends IGameManagerService.Stub { * Insert a new GameModeConfiguration */ public void addModeConfig(GameModeConfiguration config) { - if (config.isValid()) { + if (config.isActive()) { mModeConfigs.put(config.getGameMode(), config); } else { - Slog.w(TAG, "Invalid game mode config for " + Slog.w(TAG, "Attempt to add inactive game mode config for " + mPackageName + ":" + config.toString()); } } - public boolean isValid() { + public boolean isActive() { return mModeConfigs.size() > 0 || mBatteryModeOptedIn || mPerfModeOptedIn; } @@ -1569,20 +1570,27 @@ public final class GameManagerService extends IGameManagerService.Stub { * @hide */ @VisibleForTesting - void updateConfigsForUser(@UserIdInt int userId, String... packageNames) { + void updateConfigsForUser(@UserIdInt int userId, boolean checkGamePackage, + String... packageNames) { + if (checkGamePackage) { + packageNames = Arrays.stream(packageNames).filter( + p -> isPackageGame(p, userId)).toArray(String[]::new); + } try { synchronized (mDeviceConfigLock) { for (final String packageName : packageNames) { final GamePackageConfiguration config = new GamePackageConfiguration(packageName, userId); - if (config.isValid()) { + if (config.isActive()) { if (DEBUG) { Slog.i(TAG, "Adding config: " + config.toString()); } mConfigs.put(packageName, config); } else { - Slog.w(TAG, "Invalid package config for " - + config.getPackageName() + ":" + config.toString()); + if (DEBUG) { + Slog.w(TAG, "Inactive package config for " + + config.getPackageName() + ":" + config.toString()); + } mConfigs.remove(packageName); } } @@ -1760,7 +1768,7 @@ public final class GameManagerService extends IGameManagerService.Stub { } switch (intent.getAction()) { case ACTION_PACKAGE_ADDED: - updateConfigsForUser(userId, packageName); + updateConfigsForUser(userId, true /*checkGamePackage*/, packageName); break; case ACTION_PACKAGE_REMOVED: disableCompatScale(packageName); diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java index d675b0aa4973a..d325e47f76879 100644 --- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java @@ -450,13 +450,13 @@ public class GameManagerServiceTests { startUser(gameManagerService, USER_ID_1); - gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName); + gameManagerService.updateConfigsForUser(USER_ID_1, true, 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.updateConfigsForUser(USER_ID_1, true, mPackageName); gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1); assertEquals(GameManager.GAME_MODE_STANDARD, gameManagerService.getGameMode(mPackageName, USER_ID_1)); @@ -534,8 +534,8 @@ public class GameManagerServiceTests { startUser(gameManagerService, USER_ID_1); startUser(gameManagerService, USER_ID_2); - gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName); - gameManagerService.updateConfigsForUser(USER_ID_2, mPackageName); + gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName); + gameManagerService.updateConfigsForUser(USER_ID_2, true, mPackageName); // Set User 1 to Standard gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1); @@ -563,7 +563,7 @@ public class GameManagerServiceTests { if (gameManagerService == null) { gameManagerService = new GameManagerService(mMockContext, mTestLooper.getLooper()); startUser(gameManagerService, USER_ID_1); - gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName); + gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName); } ArraySet reportedModes = new ArraySet<>(); int[] modes = gameManagerService.getAvailableGameModes(mPackageName); @@ -582,7 +582,7 @@ public class GameManagerServiceTests { if (gameManagerService == null) { gameManagerService = new GameManagerService(mMockContext, mTestLooper.getLooper()); startUser(gameManagerService, USER_ID_1); - gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName); + gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName); } GameManagerService.GamePackageConfiguration config = gameManagerService.getConfig(mPackageName); @@ -591,7 +591,7 @@ public class GameManagerServiceTests { private void checkAngleEnabled(GameManagerService gameManagerService, int gameMode, boolean angleEnabled) { - gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName); + gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName); // Validate GamePackageConfiguration returns the correct value. GameManagerService.GamePackageConfiguration config = @@ -604,7 +604,7 @@ public class GameManagerServiceTests { private void checkLoadingBoost(GameManagerService gameManagerService, int gameMode, int loadingBoost) { - gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName); + gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName); // Validate GamePackageConfiguration returns the correct value. GameManagerService.GamePackageConfiguration config = @@ -621,7 +621,7 @@ public class GameManagerServiceTests { if (gameManagerService == null) { gameManagerService = new GameManagerService(mMockContext, mTestLooper.getLooper()); startUser(gameManagerService, USER_ID_1); - gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName); + gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName); } GameManagerService.GamePackageConfiguration config = gameManagerService.getConfig(mPackageName); @@ -1091,7 +1091,7 @@ public class GameManagerServiceTests { GameManagerService gameManagerService = new GameManagerService(mMockContext, mTestLooper.getLooper()); startUser(gameManagerService, USER_ID_1); - gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName); + gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName); GameManagerService.GamePackageConfiguration config = gameManagerService.getConfig(mPackageName); assertNull(config.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE)); @@ -1109,7 +1109,7 @@ public class GameManagerServiceTests { new GameManagerService(mMockContext, mTestLooper.getLooper()); startUser(gameManagerService, USER_ID_1); gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1); - gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName); + gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName); assertEquals(GameManager.GAME_MODE_UNSUPPORTED, gameManagerService.getGameMode(mPackageName, USER_ID_1)); } @@ -1126,7 +1126,7 @@ public class GameManagerServiceTests { new GameManagerService(mMockContext, mTestLooper.getLooper()); startUser(gameManagerService, USER_ID_1); gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1); - gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName); + gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName); assertEquals(GameManager.GAME_MODE_STANDARD, gameManagerService.getGameMode(mPackageName, USER_ID_1)); } @@ -1143,7 +1143,7 @@ public class GameManagerServiceTests { new GameManagerService(mMockContext, mTestLooper.getLooper()); startUser(gameManagerService, USER_ID_1); gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_UNSUPPORTED, USER_ID_1); - gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName); + gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName); assertEquals(GameManager.GAME_MODE_STANDARD, gameManagerService.getGameMode(mPackageName, USER_ID_1)); } From 1ddd0c1b959feae702a31c6aeb7645bf682950d5 Mon Sep 17 00:00:00 2001 From: Xiang Wang Date: Tue, 2 Aug 2022 11:02:46 -0700 Subject: [PATCH 2/4] Guard the mode configs map in GamePackageConfiguration with lock Synchronizes the getter and setter of GameModeConfiguration as the sub fields can be read/write by different callers Bug: b/240335717 Test: atest GameManagerServiceTests Change-Id: Iac718a6a5d91e7aa3452b5cdb9aaee587f6f7773 Merged-In: Iac718a6a5d91e7aa3452b5cdb9aaee587f6f7773 --- .../server/app/GameManagerService.java | 159 ++++++++---------- 1 file changed, 67 insertions(+), 92 deletions(-) diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index 9a40a61ec3632..dc8e44fe3ec56 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -554,6 +554,8 @@ public final class GameManagerService extends IGameManagerService.Stub { private static final String GAME_MODE_CONFIG_NODE_NAME = "game-mode-config"; private final String mPackageName; + private final Object mModeConfigLock = new Object(); + @GuardedBy("mModeConfigLock") private final ArrayMap mModeConfigs; private boolean mPerfModeOptedIn = false; private boolean mBatteryModeOptedIn = false; @@ -694,11 +696,11 @@ public final class GameManagerService extends IGameManagerService.Stub { return mGameMode; } - public String getScaling() { + public synchronized String getScaling() { return mScaling; } - public int getFps() { + public synchronized int getFps() { return GameManagerService.getFpsInt(mFps); } @@ -710,11 +712,11 @@ public final class GameManagerService extends IGameManagerService.Stub { return mLoadingBoostDuration; } - public void setScaling(String scaling) { + public synchronized void setScaling(String scaling) { mScaling = scaling; } - public void setFpsStr(String fpsStr) { + public synchronized void setFpsStr(String fpsStr) { mFps = fpsStr; } @@ -761,8 +763,10 @@ public final class GameManagerService extends IGameManagerService.Stub { private int getAvailableGameModesBitfield() { int field = 0; - for (final int mode : mModeConfigs.keySet()) { - field |= modeToBitmask(mode); + synchronized (mModeConfigLock) { + for (final int mode : mModeConfigs.keySet()) { + field |= modeToBitmask(mode); + } } if (mBatteryModeOptedIn) { field |= modeToBitmask(GameManager.GAME_MODE_BATTERY); @@ -803,7 +807,9 @@ public final class GameManagerService extends IGameManagerService.Stub { * @return The package's GameModeConfiguration for the provided mode or null if absent */ public GameModeConfiguration getGameModeConfiguration(@GameMode int gameMode) { - return mModeConfigs.get(gameMode); + synchronized (mModeConfigLock) { + return mModeConfigs.get(gameMode); + } } /** @@ -811,7 +817,9 @@ public final class GameManagerService extends IGameManagerService.Stub { */ public void addModeConfig(GameModeConfiguration config) { if (config.isActive()) { - mModeConfigs.put(config.getGameMode(), config); + synchronized (mModeConfigLock) { + mModeConfigs.put(config.getGameMode(), config); + } } else { Slog.w(TAG, "Attempt to add inactive game mode config for " + mPackageName + ":" + config.toString()); @@ -819,11 +827,15 @@ public final class GameManagerService extends IGameManagerService.Stub { } public boolean isActive() { - return mModeConfigs.size() > 0 || mBatteryModeOptedIn || mPerfModeOptedIn; + synchronized (mModeConfigLock) { + return mModeConfigs.size() > 0 || mBatteryModeOptedIn || mPerfModeOptedIn; + } } public String toString() { - return "[Name:" + mPackageName + " Modes: " + mModeConfigs.toString() + "]"; + synchronized (mModeConfigLock) { + return "[Name:" + mPackageName + " Modes: " + mModeConfigs.toString() + "]"; + } } } @@ -894,15 +906,7 @@ public final class GameManagerService extends IGameManagerService.Stub { } private @GameMode int[] getAvailableGameModesUnchecked(String packageName) { - GamePackageConfiguration config = null; - synchronized (mOverrideConfigLock) { - config = mOverrideConfigs.get(packageName); - } - if (config == null) { - synchronized (mDeviceConfigLock) { - config = mConfigs.get(packageName); - } - } + final GamePackageConfiguration config = getConfig(packageName); if (config == null) { return new int[]{}; } @@ -1055,19 +1059,19 @@ public final class GameManagerService extends IGameManagerService.Stub { if (gameMode == GameManager.GAME_MODE_UNSUPPORTED) { return false; } - + final GamePackageConfiguration config; synchronized (mDeviceConfigLock) { - final GamePackageConfiguration config = mConfigs.get(packageName); + config = mConfigs.get(packageName); if (config == null) { return false; } - GamePackageConfiguration.GameModeConfiguration gameModeConfiguration = - config.getGameModeConfiguration(gameMode); - if (gameModeConfiguration == null) { - return false; - } - return gameModeConfiguration.getUseAngle(); } + GamePackageConfiguration.GameModeConfiguration gameModeConfiguration = + config.getGameModeConfiguration(gameMode); + if (gameModeConfiguration == null) { + return false; + } + return gameModeConfiguration.getUseAngle(); } /** @@ -1082,19 +1086,19 @@ public final class GameManagerService extends IGameManagerService.Stub { if (gameMode == GameManager.GAME_MODE_UNSUPPORTED) { return -1; } - + final GamePackageConfiguration config; synchronized (mDeviceConfigLock) { - final GamePackageConfiguration config = mConfigs.get(packageName); - if (config == null) { - return -1; - } - GamePackageConfiguration.GameModeConfiguration gameModeConfiguration = - config.getGameModeConfiguration(gameMode); - if (gameModeConfiguration == null) { - return -1; - } - return gameModeConfiguration.getLoadingBoostDuration(); + config = mConfigs.get(packageName); } + if (config == null) { + return -1; + } + GamePackageConfiguration.GameModeConfiguration gameModeConfiguration = + config.getGameModeConfiguration(gameMode); + if (gameModeConfiguration == null) { + return -1; + } + return gameModeConfiguration.getLoadingBoostDuration(); } /** @@ -1364,18 +1368,7 @@ public final class GameManagerService extends IGameManagerService.Stub { resetFps(packageName, userId); return; } - GamePackageConfiguration packageConfig = null; - - synchronized (mOverrideConfigLock) { - packageConfig = mOverrideConfigs.get(packageName); - } - - if (packageConfig == null) { - synchronized (mDeviceConfigLock) { - packageConfig = mConfigs.get(packageName); - } - } - + final GamePackageConfiguration packageConfig = getConfig(packageName); if (packageConfig == null) { disableCompatScale(packageName); Slog.v(TAG, "Package configuration not found for " + packageName); @@ -1404,34 +1397,34 @@ public final class GameManagerService extends IGameManagerService.Stub { } } // Adding override game mode configuration of the given package name + GamePackageConfiguration overrideConfig; synchronized (mOverrideConfigLock) { // look for the existing override GamePackageConfiguration - GamePackageConfiguration overrideConfig = mOverrideConfigs.get(packageName); + overrideConfig = mOverrideConfigs.get(packageName); if (overrideConfig == null) { overrideConfig = new GamePackageConfiguration(packageName, userId); mOverrideConfigs.put(packageName, overrideConfig); } - - // modify GameModeConfiguration intervention settings - GamePackageConfiguration.GameModeConfiguration overrideModeConfig = - overrideConfig.getGameModeConfiguration(gameMode); - - if (fpsStr != null) { - overrideModeConfig.setFpsStr(fpsStr); - } else { - overrideModeConfig.setFpsStr( - GamePackageConfiguration.GameModeConfiguration.DEFAULT_FPS); - } - if (scaling != null) { - overrideModeConfig.setScaling(scaling); - } else { - overrideModeConfig.setScaling( - GamePackageConfiguration.GameModeConfiguration.DEFAULT_SCALING); - } - Slog.i(TAG, "Package Name: " + packageName - + " FPS: " + String.valueOf(overrideModeConfig.getFps()) - + " Scaling: " + overrideModeConfig.getScaling()); } + // modify GameModeConfiguration intervention settings + GamePackageConfiguration.GameModeConfiguration overrideModeConfig = + overrideConfig.getGameModeConfiguration(gameMode); + + if (fpsStr != null) { + overrideModeConfig.setFpsStr(fpsStr); + } else { + overrideModeConfig.setFpsStr( + GamePackageConfiguration.GameModeConfiguration.DEFAULT_FPS); + } + if (scaling != null) { + overrideModeConfig.setScaling(scaling); + } else { + overrideModeConfig.setScaling( + GamePackageConfiguration.GameModeConfiguration.DEFAULT_SCALING); + } + Slog.i(TAG, "Package Name: " + packageName + + " FPS: " + String.valueOf(overrideModeConfig.getFps()) + + " Scaling: " + overrideModeConfig.getScaling()); setGameMode(packageName, gameMode, userId); } @@ -1497,15 +1490,7 @@ public final class GameManagerService extends IGameManagerService.Stub { // If not, set the game mode to standard int gameMode = getGameMode(packageName, userId); - GamePackageConfiguration config = null; - synchronized (mOverrideConfigLock) { - config = mOverrideConfigs.get(packageName); - } - if (config == null) { - synchronized (mDeviceConfigLock) { - config = mConfigs.get(packageName); - } - } + final GamePackageConfiguration config = getConfig(packageName); final int newGameMode = getNewGameMode(gameMode, config); if (gameMode != newGameMode) { setGameMode(packageName, GameManager.GAME_MODE_STANDARD, userId); @@ -1544,18 +1529,8 @@ public final class GameManagerService extends IGameManagerService.Stub { * Returns the string listing all the interventions currently set to a game. */ public String getInterventionList(String packageName) { - GamePackageConfiguration packageConfig = null; - synchronized (mOverrideConfigLock) { - packageConfig = mOverrideConfigs.get(packageName); - } - - if (packageConfig == null) { - synchronized (mDeviceConfigLock) { - packageConfig = mConfigs.get(packageName); - } - } - - StringBuilder listStrSb = new StringBuilder(); + final GamePackageConfiguration packageConfig = getConfig(packageName); + final StringBuilder listStrSb = new StringBuilder(); if (packageConfig == null) { listStrSb.append("\n No intervention found for package ") .append(packageName); From 5abb52c1669a5d582b65f1e6b55d327d21c8fb30 Mon Sep 17 00:00:00 2001 From: Xiang Wang Date: Wed, 12 Oct 2022 16:48:17 -0700 Subject: [PATCH 3/4] Override config should trigger intervention ignoring opt-in info In the past we have an inconsistent behavior regarding override config as it will ignore intervention setting such as `mAllowDownscale` but still respect opt-in info as `mPerfModeOptedIn`. This will be confusing and there is no way for OEM or game developers to test new interventions for games without any pre-configured game mode device config. Now they can instead first opt in the game modes temporarily if not pre-configured (to make them available), then apply the override to test. But they should reset the opt-in info and overrides after testing, then communicate the interventions to OEMs. This also fix the bug below where the override config used to contain full information including opt-in info that can be stale. Now it's lightweight as it only contains GameModeConfiguration(s) and will be used together with default config in getConfig call. Bug: b/253102835 Test: atest GameManagerServiceTests Change-Id: Iee14d6eed07b16b6adb86b459edebdeca2b03fbc Merged-In: Iee14d6eed07b16b6adb86b459edebdeca2b03fbc --- .../server/app/GameManagerService.java | 85 ++++++++++-- ...nfig_interventions_disabled_all_opt_in.xml | 9 ++ ...nfig_interventions_disabled_no_opt_in.xml} | 0 ...onfig_interventions_enabled_no_opt_in.xml} | 0 .../server/app/GameManagerServiceTests.java | 129 ++++++++++++++---- 5 files changed, 182 insertions(+), 41 deletions(-) create mode 100644 services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_disabled_all_opt_in.xml rename services/tests/mockingservicestests/res/xml/{gama_manager_service_metadata_config_disabled.xml => game_manager_service_metadata_config_interventions_disabled_no_opt_in.xml} (100%) rename services/tests/mockingservicestests/res/xml/{gama_manager_service_metadata_config_enabled.xml => game_manager_service_metadata_config_interventions_enabled_no_opt_in.xml} (100%) diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index dc8e44fe3ec56..62e2a9b8d40cc 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -117,6 +117,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Map; /** * Service to manage game related features. @@ -556,16 +557,21 @@ public final class GameManagerService extends IGameManagerService.Stub { private final String mPackageName; private final Object mModeConfigLock = new Object(); @GuardedBy("mModeConfigLock") - private final ArrayMap mModeConfigs; + private final ArrayMap mModeConfigs = new ArrayMap<>(); + // if adding new properties or make any of the below overridable, the method + // copyAndApplyOverride should be updated accordingly private boolean mPerfModeOptedIn = false; private boolean mBatteryModeOptedIn = false; private boolean mAllowDownscale = true; private boolean mAllowAngle = true; private boolean mAllowFpsOverride = true; + GamePackageConfiguration(String packageName) { + mPackageName = packageName; + } + GamePackageConfiguration(String packageName, int userId) { mPackageName = packageName; - mModeConfigs = new ArrayMap<>(); try { final ApplicationInfo ai = mPackageManager.getApplicationInfoAsUser(packageName, @@ -649,6 +655,13 @@ public final class GameManagerService extends IGameManagerService.Stub { return xmlFound; } + GameModeConfiguration getOrAddDefaultGameModeConfiguration(int gameMode) { + synchronized (mModeConfigLock) { + mModeConfigs.putIfAbsent(gameMode, new GameModeConfiguration(gameMode)); + return mModeConfigs.get(gameMode); + } + } + /** * GameModeConfiguration contains all the values for all the interventions associated with * a game mode. @@ -661,15 +674,23 @@ public final class GameManagerService extends IGameManagerService.Stub { public static final String FPS_KEY = "fps"; public static final String DEFAULT_SCALING = "1.0"; public static final String DEFAULT_FPS = ""; + public static final boolean DEFAULT_USE_ANGLE = false; + public static final int DEFAULT_LOADING_BOOST_DURATION = -1; public static final String ANGLE_KEY = "useAngle"; public static final String LOADING_BOOST_KEY = "loadingBoost"; private final @GameMode int mGameMode; - private String mScaling; - private String mFps; + private String mScaling = DEFAULT_SCALING; + private String mFps = DEFAULT_FPS; private final boolean mUseAngle; private final int mLoadingBoostDuration; + GameModeConfiguration(int gameMode) { + mGameMode = gameMode; + mUseAngle = DEFAULT_USE_ANGLE; + mLoadingBoostDuration = DEFAULT_LOADING_BOOST_DURATION; + } + GameModeConfiguration(KeyValueListParser parser) { mGameMode = parser.getInt(MODE_KEY, GameManager.GAME_MODE_UNSUPPORTED); // isGameModeOptedIn() returns if an app will handle all of the changes necessary @@ -832,6 +853,42 @@ public final class GameManagerService extends IGameManagerService.Stub { } } + GamePackageConfiguration copyAndApplyOverride(GamePackageConfiguration overrideConfig) { + GamePackageConfiguration copy = new GamePackageConfiguration(mPackageName); + // if a game mode is overridden, we treat it with the highest priority and reset any + // opt-in game modes so that interventions are always executed. + copy.mPerfModeOptedIn = mPerfModeOptedIn && !(overrideConfig != null + && overrideConfig.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE) + != null); + copy.mBatteryModeOptedIn = mBatteryModeOptedIn && !(overrideConfig != null + && overrideConfig.getGameModeConfiguration(GameManager.GAME_MODE_BATTERY) + != null); + + // if any game mode is overridden, we will consider all interventions forced-active, + // this can be done more granular by checking if a specific intervention is + // overridden under each game mode override, but only if necessary. + copy.mAllowDownscale = mAllowDownscale || overrideConfig != null; + copy.mAllowAngle = mAllowAngle || overrideConfig != null; + copy.mAllowFpsOverride = mAllowFpsOverride || overrideConfig != null; + if (overrideConfig != null) { + synchronized (copy.mModeConfigLock) { + synchronized (mModeConfigLock) { + for (Map.Entry entry : + mModeConfigs.entrySet()) { + copy.mModeConfigs.put(entry.getKey(), entry.getValue()); + } + } + synchronized (overrideConfig.mModeConfigLock) { + for (Map.Entry entry : + overrideConfig.mModeConfigs.entrySet()) { + copy.mModeConfigs.put(entry.getKey(), entry.getValue()); + } + } + } + } + return copy; + } + public String toString() { synchronized (mModeConfigLock) { return "[Name:" + mPackageName + " Modes: " + mModeConfigs.toString() + "]"; @@ -1402,13 +1459,13 @@ public final class GameManagerService extends IGameManagerService.Stub { // look for the existing override GamePackageConfiguration overrideConfig = mOverrideConfigs.get(packageName); if (overrideConfig == null) { - overrideConfig = new GamePackageConfiguration(packageName, userId); + overrideConfig = new GamePackageConfiguration(packageName); mOverrideConfigs.put(packageName, overrideConfig); } } // modify GameModeConfiguration intervention settings GamePackageConfiguration.GameModeConfiguration overrideModeConfig = - overrideConfig.getGameModeConfiguration(gameMode); + overrideConfig.getOrAddDefaultGameModeConfiguration(gameMode); if (fpsStr != null) { overrideModeConfig.setFpsStr(fpsStr); @@ -1704,16 +1761,18 @@ public final class GameManagerService extends IGameManagerService.Stub { */ @VisibleForTesting public GamePackageConfiguration getConfig(String packageName) { - GamePackageConfiguration packageConfig = null; + GamePackageConfiguration overrideConfig = null; + GamePackageConfiguration config; + synchronized (mDeviceConfigLock) { + config = mConfigs.get(packageName); + } synchronized (mOverrideConfigLock) { - packageConfig = mOverrideConfigs.get(packageName); + overrideConfig = mOverrideConfigs.get(packageName); } - if (packageConfig == null) { - synchronized (mDeviceConfigLock) { - packageConfig = mConfigs.get(packageName); - } + if (overrideConfig == null || config == null) { + return overrideConfig == null ? config : overrideConfig; } - return packageConfig; + return config.copyAndApplyOverride(overrideConfig); } private void registerPackageReceiver() { diff --git a/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_disabled_all_opt_in.xml b/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_disabled_all_opt_in.xml new file mode 100644 index 0000000000000..77fe786f812f9 --- /dev/null +++ b/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_disabled_all_opt_in.xml @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_disabled.xml b/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_disabled_no_opt_in.xml similarity index 100% rename from services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_disabled.xml rename to services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_disabled_no_opt_in.xml diff --git a/services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_enabled.xml b/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_enabled_no_opt_in.xml similarity index 100% rename from services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_enabled.xml rename to services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_enabled_no_opt_in.xml diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java index d325e47f76879..adc4b843e24c1 100644 --- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java @@ -19,6 +19,7 @@ package com.android.server.app; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; @@ -369,38 +370,35 @@ public class GameManagerServiceTests { .thenReturn(applicationInfo); } - private void mockInterventionsEnabledFromXml() throws Exception { - final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( - mPackageName, PackageManager.GET_META_DATA, USER_ID_1); - Bundle metaDataBundle = new Bundle(); - final int resId = 123; - metaDataBundle.putInt( - GameManagerService.GamePackageConfiguration.METADATA_GAME_MODE_CONFIG, resId); - applicationInfo.metaData = metaDataBundle; - when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) - .thenReturn(applicationInfo); - seedGameManagerServiceMetaDataFromFile(mPackageName, resId, - "res/xml/gama_manager_service_metadata_config_enabled.xml"); + private void mockInterventionsEnabledNoOptInFromXml() throws Exception { + seedGameManagerServiceMetaDataFromFile(mPackageName, 123, + "res/xml/game_manager_service_metadata_config_interventions_enabled_no_opt_in.xml"); } - private void mockInterventionsDisabledFromXml() throws Exception { - final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( - mPackageName, PackageManager.GET_META_DATA, USER_ID_1); - Bundle metaDataBundle = new Bundle(); - final int resId = 123; - metaDataBundle.putInt( - GameManagerService.GamePackageConfiguration.METADATA_GAME_MODE_CONFIG, resId); - applicationInfo.metaData = metaDataBundle; - when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) - .thenReturn(applicationInfo); - seedGameManagerServiceMetaDataFromFile(mPackageName, resId, - "res/xml/gama_manager_service_metadata_config_disabled.xml"); + private void mockInterventionsDisabledNoOptInFromXml() throws Exception { + seedGameManagerServiceMetaDataFromFile(mPackageName, 123, + "res/xml/game_manager_service_metadata_config_interventions_disabled_no_opt_in" + + ".xml"); + } + + private void mockInterventionsDisabledAllOptInFromXml() throws Exception { + seedGameManagerServiceMetaDataFromFile(mPackageName, 123, + "res/xml/game_manager_service_metadata_config_interventions_disabled_all_opt_in" + + ".xml"); } private void seedGameManagerServiceMetaDataFromFile(String packageName, int resId, String fileName) throws Exception { + final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( + mPackageName, PackageManager.GET_META_DATA, USER_ID_1); + Bundle metaDataBundle = new Bundle(); + metaDataBundle.putInt( + GameManagerService.GamePackageConfiguration.METADATA_GAME_MODE_CONFIG, resId); + applicationInfo.metaData = metaDataBundle; + when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) + .thenReturn(applicationInfo); AssetManager assetManager = InstrumentationRegistry.getInstrumentation().getContext().getAssets(); XmlResourceParser xmlResourceParser = @@ -628,6 +626,12 @@ public class GameManagerServiceTests { assertEquals(fps, config.getGameModeConfiguration(gameMode).getFps()); } + private boolean checkOptedIn(GameManagerService gameManagerService, int gameMode) { + GameManagerService.GamePackageConfiguration config = + gameManagerService.getConfig(mPackageName); + return config.willGamePerformOptimizations(gameMode); + } + /** * Phenotype device config exists, but is only propagating the default value. */ @@ -743,7 +747,7 @@ public class GameManagerServiceTests { * Override device configs for both battery and performance modes exists and are valid. */ @Test - public void testSetDeviceOverrideConfigAll() { + public void testSetDeviceConfigOverrideAll() { mockDeviceConfigAll(); mockModifyGameModeGranted(); @@ -763,6 +767,75 @@ public class GameManagerServiceTests { checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 60); } + @Test + public void testSetBatteryModeConfigOverride_thenUpdateAllDeviceConfig() throws Exception { + mockModifyGameModeGranted(); + String configStringBefore = + "mode=2,downscaleFactor=1.0,fps=90:mode=3,downscaleFactor=0.1,fps=30"; + when(DeviceConfig.getProperty(anyString(), anyString())) + .thenReturn(configStringBefore); + mockInterventionsEnabledNoOptInFromXml(); + GameManagerService gameManagerService = new GameManagerService(mMockContext, + mTestLooper.getLooper()); + startUser(gameManagerService, USER_ID_1); + + checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, "1.0"); + checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90); + checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.1"); + checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 30); + + gameManagerService.setGameModeConfigOverride(mPackageName, USER_ID_1, 3, "40", + "0.2"); + + checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 40); + checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.2"); + + String configStringAfter = + "mode=2,downscaleFactor=0.9,fps=60:mode=3,downscaleFactor=0.3,fps=50"; + when(DeviceConfig.getProperty(anyString(), anyString())) + .thenReturn(configStringAfter); + gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName); + + // performance mode was not overridden thus it should be updated + checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, "0.9"); + checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 60); + + // battery mode was overridden thus it should be the same as the override + checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.2"); + checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 40); + } + + @Test + public void testSetBatteryModeConfigOverride_thenOptInBatteryMode() throws Exception { + mockModifyGameModeGranted(); + String configStringBefore = + "mode=2,downscaleFactor=1.0,fps=90:mode=3,downscaleFactor=0.1,fps=30"; + when(DeviceConfig.getProperty(anyString(), anyString())) + .thenReturn(configStringBefore); + mockInterventionsDisabledNoOptInFromXml(); + GameManagerService gameManagerService = new GameManagerService(mMockContext, + mTestLooper.getLooper()); + startUser(gameManagerService, USER_ID_1); + + assertFalse(checkOptedIn(gameManagerService, GameManager.GAME_MODE_PERFORMANCE)); + assertFalse(checkOptedIn(gameManagerService, GameManager.GAME_MODE_BATTERY)); + checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0); + + gameManagerService.setGameModeConfigOverride(mPackageName, USER_ID_1, 3, "40", + "0.2"); + checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0); + // override will enable the interventions + checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.2"); + checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 40); + + mockInterventionsDisabledAllOptInFromXml(); + gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName); + + assertTrue(checkOptedIn(gameManagerService, GameManager.GAME_MODE_PERFORMANCE)); + // opt-in is still false for battery mode as override exists + assertFalse(checkOptedIn(gameManagerService, GameManager.GAME_MODE_BATTERY)); + } + /** * Override device config for performance mode exists and is valid. */ @@ -1037,7 +1110,7 @@ public class GameManagerServiceTests { gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1); assertEquals(GameManager.GAME_MODE_PERFORMANCE, gameManagerService.getGameMode(mPackageName, USER_ID_1)); - mockInterventionsEnabledFromXml(); + mockInterventionsEnabledNoOptInFromXml(); checkLoadingBoost(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0); } @@ -1045,7 +1118,7 @@ public class GameManagerServiceTests { public void testGameModeConfigAllowFpsTrue() throws Exception { mockDeviceConfigAll(); mockModifyGameModeGranted(); - mockInterventionsEnabledFromXml(); + mockInterventionsEnabledNoOptInFromXml(); GameManagerService gameManagerService = new GameManagerService(mMockContext, mTestLooper.getLooper()); startUser(gameManagerService, USER_ID_1); @@ -1060,7 +1133,7 @@ public class GameManagerServiceTests { public void testGameModeConfigAllowFpsFalse() throws Exception { mockDeviceConfigAll(); mockModifyGameModeGranted(); - mockInterventionsDisabledFromXml(); + mockInterventionsDisabledNoOptInFromXml(); GameManagerService gameManagerService = new GameManagerService(mMockContext, mTestLooper.getLooper()); startUser(gameManagerService, USER_ID_1); From e8d4d360d0266a2e94222e5abaa93959bc0f75f2 Mon Sep 17 00:00:00 2001 From: Xiang Wang Date: Wed, 12 Oct 2022 18:06:43 -0700 Subject: [PATCH 4/4] Reset FPS when device config resets or app opts in to a game mode Bug: b/253100682 Test: atest GameManagerServiceTests Change-Id: If537a25e75be963ef5871a0383230d2ab13ff85a Merged-In: If537a25e75be963ef5871a0383230d2ab13ff85a --- .../server/app/GameManagerService.java | 27 +++--- ...onfig_interventions_enabled_all_opt_in.xml | 9 ++ .../server/app/GameManagerServiceTests.java | 87 +++++++++++++++++++ 3 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_enabled_all_opt_in.xml diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index 62e2a9b8d40cc..4013acefa3666 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -1324,7 +1324,7 @@ public final class GameManagerService extends IGameManagerService.Stub { try { final float fps = 0.0f; final int uid = mPackageManager.getPackageUidAsUser(packageName, userId); - nativeSetOverrideFrameRate(uid, fps); + setOverrideFrameRate(uid, fps); } catch (PackageManager.NameNotFoundException e) { return; } @@ -1410,7 +1410,7 @@ public final class GameManagerService extends IGameManagerService.Stub { try { final float fps = modeConfig.getFps(); final int uid = mPackageManager.getPackageUidAsUser(packageName, userId); - nativeSetOverrideFrameRate(uid, fps); + setOverrideFrameRate(uid, fps); } catch (PackageManager.NameNotFoundException e) { return; } @@ -1419,20 +1419,16 @@ public final class GameManagerService extends IGameManagerService.Stub { private void updateInterventions(String packageName, @GameMode int gameMode, @UserIdInt int userId) { + final GamePackageConfiguration packageConfig = getConfig(packageName); if (gameMode == GameManager.GAME_MODE_STANDARD - || gameMode == GameManager.GAME_MODE_UNSUPPORTED) { + || gameMode == GameManager.GAME_MODE_UNSUPPORTED || packageConfig == null + || packageConfig.willGamePerformOptimizations(gameMode)) { disableCompatScale(packageName); resetFps(packageName, userId); - return; - } - final GamePackageConfiguration packageConfig = getConfig(packageName); - if (packageConfig == null) { - disableCompatScale(packageName); - Slog.v(TAG, "Package configuration not found for " + packageName); - return; - } - if (packageConfig.willGamePerformOptimizations(gameMode)) { - return; + if (packageConfig == null) { + Slog.v(TAG, "Package configuration not found for " + packageName); + return; + } } updateCompatModeDownscale(packageConfig, packageName, gameMode); updateFps(packageConfig, packageName, gameMode, userId); @@ -1876,6 +1872,11 @@ public final class GameManagerService extends IGameManagerService.Stub { return handlerThread; } + @VisibleForTesting + void setOverrideFrameRate(int uid, float frameRate) { + nativeSetOverrideFrameRate(uid, frameRate); + } + /** * load dynamic library for frame rate overriding JNI calls */ diff --git a/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_enabled_all_opt_in.xml b/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_enabled_all_opt_in.xml new file mode 100644 index 0000000000000..96d28785ba0ad --- /dev/null +++ b/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_enabled_all_opt_in.xml @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java index adc4b843e24c1..cfb80148f166d 100644 --- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java @@ -68,7 +68,9 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentMatchers; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; @@ -88,6 +90,7 @@ public class GameManagerServiceTests { private static final String PACKAGE_NAME_INVALID = "com.android.app"; private static final int USER_ID_1 = 1001; private static final int USER_ID_2 = 1002; + private static final int DEFAULT_PACKAGE_UID = 12345; private MockitoSession mMockingSession; private String mPackageName; @@ -195,6 +198,8 @@ public class GameManagerServiceTests { .thenReturn(packages); when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) .thenReturn(applicationInfo); + when(mMockPackageManager.getPackageUidAsUser(mPackageName, USER_ID_1)).thenReturn( + DEFAULT_PACKAGE_UID); LocalServices.addService(PowerManagerInternal.class, mMockPowerManager); } @@ -375,6 +380,12 @@ public class GameManagerServiceTests { "res/xml/game_manager_service_metadata_config_interventions_enabled_no_opt_in.xml"); } + private void mockInterventionsEnabledAllOptInFromXml() throws Exception { + seedGameManagerServiceMetaDataFromFile(mPackageName, 123, + "res/xml/game_manager_service_metadata_config_interventions_enabled_all_opt_in" + + ".xml"); + } + private void mockInterventionsDisabledNoOptInFromXml() throws Exception { seedGameManagerServiceMetaDataFromFile(mPackageName, 123, "res/xml/game_manager_service_metadata_config_interventions_disabled_no_opt_in" @@ -1477,4 +1488,80 @@ public class GameManagerServiceTests { assertEquals(splitLine[6], "angle=0,scaling=0.7,fps=30"); } + + @Test + public void testResetInterventions_onDeviceConfigReset() throws Exception { + mockModifyGameModeGranted(); + String configStringBefore = + "mode=2,downscaleFactor=1.0,fps=90"; + when(DeviceConfig.getProperty(anyString(), anyString())) + .thenReturn(configStringBefore); + mockInterventionsEnabledNoOptInFromXml(); + GameManagerService gameManagerService = Mockito.spy(new GameManagerService(mMockContext, + mTestLooper.getLooper())); + startUser(gameManagerService, USER_ID_1); + gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1); + Mockito.verify(gameManagerService).setOverrideFrameRate( + ArgumentMatchers.eq(DEFAULT_PACKAGE_UID), + ArgumentMatchers.eq(90.0f)); + checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90); + + String configStringAfter = ""; + when(DeviceConfig.getProperty(anyString(), anyString())) + .thenReturn(configStringAfter); + gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName); + Mockito.verify(gameManagerService).setOverrideFrameRate( + ArgumentMatchers.eq(DEFAULT_PACKAGE_UID), + ArgumentMatchers.eq(0.0f)); + } + + @Test + public void testResetInterventions_onInterventionsDisabled() throws Exception { + mockModifyGameModeGranted(); + String configStringBefore = + "mode=2,downscaleFactor=1.0,fps=90"; + when(DeviceConfig.getProperty(anyString(), anyString())) + .thenReturn(configStringBefore); + mockInterventionsEnabledNoOptInFromXml(); + GameManagerService gameManagerService = Mockito.spy(new GameManagerService(mMockContext, + mTestLooper.getLooper())); + startUser(gameManagerService, USER_ID_1); + gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1); + Mockito.verify(gameManagerService).setOverrideFrameRate( + ArgumentMatchers.eq(DEFAULT_PACKAGE_UID), + ArgumentMatchers.eq(90.0f)); + checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90); + + mockInterventionsDisabledNoOptInFromXml(); + gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName); + Mockito.verify(gameManagerService).setOverrideFrameRate( + ArgumentMatchers.eq(DEFAULT_PACKAGE_UID), + ArgumentMatchers.eq(0.0f)); + checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0); + } + + @Test + public void testResetInterventions_onGameModeOptedIn() throws Exception { + mockModifyGameModeGranted(); + String configStringBefore = + "mode=2,downscaleFactor=1.0,fps=90"; + when(DeviceConfig.getProperty(anyString(), anyString())) + .thenReturn(configStringBefore); + mockInterventionsEnabledNoOptInFromXml(); + GameManagerService gameManagerService = Mockito.spy(new GameManagerService(mMockContext, + mTestLooper.getLooper())); + startUser(gameManagerService, USER_ID_1); + + gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1); + Mockito.verify(gameManagerService).setOverrideFrameRate( + ArgumentMatchers.eq(DEFAULT_PACKAGE_UID), + ArgumentMatchers.eq(90.0f)); + checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90); + + mockInterventionsEnabledAllOptInFromXml(); + gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName); + Mockito.verify(gameManagerService).setOverrideFrameRate( + ArgumentMatchers.eq(DEFAULT_PACKAGE_UID), + ArgumentMatchers.eq(0.0f)); + } }