From 4f62571e7858c9a2b5dd8e5e342b00bcb45ea2bd Mon Sep 17 00:00:00 2001 From: Xiang Wang Date: Wed, 12 Oct 2022 16:48:17 -0700 Subject: [PATCH 1/2] 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 --- .../server/app/GameManagerService.java | 69 +++++++--- ...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 | 128 ++++++++++++++---- 5 files changed, 161 insertions(+), 45 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 e11d95ada524d..558364f1461a4 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -490,6 +490,8 @@ public final class GameManagerService extends IGameManagerService.Stub { private final Object mModeConfigLock = new Object(); @GuardedBy("mModeConfigLock") 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; @@ -800,6 +802,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() + "]"; @@ -1375,7 +1413,7 @@ public final class GameManagerService extends IGameManagerService.Stub { // look for the existing GamePackageConfiguration override configOverride = settings.getConfigOverride(packageName); if (configOverride == null) { - configOverride = new GamePackageConfiguration(mPackageManager, packageName, userId); + configOverride = new GamePackageConfiguration(packageName); settings.setConfigOverride(packageName, configOverride); } } @@ -1430,18 +1468,12 @@ public final class GameManagerService extends IGameManagerService.Stub { return; } // if the game mode to reset is the only mode other than standard mode or there - // is device config, the config override is removed. + // is device config, the entire package config override is removed. if (Integer.bitCount(modesBitfield) <= 2 || deviceConfig == null) { settings.removeConfigOverride(packageName); } else { - final GamePackageConfiguration.GameModeConfiguration defaultModeConfig = - deviceConfig.getGameModeConfiguration(gameModeToReset); - // otherwise we reset the mode by copying the original config. - if (defaultModeConfig == null) { - configOverride.removeModeConfig(gameModeToReset); - } else { - configOverride.addModeConfig(defaultModeConfig); - } + // otherwise we reset the mode by removing the game mode config override + configOverride.removeModeConfig(gameModeToReset); } } else { settings.removeConfigOverride(packageName); @@ -1661,18 +1693,21 @@ public final class GameManagerService extends IGameManagerService.Stub { * @hide */ public GamePackageConfiguration getConfig(String packageName, int userId) { - GamePackageConfiguration packageConfig = null; + GamePackageConfiguration overrideConfig = null; + GamePackageConfiguration config; + synchronized (mDeviceConfigLock) { + config = mConfigs.get(packageName); + } + synchronized (mLock) { if (mSettings.containsKey(userId)) { - packageConfig = mSettings.get(userId).getConfigOverride(packageName); + overrideConfig = mSettings.get(userId).getConfigOverride(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 9022db83d5ce8..c7f8e54b99b1b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java @@ -382,38 +382,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 = @@ -641,6 +638,12 @@ public class GameManagerServiceTests { assertEquals(fps, config.getGameModeConfiguration(gameMode).getFps()); } + private boolean checkOptedIn(GameManagerService gameManagerService, int gameMode) { + GameManagerService.GamePackageConfiguration config = + gameManagerService.getConfig(mPackageName, USER_ID_1); + return config.willGamePerformOptimizations(gameMode); + } + /** * Phenotype device config exists, but is only propagating the default value. */ @@ -756,7 +759,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(); @@ -776,6 +779,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.0f); + checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90); + checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, 0.1f); + 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.2f); + + 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.9f); + 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.2f); + 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.2f); + 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. */ @@ -1050,7 +1122,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); } @@ -1058,7 +1130,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); @@ -1073,7 +1145,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 018d4534932230dec1fae2a6fad9d37f77fee767 Mon Sep 17 00:00:00 2001 From: Xiang Wang Date: Wed, 12 Oct 2022 18:06:43 -0700 Subject: [PATCH 2/2] Reset FPS when device config resets or app opts in to a game mode Bug: b/253100682 Test: atest GameManagerServiceTests Change-Id: If537a25e75be963ef5871a0383230d2ab13ff85a --- .../server/app/GameManagerService.java | 31 ++++--- ...onfig_interventions_enabled_all_opt_in.xml | 9 ++ .../server/app/GameManagerServiceTests.java | 87 +++++++++++++++++++ 3 files changed, 114 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 558364f1461a4..efa2f25bf3e33 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -1336,7 +1336,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; } @@ -1368,7 +1368,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; } @@ -1377,18 +1377,18 @@ public final class GameManagerService extends IGameManagerService.Stub { private void updateInterventions(String packageName, @GameMode int gameMode, @UserIdInt int userId) { - if (gameMode == GameManager.GAME_MODE_STANDARD - || gameMode == GameManager.GAME_MODE_UNSUPPORTED) { - resetFps(packageName, userId); - return; - } final GamePackageConfiguration packageConfig = getConfig(packageName, userId); - if (packageConfig == null) { - Slog.v(TAG, "Package configuration not found for " + packageName); - return; - } - if (packageConfig.willGamePerformOptimizations(gameMode)) { - return; + if (gameMode == GameManager.GAME_MODE_STANDARD + || gameMode == GameManager.GAME_MODE_UNSUPPORTED || packageConfig == null + || packageConfig.willGamePerformOptimizations(gameMode)) { + resetFps(packageName, userId); + // resolution scaling does not need to be reset as it's now read dynamically on game + // restart, see #getResolutionScalingFactor and CompatModePackages#getCompatScale. + // TODO: reset Angle intervention here once implemented + if (packageConfig == null) { + Slog.v(TAG, "Package configuration not found for " + packageName); + return; + } } updateFps(packageConfig, packageName, gameMode, userId); updateUseAngle(packageName, gameMode); @@ -1809,6 +1809,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 c7f8e54b99b1b..d78f6d83d0ab1 100644 --- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java @@ -73,7 +73,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; @@ -93,6 +95,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; @@ -207,6 +210,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); } @@ -387,6 +392,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" @@ -1623,6 +1634,82 @@ public class GameManagerServiceTests { assertFalse(gameManagerService.mHandler.hasEqualMessages(WRITE_SETTINGS, USER_ID_1)); } + @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)); + } + private static void deleteFolder(File folder) { File[] files = folder.listFiles(); if (files != null) {