diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java
index 8768a02ba95e0..f92194d3ffac5 100644
--- a/core/java/android/app/GameManager.java
+++ b/core/java/android/app/GameManager.java
@@ -187,7 +187,9 @@ public final class GameManager {
* Sets the game mode for the given package.
*
* The caller must have {@link android.Manifest.permission#MANAGE_GAME_MODE}.
- *
+ *
+ * Setting the game mode on a non-game application or setting a game to
+ * {@link #GAME_MODE_UNSUPPORTED} will have no effect.
* @hide
*/
@SystemApi
diff --git a/core/java/android/app/IGameManagerService.aidl b/core/java/android/app/IGameManagerService.aidl
index f695ed32e8dda..aea097d069dce 100644
--- a/core/java/android/app/IGameManagerService.aidl
+++ b/core/java/android/app/IGameManagerService.aidl
@@ -19,20 +19,34 @@ package android.app;
import android.app.GameModeConfiguration;
import android.app.GameModeInfo;
import android.app.GameState;
+import android.app.IGameModeListener;
/**
* @hide
*/
interface IGameManagerService {
int getGameMode(String packageName, int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)")
void setGameMode(String packageName, int gameMode, int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)")
int[] getAvailableGameModes(String packageName);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)")
boolean isAngleEnabled(String packageName, int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)")
void notifyGraphicsEnvironmentSetup(String packageName, int userId);
void setGameState(String packageName, in GameState gameState, int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)")
GameModeInfo getGameModeInfo(String packageName, int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.SET_GAME_SERVICE)")
void setGameServiceProvider(String packageName);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)")
void updateResolutionScalingFactor(String packageName, int gameMode, float scalingFactor, int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)")
float getResolutionScalingFactor(String packageName, int gameMode, int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)")
void updateCustomGameModeConfiguration(String packageName, in GameModeConfiguration gameModeConfig, int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)")
+ void addGameModeListener(IGameModeListener gameModeListener);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)")
+ void removeGameModeListener(IGameModeListener gameModeListener);
}
diff --git a/core/java/android/app/IGameModeListener.aidl b/core/java/android/app/IGameModeListener.aidl
new file mode 100644
index 0000000000000..77fcac07f7e74
--- /dev/null
+++ b/core/java/android/app/IGameModeListener.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+/** @hide */
+interface IGameModeListener {
+ /**
+ * Called when the game mode of the user has changed.
+ */
+ void onGameModeChanged(String packageName, int gameModeFrom, int gameModeTo, int userId);
+}
diff --git a/core/tests/GameManagerTests/src/android/app/GameManagerTests.java b/core/tests/GameManagerTests/src/android/app/GameManagerTests.java
index 207ab2a271124..fac3a0ecdec2a 100644
--- a/core/tests/GameManagerTests/src/android/app/GameManagerTests.java
+++ b/core/tests/GameManagerTests/src/android/app/GameManagerTests.java
@@ -50,15 +50,11 @@ public final class GameManagerTests {
mPackageName = mContext.getPackageName();
// Reset the Game Mode for the test app, since it persists across invocations.
- mGameManager.setGameMode(mPackageName, GameManager.GAME_MODE_UNSUPPORTED);
+ mGameManager.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD);
}
@Test
public void testPublicApiGameModeGetterSetter() {
- assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
- mGameManager.getGameMode());
-
- mGameManager.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD);
assertEquals(GameManager.GAME_MODE_STANDARD,
mGameManager.getGameMode());
@@ -73,10 +69,6 @@ public final class GameManagerTests {
@Test
public void testPrivilegedGameModeGetterSetter() {
- assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
- mGameManager.getGameMode(mPackageName));
-
- mGameManager.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD);
assertEquals(GameManager.GAME_MODE_STANDARD,
mGameManager.getGameMode(mPackageName));
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 14601da634d99..b92c1635d7c61 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -39,6 +39,7 @@ import android.app.GameModeConfiguration;
import android.app.GameModeInfo;
import android.app.GameState;
import android.app.IGameManagerService;
+import android.app.IGameModeListener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -58,10 +59,12 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManagerInternal;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserManager;
@@ -132,6 +135,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
private final Context mContext;
private final Object mLock = new Object();
private final Object mDeviceConfigLock = new Object();
+ private final Object mGameModeListenerLock = new Object();
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
final Handler mHandler;
private final PackageManager mPackageManager;
@@ -145,6 +149,9 @@ public final class GameManagerService extends IGameManagerService.Stub {
private final ArrayMap mSettings = new ArrayMap<>();
@GuardedBy("mDeviceConfigLock")
private final ArrayMap mConfigs = new ArrayMap<>();
+ // listener to caller uid map
+ @GuardedBy("mGameModeListenerLock")
+ private final ArrayMap mGameModeListeners = new ArrayMap<>();
@Nullable
private final GameServiceController mGameServiceController;
@@ -598,6 +605,14 @@ public final class GameManagerService extends IGameManagerService.Stub {
}
}
+ // used to check if the override package config has any game mode config, if not, it's
+ // considered empty and safe to delete from settings
+ boolean hasActiveGameModeConfig() {
+ synchronized (mModeConfigLock) {
+ return !mModeConfigs.isEmpty();
+ }
+ }
+
/**
* GameModeConfiguration contains all the values for all the interventions associated with
* a game mode.
@@ -693,7 +708,8 @@ public final class GameManagerService extends IGameManagerService.Stub {
public boolean isActive() {
return (mGameMode == GameManager.GAME_MODE_STANDARD
|| mGameMode == GameManager.GAME_MODE_PERFORMANCE
- || mGameMode == GameManager.GAME_MODE_BATTERY)
+ || mGameMode == GameManager.GAME_MODE_BATTERY
+ || mGameMode == GameManager.GAME_MODE_CUSTOM)
&& !willGamePerformOptimizations(mGameMode);
}
@@ -741,7 +757,8 @@ public final class GameManagerService extends IGameManagerService.Stub {
}
private int getAvailableGameModesBitfield() {
- int field = 0;
+ int field = modeToBitmask(GameManager.GAME_MODE_CUSTOM)
+ | modeToBitmask(GameManager.GAME_MODE_STANDARD);
synchronized (mModeConfigLock) {
for (final int mode : mModeConfigs.keySet()) {
field |= modeToBitmask(mode);
@@ -753,13 +770,6 @@ public final class GameManagerService extends IGameManagerService.Stub {
if (mPerfModeOptedIn) {
field |= modeToBitmask(GameManager.GAME_MODE_PERFORMANCE);
}
- // The lowest bit is reserved for UNSUPPORTED, STANDARD is supported if we support any
- // other mode.
- if (field > 1) {
- field |= modeToBitmask(GameManager.GAME_MODE_STANDARD);
- } else {
- field |= modeToBitmask(GameManager.GAME_MODE_UNSUPPORTED);
- }
return field;
}
@@ -881,7 +891,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
private final class LocalService extends GameManagerInternal {
@Override
public float getResolutionScalingFactor(String packageName, int userId) {
- final int gameMode = getGameModeFromSettings(packageName, userId);
+ final int gameMode = getGameModeFromSettingsUnchecked(packageName, userId);
return getResolutionScalingFactorInternal(packageName, gameMode, userId);
}
}
@@ -960,7 +970,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
config = mConfigs.get(packageName);
}
if (config == null) {
- return new int[]{};
+ return new int[]{GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_CUSTOM};
}
return config.getAvailableGameModes();
}
@@ -986,12 +996,13 @@ public final class GameManagerService extends IGameManagerService.Stub {
return getAvailableGameModesUnchecked(packageName);
}
- private @GameMode int getGameModeFromSettings(String packageName, @UserIdInt int userId) {
+ private @GameMode int getGameModeFromSettingsUnchecked(String packageName,
+ @UserIdInt int userId) {
synchronized (mLock) {
if (!mSettings.containsKey(userId)) {
Slog.d(TAG, "User ID '" + userId + "' does not have a Game Mode"
- + " selected for package: '" + packageName + "'");
- return GameManager.GAME_MODE_UNSUPPORTED;
+ + " selected for package: '" + packageName + "'");
+ return GameManager.GAME_MODE_STANDARD;
}
return mSettings.get(userId).getGameModeLocked(packageName);
@@ -1024,12 +1035,12 @@ public final class GameManagerService extends IGameManagerService.Stub {
// return a value if the package name is valid. Next, check if the caller has the necessary
// permission and return a value. Do this check last, since it can throw an exception.
if (isValidPackageName(packageName, userId)) {
- return getGameModeFromSettings(packageName, userId);
+ return getGameModeFromSettingsUnchecked(packageName, userId);
}
// Since the package name doesn't match, check the caller has the necessary permission.
checkPermission(Manifest.permission.MANAGE_GAME_MODE);
- return getGameModeFromSettings(packageName, userId);
+ return getGameModeFromSettingsUnchecked(packageName, userId);
}
/**
@@ -1054,7 +1065,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
return null;
}
- final @GameMode int activeGameMode = getGameModeFromSettings(packageName, userId);
+ final @GameMode int activeGameMode = getGameModeFromSettingsUnchecked(packageName, userId);
final GamePackageConfiguration config = getConfig(packageName, userId);
if (config != null) {
final @GameMode int[] optedInGameModes = config.getOptedInGameModes();
@@ -1077,7 +1088,10 @@ public final class GameManagerService extends IGameManagerService.Stub {
}
return gameModeInfoBuilder.build();
} else {
- return new GameModeInfo.Builder().setActiveGameMode(activeGameMode).build();
+ return new GameModeInfo.Builder()
+ .setActiveGameMode(activeGameMode)
+ .setAvailableGameModes(getAvailableGameModesUnchecked(packageName))
+ .build();
}
}
@@ -1091,11 +1105,11 @@ public final class GameManagerService extends IGameManagerService.Stub {
throws SecurityException {
checkPermission(Manifest.permission.MANAGE_GAME_MODE);
- if (!isPackageGame(packageName, userId)) {
- // Restrict to games only.
+ if (!isPackageGame(packageName, userId) || gameMode == GameManager.GAME_MODE_UNSUPPORTED) {
+ // Restrict to games and valid game modes only.
return;
}
-
+ int fromGameMode;
synchronized (mLock) {
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, true, "setGameMode",
@@ -1107,9 +1121,21 @@ public final class GameManagerService extends IGameManagerService.Stub {
return;
}
GameManagerSettings userSettings = mSettings.get(userId);
+ fromGameMode = userSettings.getGameModeLocked(packageName);
userSettings.setGameModeLocked(packageName, gameMode);
}
updateInterventions(packageName, gameMode, userId);
+ synchronized (mGameModeListenerLock) {
+ for (IGameModeListener listener : mGameModeListeners.keySet()) {
+ Binder.allowBlocking(listener.asBinder());
+ try {
+ listener.onGameModeChanged(packageName, fromGameMode, gameMode, userId);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Cannot notify game mode change for listener added by "
+ + mGameModeListeners.get(listener));
+ }
+ }
+ }
sendUserMessage(userId, WRITE_SETTINGS, "SET_GAME_MODE", WRITE_DELAY_MILLIS);
sendUserMessage(userId, WRITE_GAME_MODE_INTERVENTION_LIST_FILE,
"SET_GAME_MODE", 0 /*delayMillis*/);
@@ -1334,6 +1360,57 @@ public final class GameManagerService extends IGameManagerService.Stub {
+ internalConfig.getScaling());
}
+ /**
+ * Adds a game mode listener.
+ *
+ * @throws SecurityException if caller doesn't have
+ * {@link android.Manifest.permission#MANAGE_GAME_MODE}
+ * permission.
+ */
+ @Override
+ @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
+ public void addGameModeListener(@NonNull IGameModeListener listener) {
+ checkPermission(Manifest.permission.MANAGE_GAME_MODE);
+ try {
+ final IBinder listenerBinder = listener.asBinder();
+ listenerBinder.linkToDeath(new DeathRecipient() {
+ @Override public void binderDied() {
+ // TODO(b/258851194): add traces on binder death based listener removal
+ removeGameModeListenerUnchecked(listener);
+ listenerBinder.unlinkToDeath(this, 0 /*flags*/);
+ }
+ }, 0 /*flags*/);
+ synchronized (mGameModeListenerLock) {
+ mGameModeListeners.put(listener, Binder.getCallingUid());
+ }
+ } catch (RemoteException ex) {
+ Slog.e(TAG,
+ "Failed to link death recipient for IGameModeListener from caller "
+ + Binder.getCallingUid() + ", abandoned its listener registration", ex);
+ }
+ }
+
+ /**
+ * Removes a game mode listener.
+ *
+ * @throws SecurityException if caller doesn't have
+ * {@link android.Manifest.permission#MANAGE_GAME_MODE}
+ * permission.
+ */
+ @Override
+ @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
+ public void removeGameModeListener(@NonNull IGameModeListener listener) {
+ // TODO(b/258851194): add traces on manual listener removal
+ checkPermission(Manifest.permission.MANAGE_GAME_MODE);
+ removeGameModeListenerUnchecked(listener);
+ }
+
+ private void removeGameModeListenerUnchecked(IGameModeListener listener) {
+ synchronized (mGameModeListenerLock) {
+ mGameModeListeners.remove(listener);
+ }
+ }
+
/**
* Notified when boot is completed.
*/
@@ -1474,7 +1551,8 @@ public final class GameManagerService extends IGameManagerService.Stub {
final GamePackageConfiguration packageConfig = getConfig(packageName, userId);
if (gameMode == GameManager.GAME_MODE_STANDARD
|| gameMode == GameManager.GAME_MODE_UNSUPPORTED || packageConfig == null
- || packageConfig.willGamePerformOptimizations(gameMode)) {
+ || packageConfig.willGamePerformOptimizations(gameMode)
+ || packageConfig.getGameModeConfiguration(gameMode) == null) {
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.
@@ -1562,13 +1640,9 @@ public final class GameManagerService extends IGameManagerService.Stub {
if (!bitFieldContainsModeBitmask(modesBitfield, gameModeToReset)) {
return;
}
- // if the game mode to reset is the only mode other than standard mode or there
- // is device config, the entire package config override is removed.
- if (Integer.bitCount(modesBitfield) <= 2 || deviceConfig == null) {
+ configOverride.removeModeConfig(gameModeToReset);
+ if (!configOverride.hasActiveGameModeConfig()) {
settings.removeConfigOverride(packageName);
- } else {
- // otherwise we reset the mode by removing the game mode config override
- configOverride.removeModeConfig(gameModeToReset);
}
} else {
settings.removeConfigOverride(packageName);
@@ -1596,20 +1670,12 @@ public final class GameManagerService extends IGameManagerService.Stub {
// 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;
- }
+ // always default to STANDARD if there is no mode config
+ newGameMode = GameManager.GAME_MODE_STANDARD;
}
- } 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;
+ } else {
+ // always default to STANDARD if there is no package config
+ newGameMode = GameManager.GAME_MODE_STANDARD;
}
return newGameMode;
}
diff --git a/services/core/java/com/android/server/app/GameManagerSettings.java b/services/core/java/com/android/server/app/GameManagerSettings.java
index 1e688371fa4d8..638bc4e7a0700 100644
--- a/services/core/java/com/android/server/app/GameManagerSettings.java
+++ b/services/core/java/com/android/server/app/GameManagerSettings.java
@@ -90,9 +90,14 @@ public class GameManagerSettings {
*/
int getGameModeLocked(String packageName) {
if (mGameModes.containsKey(packageName)) {
- return mGameModes.get(packageName);
+ final int gameMode = mGameModes.get(packageName);
+ if (gameMode == GameManager.GAME_MODE_UNSUPPORTED) {
+ // force replace cached UNSUPPORTED mode with STANDARD starting in U
+ return GameManager.GAME_MODE_STANDARD;
+ }
+ return gameMode;
}
- return GameManager.GAME_MODE_UNSUPPORTED;
+ return GameManager.GAME_MODE_STANDARD;
}
/**
@@ -255,7 +260,7 @@ public class GameManagerSettings {
XmlUtils.skipCurrentTag(parser);
return;
}
- int gameMode = GameManager.GAME_MODE_UNSUPPORTED;
+ int gameMode;
try {
gameMode = parser.getAttributeInt(null, ATTR_GAME_MODE);
} catch (XmlPullParserException e) {
@@ -282,7 +287,7 @@ public class GameManagerSettings {
+ type);
}
}
- if (config.getAvailableGameModes().length > 1) {
+ if (config.hasActiveGameModeConfig()) {
mConfigOverrides.put(name, config);
}
}
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 09d0683bdb4e5..dc77762795c7e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -33,6 +33,7 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -43,6 +44,7 @@ import android.app.GameManager;
import android.app.GameModeConfiguration;
import android.app.GameModeInfo;
import android.app.GameState;
+import android.app.IGameModeListener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
@@ -57,7 +59,9 @@ import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.hardware.power.Mode;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.PowerManagerInternal;
+import android.os.RemoteException;
import android.os.UserManager;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
@@ -74,7 +78,9 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoSession;
@@ -110,6 +116,9 @@ public class GameManagerServiceTests {
private UserManager mMockUserManager;
private BroadcastReceiver mShutDownActionReceiver;
+ @Captor
+ ArgumentCaptor mDeathRecipientCaptor;
+
// Stolen from ConnectivityServiceTest.MockContext
class MockContext extends ContextWrapper {
private static final String TAG = "MockContext";
@@ -444,7 +453,7 @@ public class GameManagerServiceTests {
}
/**
- * By default game mode is not supported.
+ * By default game mode is set to STANDARD
*/
@Test
public void testGameModeDefaultValue() {
@@ -454,7 +463,7 @@ public class GameManagerServiceTests {
startUser(gameManagerService, USER_ID_1);
mockModifyGameModeGranted();
- assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
+ assertEquals(GameManager.GAME_MODE_STANDARD,
gameManagerService.getGameMode(mPackageName, USER_ID_1));
}
@@ -470,7 +479,7 @@ public class GameManagerServiceTests {
mockModifyGameModeGranted();
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_2);
- assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
+ assertEquals(GameManager.GAME_MODE_STANDARD,
gameManagerService.getGameMode(mPackageName, USER_ID_2));
}
@@ -486,7 +495,7 @@ public class GameManagerServiceTests {
startUser(gameManagerService, USER_ID_1);
gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName);
mockModifyGameModeGranted();
- assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
+ assertEquals(GameManager.GAME_MODE_STANDARD,
gameManagerService.getGameMode(mPackageName, USER_ID_1));
// We need to make sure the mode is supported before setting it.
mockDeviceConfigAll();
@@ -679,7 +688,8 @@ public class GameManagerServiceTests {
public void testDeviceConfigDefault() {
mockDeviceConfigDefault();
mockModifyGameModeGranted();
- checkReportedAvailableGameModes(createServiceAndStartUser(USER_ID_1));
+ checkReportedAvailableGameModes(createServiceAndStartUser(USER_ID_1),
+ GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_CUSTOM);
}
/**
@@ -689,7 +699,8 @@ public class GameManagerServiceTests {
public void testDeviceConfigNone() {
mockDeviceConfigNone();
mockModifyGameModeGranted();
- checkReportedAvailableGameModes(createServiceAndStartUser(USER_ID_1));
+ checkReportedAvailableGameModes(createServiceAndStartUser(USER_ID_1),
+ GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_CUSTOM);
}
/**
@@ -699,7 +710,8 @@ public class GameManagerServiceTests {
public void testDeviceConfigInvalid() {
mockDeviceConfigInvalid();
mockModifyGameModeGranted();
- checkReportedAvailableGameModes(createServiceAndStartUser(USER_ID_1));
+ checkReportedAvailableGameModes(createServiceAndStartUser(USER_ID_1),
+ GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_CUSTOM);
}
/**
@@ -709,7 +721,8 @@ public class GameManagerServiceTests {
public void testDeviceConfigMalformed() {
mockDeviceConfigMalformed();
mockModifyGameModeGranted();
- checkReportedAvailableGameModes(createServiceAndStartUser(USER_ID_1));
+ checkReportedAvailableGameModes(createServiceAndStartUser(USER_ID_1),
+ GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_CUSTOM);
}
/**
@@ -727,7 +740,7 @@ public class GameManagerServiceTests {
GameManager.GAME_MODE_PERFORMANCE, "120", "0.3");
checkReportedAvailableGameModes(gameManagerService, GameManager.GAME_MODE_PERFORMANCE,
- GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_CUSTOM);
checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0.3f);
checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 120);
}
@@ -747,7 +760,7 @@ public class GameManagerServiceTests {
GameManager.GAME_MODE_BATTERY, "60", "0.5");
checkReportedAvailableGameModes(gameManagerService, GameManager.GAME_MODE_BATTERY,
- GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_CUSTOM);
checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, 0.5f);
checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 60);
}
@@ -769,7 +782,8 @@ public class GameManagerServiceTests {
GameManager.GAME_MODE_BATTERY, "60", "0.5");
checkReportedAvailableGameModes(gameManagerService, GameManager.GAME_MODE_PERFORMANCE,
- GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD,
+ GameManager.GAME_MODE_CUSTOM);
checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0.3f);
checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 120);
checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, 0.5f);
@@ -863,7 +877,7 @@ public class GameManagerServiceTests {
GameManager.GAME_MODE_PERFORMANCE);
checkReportedAvailableGameModes(gameManagerService, GameManager.GAME_MODE_PERFORMANCE,
- GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_CUSTOM);
checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0.5f);
checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90);
}
@@ -886,7 +900,7 @@ public class GameManagerServiceTests {
GameManager.GAME_MODE_BATTERY);
checkReportedAvailableGameModes(gameManagerService, GameManager.GAME_MODE_BATTERY,
- GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_CUSTOM);
checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, 0.7f);
checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 30);
}
@@ -910,7 +924,8 @@ public class GameManagerServiceTests {
gameManagerService.resetGameModeConfigOverride(mPackageName, USER_ID_1, -1);
checkReportedAvailableGameModes(gameManagerService, GameManager.GAME_MODE_PERFORMANCE,
- GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD,
+ GameManager.GAME_MODE_CUSTOM);
checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0.5f);
checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90);
checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, 0.7f);
@@ -939,7 +954,8 @@ public class GameManagerServiceTests {
GameManager.GAME_MODE_BATTERY);
checkReportedAvailableGameModes(gameManagerService, GameManager.GAME_MODE_PERFORMANCE,
- GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD,
+ GameManager.GAME_MODE_CUSTOM);
checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0.3f);
checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 120);
checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, 0.7f);
@@ -956,7 +972,7 @@ public class GameManagerServiceTests {
mockModifyGameModeGranted();
checkReportedAvailableGameModes(createServiceAndStartUser(USER_ID_1),
GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_BATTERY,
- GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_CUSTOM);
}
@@ -969,7 +985,8 @@ public class GameManagerServiceTests {
mockDeviceConfigNone();
mockModifyGameModeGranted();
checkReportedAvailableGameModes(createServiceAndStartUser(USER_ID_1),
- GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD,
+ GameManager.GAME_MODE_CUSTOM);
}
/**
@@ -981,7 +998,8 @@ public class GameManagerServiceTests {
mockDeviceConfigNone();
mockModifyGameModeGranted();
checkReportedAvailableGameModes(createServiceAndStartUser(USER_ID_1),
- GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_STANDARD,
+ GameManager.GAME_MODE_CUSTOM);
}
/**
@@ -995,7 +1013,7 @@ public class GameManagerServiceTests {
mockModifyGameModeGranted();
checkReportedAvailableGameModes(createServiceAndStartUser(USER_ID_1),
GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_BATTERY,
- GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_CUSTOM);
}
/**
@@ -1009,7 +1027,7 @@ public class GameManagerServiceTests {
mockModifyGameModeGranted();
checkReportedAvailableGameModes(createServiceAndStartUser(USER_ID_1),
GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_BATTERY,
- GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_CUSTOM);
}
/**
@@ -1181,7 +1199,7 @@ public class GameManagerServiceTests {
/**
* Ensure that, if a game no longer supports any game modes, we set the game mode to
- * UNSUPPORTED
+ * STANDARD
*/
@Test
public void testUnsetInvalidGameMode() throws Exception {
@@ -1192,7 +1210,7 @@ public class GameManagerServiceTests {
startUser(gameManagerService, USER_ID_1);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName);
- assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
+ assertEquals(GameManager.GAME_MODE_STANDARD,
gameManagerService.getGameMode(mPackageName, USER_ID_1));
}
@@ -1260,7 +1278,8 @@ public class GameManagerServiceTests {
assertTrue(gameModeInfo.isFpsOverrideAllowed());
checkReportedAvailableGameModes(gameManagerService, GameManager.GAME_MODE_PERFORMANCE,
- GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD,
+ GameManager.GAME_MODE_CUSTOM);
checkReportedOptedInGameModes(gameManagerService);
assertEquals(new GameModeConfiguration.Builder()
@@ -1286,7 +1305,8 @@ public class GameManagerServiceTests {
assertEquals(GameManager.GAME_MODE_BATTERY, gameModeInfo.getActiveGameMode());
checkReportedAvailableGameModes(gameManagerService,
- GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD,
+ GameManager.GAME_MODE_CUSTOM);
checkReportedOptedInGameModes(gameManagerService);
assertNotNull(gameModeInfo.getGameModeConfiguration(GameManager.GAME_MODE_BATTERY));
@@ -1305,7 +1325,8 @@ public class GameManagerServiceTests {
assertEquals(GameManager.GAME_MODE_PERFORMANCE, gameModeInfo.getActiveGameMode());
checkReportedAvailableGameModes(gameManagerService,
- GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_STANDARD,
+ GameManager.GAME_MODE_CUSTOM);
checkReportedOptedInGameModes(gameManagerService);
assertNotNull(gameModeInfo.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE));
@@ -1313,7 +1334,7 @@ public class GameManagerServiceTests {
}
@Test
- public void testGetGameModeInfoWithUnsupportedGameMode() {
+ public void testGetGameModeInfoWithDefaultGameModes() {
mockDeviceConfigNone();
mockModifyGameModeGranted();
GameManagerService gameManagerService =
@@ -1321,9 +1342,11 @@ public class GameManagerServiceTests {
startUser(gameManagerService, USER_ID_1);
GameModeInfo gameModeInfo = gameManagerService.getGameModeInfo(mPackageName, USER_ID_1);
- assertEquals(GameManager.GAME_MODE_UNSUPPORTED, gameModeInfo.getActiveGameMode());
- checkReportedAvailableGameModes(gameManagerService);
-
+ assertEquals(GameManager.GAME_MODE_STANDARD, gameModeInfo.getActiveGameMode());
+ checkReportedAvailableGameModes(gameManagerService, GameManager.GAME_MODE_STANDARD,
+ GameManager.GAME_MODE_CUSTOM);
+ assertNull(gameModeInfo.getGameModeConfiguration(GameManager.GAME_MODE_CUSTOM));
+ assertNull(gameModeInfo.getGameModeConfiguration(GameManager.GAME_MODE_STANDARD));
assertNull(gameModeInfo.getGameModeConfiguration(GameManager.GAME_MODE_BATTERY));
assertNull(gameModeInfo.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE));
}
@@ -1363,7 +1386,7 @@ public class GameManagerServiceTests {
GameModeInfo gameModeInfo) {
checkReportedAvailableGameModes(gameManagerService,
GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_BATTERY,
- GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_CUSTOM);
checkReportedOptedInGameModes(gameManagerService,
GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_BATTERY);
assertTrue(gameModeInfo.isFpsOverrideAllowed());
@@ -1381,7 +1404,7 @@ public class GameManagerServiceTests {
assertEquals(GameManager.GAME_MODE_STANDARD, gameModeInfo.getActiveGameMode());
checkReportedAvailableGameModes(gameManagerService, GameManager.GAME_MODE_BATTERY,
- GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_CUSTOM);
checkReportedOptedInGameModes(gameManagerService, GameManager.GAME_MODE_BATTERY);
assertNull(gameModeInfo.getGameModeConfiguration(GameManager.GAME_MODE_BATTERY));
@@ -1399,7 +1422,8 @@ public class GameManagerServiceTests {
assertEquals(GameManager.GAME_MODE_STANDARD, gameModeInfo.getActiveGameMode());
checkReportedAvailableGameModes(gameManagerService, GameManager.GAME_MODE_PERFORMANCE,
- GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD);
+ GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD,
+ GameManager.GAME_MODE_CUSTOM);
checkReportedOptedInGameModes(gameManagerService, GameManager.GAME_MODE_PERFORMANCE);
assertNotNull(gameModeInfo.getGameModeConfiguration(GameManager.GAME_MODE_BATTERY));
@@ -1526,14 +1550,14 @@ public class GameManagerServiceTests {
/* Expected fileOutput (order may vary)
# user 1001:
- com.android.app2 0 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.5,fps=60
+ com.android.app2 1 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.5,fps=60
com.android.app1 1 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.7,fps=30
- com.android.app0 0 2 angle=0,scaling=0.6,fps=120 3 angle=0,scaling=0.7,fps=30
+ com.android.app0 1 2 angle=0,scaling=0.6,fps=120 3 angle=0,scaling=0.7,fps=30
# user 1002:
- com.android.app2 0 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.7,fps=30
+ com.android.app2 1 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.7,fps=30
com.android.app1 1 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.7,fps=30
- com.android.app0 0 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.7,fps=30
+ com.android.app0 1 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.7,fps=30
The current game mode would only be set to non-zero if the current user have that game
installed.
*/
@@ -1550,7 +1574,7 @@ public class GameManagerServiceTests {
assertEquals(splitLine[6], "angle=0,scaling=0.5,fps=60");
splitLine = fileOutput.get(1).split("\\s+");
assertEquals(splitLine[0], "com.android.app1");
- assertEquals(splitLine[2], "0");
+ assertEquals(splitLine[2], "1");
assertEquals(splitLine[3], "2");
assertEquals(splitLine[4], "angle=0,scaling=0.5,fps=90");
assertEquals(splitLine[5], "3");
@@ -1573,7 +1597,7 @@ public class GameManagerServiceTests {
splitLine = fileOutput.get(0).split("\\s+");
assertEquals(splitLine[0], "com.android.app2");
- assertEquals(splitLine[2], "0");
+ assertEquals(splitLine[2], "1");
assertEquals(splitLine[3], "2");
assertEquals(splitLine[4], "angle=0,scaling=0.5,fps=90");
assertEquals(splitLine[5], "3");
@@ -1587,7 +1611,7 @@ public class GameManagerServiceTests {
assertEquals(splitLine[6], "angle=0,scaling=0.7,fps=30");
splitLine = fileOutput.get(2).split("\\s+");
assertEquals(splitLine[0], "com.android.app0");
- assertEquals(splitLine[2], "0");
+ assertEquals(splitLine[2], "1");
assertEquals(splitLine[3], "2");
assertEquals(splitLine[4], "angle=0,scaling=0.5,fps=90");
assertEquals(splitLine[5], "3");
@@ -1608,7 +1632,7 @@ public class GameManagerServiceTests {
startUser(gameManagerService, USER_ID_2);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1);
checkReportedAvailableGameModes(gameManagerService, GameManager.GAME_MODE_STANDARD,
- GameManager.GAME_MODE_BATTERY);
+ GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_CUSTOM);
assertEquals(gameManagerService.getGameMode(mPackageName, USER_ID_1),
GameManager.GAME_MODE_BATTERY);
@@ -1617,15 +1641,15 @@ public class GameManagerServiceTests {
assertEquals(gameManagerService.getGameMode(mPackageName, USER_ID_2),
GameManager.GAME_MODE_STANDARD);
checkReportedAvailableGameModes(gameManagerService, GameManager.GAME_MODE_STANDARD,
- GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_PERFORMANCE);
- gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_2);
- gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1);
+ GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_PERFORMANCE,
+ GameManager.GAME_MODE_CUSTOM);
switchUser(gameManagerService, USER_ID_2, USER_ID_1);
+ assertEquals(gameManagerService.getGameMode(mPackageName, USER_ID_1),
+ GameManager.GAME_MODE_BATTERY);
checkReportedAvailableGameModes(gameManagerService, GameManager.GAME_MODE_STANDARD,
- GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_PERFORMANCE);
- gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_2);
- gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1);
+ GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_PERFORMANCE,
+ GameManager.GAME_MODE_CUSTOM);
}
@Test
@@ -1859,6 +1883,53 @@ public class GameManagerServiceTests {
ArgumentMatchers.eq(0.0f));
}
+ @Test
+ public void testAddGameModeListener() throws RemoteException {
+ GameManagerService gameManagerService =
+ new GameManagerService(mMockContext, mTestLooper.getLooper());
+ mockDeviceConfigAll();
+ startUser(gameManagerService, USER_ID_1);
+ mockModifyGameModeGranted();
+
+ IGameModeListener mockListener = Mockito.mock(IGameModeListener.class);
+ IBinder binder = Mockito.mock(IBinder.class);
+ when(mockListener.asBinder()).thenReturn(binder);
+ gameManagerService.addGameModeListener(mockListener);
+ verify(binder).linkToDeath(mDeathRecipientCaptor.capture(), anyInt());
+
+ gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+ verify(mockListener).onGameModeChanged(mPackageName, GameManager.GAME_MODE_STANDARD,
+ GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+ reset(mockListener);
+ gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1);
+ verify(mockListener).onGameModeChanged(mPackageName, GameManager.GAME_MODE_PERFORMANCE,
+ GameManager.GAME_MODE_BATTERY, USER_ID_1);
+ reset(mockListener);
+
+ mDeathRecipientCaptor.getValue().binderDied();
+ verify(binder).unlinkToDeath(eq(mDeathRecipientCaptor.getValue()), anyInt());
+ gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_CUSTOM, USER_ID_1);
+ verify(mockListener, never()).onGameModeChanged(anyString(), anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void testRemoveGameModeListener() throws RemoteException {
+ GameManagerService gameManagerService =
+ new GameManagerService(mMockContext, mTestLooper.getLooper());
+ mockDeviceConfigAll();
+ startUser(gameManagerService, USER_ID_1);
+ mockModifyGameModeGranted();
+
+ IGameModeListener mockListener = Mockito.mock(IGameModeListener.class);
+ IBinder binder = Mockito.mock(IBinder.class);
+ when(mockListener.asBinder()).thenReturn(binder);
+
+ gameManagerService.addGameModeListener(mockListener);
+ gameManagerService.removeGameModeListener(mockListener);
+ gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+ verify(mockListener, never()).onGameModeChanged(anyString(), anyInt(), anyInt(), anyInt());
+ }
+
private static void deleteFolder(File folder) {
File[] files = folder.listFiles();
if (files != null) {
diff --git a/services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java b/services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java
index e8dd541b05313..582c78bce54c7 100644
--- a/services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java
@@ -192,7 +192,7 @@ public class GameManagerServiceSettingsTests {
final Context context = InstrumentationRegistry.getContext();
GameManagerSettings settings = new GameManagerSettings(context.getFilesDir());
assertTrue(settings.readPersistentDataLocked());
- assertEquals(0, settings.getGameModeLocked(PACKAGE_NAME_1));
+ assertEquals(1, settings.getGameModeLocked(PACKAGE_NAME_1));
assertEquals(2, settings.getGameModeLocked(PACKAGE_NAME_2));
assertEquals(3, settings.getGameModeLocked(PACKAGE_NAME_3));