Merge "Ensure the game mode setting doesn't conflict with available modes" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-05-19 19:40:54 +00:00
committed by Android (Google) Code Review
2 changed files with 132 additions and 21 deletions

View File

@@ -56,7 +56,6 @@ import android.os.ShellCallback;
import android.provider.DeviceConfig; import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties; import android.provider.DeviceConfig.Properties;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.KeyValueListParser; import android.util.KeyValueListParser;
import android.util.Slog; import android.util.Slog;
@@ -363,19 +362,42 @@ public final class GameManagerService extends IGameManagerService.Stub {
|| (mPerfModeOptedIn && gameMode == GameManager.GAME_MODE_PERFORMANCE); || (mPerfModeOptedIn && gameMode == GameManager.GAME_MODE_PERFORMANCE);
} }
public @GameMode int[] getAvailableGameModes() { private int getAvailableGameModesBitfield() {
ArraySet<Integer> modeSet = new ArraySet<>(mModeConfigs.keySet()); int field = 0;
for (final int mode : mModeConfigs.keySet()) {
field |= modeToBitmask(mode);
}
if (mBatteryModeOptedIn) { if (mBatteryModeOptedIn) {
modeSet.add(GameManager.GAME_MODE_BATTERY); field |= modeToBitmask(GameManager.GAME_MODE_BATTERY);
} }
if (mPerfModeOptedIn) { if (mPerfModeOptedIn) {
modeSet.add(GameManager.GAME_MODE_PERFORMANCE); field |= modeToBitmask(GameManager.GAME_MODE_PERFORMANCE);
} }
if (modeSet.size() > 0) { // The lowest bit is reserved for UNSUPPORTED, STANDARD is supported if we support any
modeSet.add(GameManager.GAME_MODE_STANDARD); // other mode.
return modeSet.stream().mapToInt(Integer::intValue).toArray(); if (field > 1) {
field |= modeToBitmask(GameManager.GAME_MODE_STANDARD);
} else {
field |= modeToBitmask(GameManager.GAME_MODE_UNSUPPORTED);
} }
return new int[]{GameManager.GAME_MODE_UNSUPPORTED}; return field;
}
/**
* Get an array of a package's available game modes.
*/
public @GameMode int[] getAvailableGameModes() {
int modesBitfield = getAvailableGameModesBitfield();
int sigBits = Integer.bitCount(modesBitfield);
int[] modes = new int[sigBits];
int i = 0;
for (int mode = 0; mode < sigBits; ++mode) {
if (((modesBitfield >> mode) & 1) != 0) {
modes[i++] = mode;
}
}
return modes;
} }
/** /**
@@ -696,6 +718,14 @@ public final class GameManagerService extends IGameManagerService.Stub {
} }
} }
private int modeToBitmask(@GameMode int gameMode) {
return (1 << gameMode);
}
private boolean bitFieldContainsModeBitmask(int bitField, @GameMode int gameMode) {
return (bitField & modeToBitmask(gameMode)) != 0;
}
/** /**
* @hide * @hide
*/ */
@@ -703,8 +733,8 @@ public final class GameManagerService extends IGameManagerService.Stub {
public void updateConfigsForUser(int userId, String ...packageNames) { public void updateConfigsForUser(int userId, String ...packageNames) {
try { try {
synchronized (mDeviceConfigLock) { synchronized (mDeviceConfigLock) {
for (String packageName : packageNames) { for (final String packageName : packageNames) {
GamePackageConfiguration config = final GamePackageConfiguration config =
new GamePackageConfiguration(packageName, userId); new GamePackageConfiguration(packageName, userId);
if (config.isValid()) { if (config.isValid()) {
if (DEBUG) { if (DEBUG) {
@@ -718,13 +748,42 @@ public final class GameManagerService extends IGameManagerService.Stub {
} }
} }
} }
for (String packageName : packageNames) { for (final String packageName : packageNames) {
synchronized (mLock) { if (mSettings.containsKey(userId)) {
if (mSettings.containsKey(userId)) { int gameMode = getGameMode(packageName, userId);
GameManagerSettings userSettings = mSettings.get(userId); int newGameMode = gameMode;
updateCompatModeDownscale(packageName, // Make sure the user settings and package configs don't conflict. I.e. the
userSettings.getGameModeLocked(packageName)); // user setting is set to a mode that no longer available due to config/manifest
// changes. Most of the time we won't have to change anything.
GamePackageConfiguration config;
synchronized (mDeviceConfigLock) {
config = mConfigs.get(packageName);
} }
if (config != null) {
int modesBitfield = config.getAvailableGameModesBitfield();
// Remove UNSUPPORTED to simplify the logic here, since we really just
// want to check if we support selectable game modes
modesBitfield &= ~modeToBitmask(GameManager.GAME_MODE_UNSUPPORTED);
if (!bitFieldContainsModeBitmask(modesBitfield, gameMode)) {
if (bitFieldContainsModeBitmask(modesBitfield,
GameManager.GAME_MODE_STANDARD)) {
// If the current set mode isn't supported, but we support STANDARD,
// then set the mode to STANDARD.
newGameMode = GameManager.GAME_MODE_STANDARD;
} else {
// If we don't support any game modes, then set to UNSUPPORTED
newGameMode = GameManager.GAME_MODE_UNSUPPORTED;
}
}
} else if (gameMode != GameManager.GAME_MODE_UNSUPPORTED) {
// If we have no config for the package, but the configured mode is not
// UNSUPPORTED, then set to UNSUPPORTED
newGameMode = GameManager.GAME_MODE_UNSUPPORTED;
}
if (newGameMode != gameMode) {
setGameMode(packageName, newGameMode, userId);
}
updateCompatModeDownscale(packageName, gameMode);
} }
} }
} catch (Exception e) { } catch (Exception e) {

View File

@@ -299,11 +299,13 @@ public class GameManagerServiceTests {
public void testGameMode() { public void testGameMode() {
GameManagerService gameManagerService = new GameManagerService(mMockContext); GameManagerService gameManagerService = new GameManagerService(mMockContext);
gameManagerService.onUserStarting(USER_ID_1); gameManagerService.onUserStarting(USER_ID_1);
gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
mockModifyGameModeGranted(); mockModifyGameModeGranted();
assertEquals(GameManager.GAME_MODE_UNSUPPORTED, assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
gameManagerService.getGameMode(mPackageName, USER_ID_1)); gameManagerService.getGameMode(mPackageName, USER_ID_1));
// We need to make sure the mode is supported before setting it.
mockDeviceConfigAll();
gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1); gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1);
assertEquals(GameManager.GAME_MODE_STANDARD, assertEquals(GameManager.GAME_MODE_STANDARD,
gameManagerService.getGameMode(mPackageName, USER_ID_1)); gameManagerService.getGameMode(mPackageName, USER_ID_1));
@@ -370,11 +372,13 @@ public class GameManagerServiceTests {
*/ */
@Test @Test
public void testGameModeMultipleUsers() { public void testGameModeMultipleUsers() {
mockModifyGameModeGranted();
mockDeviceConfigAll();
GameManagerService gameManagerService = new GameManagerService(mMockContext); GameManagerService gameManagerService = new GameManagerService(mMockContext);
gameManagerService.onUserStarting(USER_ID_1); gameManagerService.onUserStarting(USER_ID_1);
gameManagerService.onUserStarting(USER_ID_2); gameManagerService.onUserStarting(USER_ID_2);
gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
mockModifyGameModeGranted(); gameManagerService.updateConfigsForUser(USER_ID_2, mPackageName);
// Set User 1 to Standard // Set User 1 to Standard
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1); gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1);
@@ -603,4 +607,52 @@ public class GameManagerServiceTests {
gameManagerService.getConfig(mPackageName); gameManagerService.getConfig(mPackageName);
assertNull(config.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE)); assertNull(config.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE));
} }
/**
* Ensure that, if a game no longer supports any game modes, we set the game mode to
* UNSUPPORTED
*/
@Test
public void testUnsetInvalidGameMode() throws Exception {
mockDeviceConfigNone();
mockModifyGameModeGranted();
GameManagerService gameManagerService = new GameManagerService(mMockContext);
gameManagerService.onUserStarting(USER_ID_1);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
gameManagerService.getGameMode(mPackageName, USER_ID_1));
}
/**
* Ensure that, if a game no longer supports a specific game mode, but supports STANDARD, we set
* the game mode to STANDARD.
*/
@Test
public void testResetInvalidGameMode() throws Exception {
mockDeviceConfigPerformance();
mockModifyGameModeGranted();
GameManagerService gameManagerService = new GameManagerService(mMockContext);
gameManagerService.onUserStarting(USER_ID_1);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1);
gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
assertEquals(GameManager.GAME_MODE_STANDARD,
gameManagerService.getGameMode(mPackageName, USER_ID_1));
}
/**
* Ensure that if a game supports STANDARD, but is currently set to UNSUPPORTED, we set the game
* mode to STANDARD
*/
@Test
public void testSetValidGameMode() throws Exception {
mockDeviceConfigPerformance();
mockModifyGameModeGranted();
GameManagerService gameManagerService = new GameManagerService(mMockContext);
gameManagerService.onUserStarting(USER_ID_1);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_UNSUPPORTED, USER_ID_1);
gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
assertEquals(GameManager.GAME_MODE_STANDARD,
gameManagerService.getGameMode(mPackageName, USER_ID_1));
}
} }