Merge changes from topics "game-mode-custom", "no-game-mode-supported"

* changes:
  Add IGameModeListener and methods to add/remove in GameManagerService
  Disallow setting UNSUPPORTED mode to avoid ambiguity
  Always return STANDARD & CUSTOM game modes as available modes
This commit is contained in:
Xiang Wang
2022-11-22 04:13:35 +00:00
committed by Android (Google) Code Review
8 changed files with 277 additions and 102 deletions

View File

@@ -187,7 +187,9 @@ public final class GameManager {
* Sets the game mode for the given package.
* <p>
* The caller must have {@link android.Manifest.permission#MANAGE_GAME_MODE}.
*
* <p>
* Setting the game mode on a non-game application or setting a game to
* {@link #GAME_MODE_UNSUPPORTED} will have no effect.
* @hide
*/
@SystemApi

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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));

View File

@@ -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<Integer, GameManagerSettings> mSettings = new ArrayMap<>();
@GuardedBy("mDeviceConfigLock")
private final ArrayMap<String, GamePackageConfiguration> mConfigs = new ArrayMap<>();
// listener to caller uid map
@GuardedBy("mGameModeListenerLock")
private final ArrayMap<IGameModeListener, Integer> 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;
}

View File

@@ -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);
}
}

View File

@@ -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<IBinder.DeathRecipient> 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 <UID> 0 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.5,fps=60
com.android.app2 <UID> 1 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.5,fps=60
com.android.app1 <UID> 1 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.7,fps=30
com.android.app0 <UID> 0 2 angle=0,scaling=0.6,fps=120 3 angle=0,scaling=0.7,fps=30
com.android.app0 <UID> 1 2 angle=0,scaling=0.6,fps=120 3 angle=0,scaling=0.7,fps=30
# user 1002:
com.android.app2 <UID> 0 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.7,fps=30
com.android.app2 <UID> 1 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.7,fps=30
com.android.app1 <UID> 1 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.7,fps=30
com.android.app0 <UID> 0 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.7,fps=30
com.android.app0 <UID> 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) {

View File

@@ -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));