diff options
| -rw-r--r-- | services/core/java/com/android/server/app/GameManagerService.java | 293 | ||||
| -rw-r--r-- | services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_disabled_all_opt_in.xml | 9 | ||||
| -rw-r--r-- | services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_disabled_no_opt_in.xml (renamed from services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_disabled.xml) | 0 | ||||
| -rw-r--r-- | services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_enabled_all_opt_in.xml | 9 | ||||
| -rw-r--r-- | services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_enabled_no_opt_in.xml (renamed from services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_enabled.xml) | 0 | ||||
| -rw-r--r-- | services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java | 238 |
6 files changed, 385 insertions, 164 deletions
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index 15c569e246f7..4013acefa366 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. @@ -333,7 +334,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 +403,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 @@ -553,16 +555,23 @@ 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 ArrayMap<Integer, GameModeConfiguration> mModeConfigs; + private final Object mModeConfigLock = new Object(); + @GuardedBy("mModeConfigLock") + private final ArrayMap<Integer, GameModeConfiguration> 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, @@ -646,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. @@ -658,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 @@ -693,11 +717,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); } @@ -709,15 +733,15 @@ 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; } - public boolean isValid() { + public boolean isActive() { return (mGameMode == GameManager.GAME_MODE_STANDARD || mGameMode == GameManager.GAME_MODE_PERFORMANCE || mGameMode == GameManager.GAME_MODE_BATTERY) @@ -760,8 +784,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); @@ -802,27 +828,71 @@ 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); + } } /** * Insert a new GameModeConfiguration */ public void addModeConfig(GameModeConfiguration config) { - if (config.isValid()) { - mModeConfigs.put(config.getGameMode(), config); + if (config.isActive()) { + synchronized (mModeConfigLock) { + 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() { - return mModeConfigs.size() > 0 || mBatteryModeOptedIn || mPerfModeOptedIn; + public boolean isActive() { + synchronized (mModeConfigLock) { + return mModeConfigs.size() > 0 || mBatteryModeOptedIn || mPerfModeOptedIn; + } + } + + 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<Integer, GameModeConfiguration> entry : + mModeConfigs.entrySet()) { + copy.mModeConfigs.put(entry.getKey(), entry.getValue()); + } + } + synchronized (overrideConfig.mModeConfigLock) { + for (Map.Entry<Integer, GameModeConfiguration> entry : + overrideConfig.mModeConfigs.entrySet()) { + copy.mModeConfigs.put(entry.getKey(), entry.getValue()); + } + } + } + } + return copy; } public String toString() { - return "[Name:" + mPackageName + " Modes: " + mModeConfigs.toString() + "]"; + synchronized (mModeConfigLock) { + return "[Name:" + mPackageName + " Modes: " + mModeConfigs.toString() + "]"; + } } } @@ -893,15 +963,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[]{}; } @@ -1054,19 +1116,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(); } /** @@ -1081,19 +1143,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(); } /** @@ -1262,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; } @@ -1348,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; } @@ -1357,32 +1419,17 @@ 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; - } - GamePackageConfiguration packageConfig = null; - - synchronized (mOverrideConfigLock) { - packageConfig = mOverrideConfigs.get(packageName); - } - - if (packageConfig == null) { - synchronized (mDeviceConfigLock) { - packageConfig = mConfigs.get(packageName); + if (packageConfig == null) { + Slog.v(TAG, "Package configuration not found for " + packageName); + return; } } - - if (packageConfig == null) { - disableCompatScale(packageName); - Slog.v(TAG, "Package configuration not found for " + packageName); - return; - } - if (packageConfig.willGamePerformOptimizations(gameMode)) { - return; - } updateCompatModeDownscale(packageConfig, packageName, gameMode); updateFps(packageConfig, packageName, gameMode, userId); updateUseAngle(packageName, gameMode); @@ -1403,34 +1450,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); + overrideConfig = new GamePackageConfiguration(packageName); mOverrideConfigs.put(packageName, overrideConfig); } + } + // modify GameModeConfiguration intervention settings + GamePackageConfiguration.GameModeConfiguration overrideModeConfig = + overrideConfig.getOrAddDefaultGameModeConfiguration(gameMode); - // 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()); + 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); } @@ -1496,15 +1543,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); @@ -1543,18 +1582,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); @@ -1569,20 +1598,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); } } @@ -1721,16 +1757,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() { @@ -1760,7 +1798,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); @@ -1834,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_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 000000000000..77fe786f812f --- /dev/null +++ b/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_disabled_all_opt_in.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<game-mode-config + xmlns:android="http://schemas.android.com/apk/res/android" + android:supportsPerformanceGameMode="true" + android:supportsBatteryGameMode="true" + android:allowGameAngleDriver="false" + android:allowGameDownscaling="false" + android:allowGameFpsOverride="false" +/>
\ 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 index eb154518c911..eb154518c911 100644 --- 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 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 000000000000..96d28785ba0a --- /dev/null +++ b/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_enabled_all_opt_in.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<game-mode-config + xmlns:android="http://schemas.android.com/apk/res/android" + android:supportsPerformanceGameMode="true" + android:supportsBatteryGameMode="true" + android:allowGameAngleDriver="true" + android:allowGameDownscaling="true" + android:allowGameFpsOverride="true" +/>
\ No newline at end of file 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 index 65b7467b80f5..65b7467b80f5 100644 --- 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 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 d675b0aa4973..cfb80148f166 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; @@ -67,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; @@ -87,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; @@ -194,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); } @@ -369,38 +375,41 @@ 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 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" + + ".xml"); + } + + private void mockInterventionsDisabledAllOptInFromXml() throws Exception { + seedGameManagerServiceMetaDataFromFile(mPackageName, 123, + "res/xml/game_manager_service_metadata_config_interventions_disabled_all_opt_in" + + ".xml"); } - private void mockInterventionsDisabledFromXml() throws Exception { + + 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(); - 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 seedGameManagerServiceMetaDataFromFile(String packageName, int resId, - String fileName) - throws Exception { AssetManager assetManager = InstrumentationRegistry.getInstrumentation().getContext().getAssets(); XmlResourceParser xmlResourceParser = @@ -450,13 +459,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 +543,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 +572,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<Integer> reportedModes = new ArraySet<>(); int[] modes = gameManagerService.getAvailableGameModes(mPackageName); @@ -582,7 +591,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 +600,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 +613,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,13 +630,19 @@ 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); 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 +758,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 +778,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 +1121,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 +1129,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 +1144,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); @@ -1091,7 +1175,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 +1193,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 +1210,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 +1227,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)); } @@ -1404,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)); + } } |