Merge "Enable ANGLE as a Game Dashboard Intervention" into sc-qpr1-dev

This commit is contained in:
Tim Van Patten
2021-09-01 00:10:33 +00:00
committed by Android (Google) Code Review
5 changed files with 225 additions and 24 deletions

View File

@@ -135,6 +135,7 @@ public final class GameManager {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
} }
/** /**
* Returns a list of supported game modes for a given package. * Returns a list of supported game modes for a given package.
* <p> * <p>
@@ -151,4 +152,20 @@ public final class GameManager {
} }
} }
/**
* Returns if ANGLE is enabled for a given package.
* <p>
* The caller must have {@link android.Manifest.permission#MANAGE_GAME_MODE}.
*
* @hide
*/
@UserHandleAware
@RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
public @GameMode boolean isAngleEnabled(@NonNull String packageName) {
try {
return mService.getAngleEnabled(packageName, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
} }

View File

@@ -23,4 +23,5 @@ interface IGameManagerService {
int getGameMode(String packageName, int userId); int getGameMode(String packageName, int userId);
void setGameMode(String packageName, int gameMode, int userId); void setGameMode(String packageName, int gameMode, int userId);
int[] getAvailableGameModes(String packageName); int[] getAvailableGameModes(String packageName);
boolean getAngleEnabled(String packageName, int userId);
} }

View File

@@ -17,6 +17,7 @@
package android.os; package android.os;
import android.app.Activity; import android.app.Activity;
import android.app.GameManager;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
@@ -113,6 +114,7 @@ public class GraphicsEnvironment {
private ClassLoader mClassLoader; private ClassLoader mClassLoader;
private String mLibrarySearchPaths; private String mLibrarySearchPaths;
private String mLibraryPermittedPaths; private String mLibraryPermittedPaths;
private GameManager mGameManager;
private int mAngleOptInIndex = -1; private int mAngleOptInIndex = -1;
@@ -125,6 +127,8 @@ public class GraphicsEnvironment {
final ApplicationInfo appInfoWithMetaData = final ApplicationInfo appInfoWithMetaData =
getAppInfoWithMetadata(context, pm, packageName); getAppInfoWithMetadata(context, pm, packageName);
mGameManager = context.getSystemService(GameManager.class);
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers"); Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers");
setupGpuLayers(context, coreSettings, pm, packageName, appInfoWithMetaData); setupGpuLayers(context, coreSettings, pm, packageName, appInfoWithMetaData);
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS); Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
@@ -142,6 +146,23 @@ public class GraphicsEnvironment {
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS); Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
} }
/**
* Query to determine if the Game Mode has enabled ANGLE.
*/
private boolean isAngleEnabledByGameMode(Context context, String packageName) {
try {
final boolean gameModeEnabledAngle =
(mGameManager != null) && mGameManager.isAngleEnabled(packageName);
Log.v(TAG, "ANGLE GameManagerService for " + packageName + ": " + gameModeEnabledAngle);
return gameModeEnabledAngle;
} catch (SecurityException e) {
Log.e(TAG, "Caught exception while querying GameManagerService if ANGLE is enabled "
+ "for package: " + packageName);
}
return false;
}
/** /**
* Query to determine if ANGLE should be used * Query to determine if ANGLE should be used
*/ */
@@ -163,7 +184,9 @@ public class GraphicsEnvironment {
Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn); Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
} }
return requested; final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName);
return requested || gameModeEnabledAngle;
} }
private int getVulkanVersion(PackageManager pm) { private int getVulkanVersion(PackageManager pm) {
@@ -521,16 +544,20 @@ public class GraphicsEnvironment {
if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths); if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
// If the user has set the developer option to something other than default, // We need to call setAngleInfo() with the package name and the developer option value
// we need to call setAngleInfo() with the package name and the developer //(native/angle/other). Then later when we are actually trying to load a driver,
// option value (native/angle/other). Then later when we are actually trying to //GraphicsEnv::getShouldUseAngle() has seen the package name before and can confidently
// load a driver, GraphicsEnv::getShouldUseAngle() has seen the package name before //answer yes/no based on the previously set developer option value.
// and can confidently answer yes/no based on the previously set developer final String devOptIn;
// option value.
final String devOptIn = getDriverForPackage(context, bundle, packageName);
final String[] features = getAngleEglFeatures(context, bundle); final String[] features = getAngleEglFeatures(context, bundle);
final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName);
if (gameModeEnabledAngle) {
devOptIn = ANGLE_GL_DRIVER_CHOICE_ANGLE;
} else {
devOptIn = getDriverForPackage(context, bundle, packageName);
}
setAngleInfo(paths, packageName, devOptIn, features); setAngleInfo(paths, packageName, devOptIn, features);
return true; return true;
} }

View File

@@ -271,6 +271,13 @@ public final class GameManagerService extends IGameManagerService.Stub {
public static final String METADATA_WM_ALLOW_DOWNSCALE = public static final String METADATA_WM_ALLOW_DOWNSCALE =
"com.android.graphics.intervention.wm.allowDownscale"; "com.android.graphics.intervention.wm.allowDownscale";
/**
* Metadata that can be included in the app manifest to allow/disallow any ANGLE
* interventions. Default value is TRUE.
*/
public static final String METADATA_ANGLE_ALLOW_ANGLE =
"com.android.graphics.intervention.angle.allowAngle";
/** /**
* Metadata that needs to be included in the app manifest to OPT-IN to PERFORMANCE mode. * Metadata that needs to be included in the app manifest to OPT-IN to PERFORMANCE mode.
* This means the app will assume full responsibility for the experience provided by this * This means the app will assume full responsibility for the experience provided by this
@@ -294,6 +301,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
private boolean mPerfModeOptedIn; private boolean mPerfModeOptedIn;
private boolean mBatteryModeOptedIn; private boolean mBatteryModeOptedIn;
private boolean mAllowDownscale; private boolean mAllowDownscale;
private boolean mAllowAngle;
GamePackageConfiguration(String packageName, int userId) { GamePackageConfiguration(String packageName, int userId) {
mPackageName = packageName; mPackageName = packageName;
@@ -305,10 +313,12 @@ public final class GameManagerService extends IGameManagerService.Stub {
mPerfModeOptedIn = ai.metaData.getBoolean(METADATA_PERFORMANCE_MODE_ENABLE); mPerfModeOptedIn = ai.metaData.getBoolean(METADATA_PERFORMANCE_MODE_ENABLE);
mBatteryModeOptedIn = ai.metaData.getBoolean(METADATA_BATTERY_MODE_ENABLE); mBatteryModeOptedIn = ai.metaData.getBoolean(METADATA_BATTERY_MODE_ENABLE);
mAllowDownscale = ai.metaData.getBoolean(METADATA_WM_ALLOW_DOWNSCALE, true); mAllowDownscale = ai.metaData.getBoolean(METADATA_WM_ALLOW_DOWNSCALE, true);
mAllowAngle = ai.metaData.getBoolean(METADATA_ANGLE_ALLOW_ANGLE, true);
} else { } else {
mPerfModeOptedIn = false; mPerfModeOptedIn = false;
mBatteryModeOptedIn = false; mBatteryModeOptedIn = false;
mAllowDownscale = true; mAllowDownscale = true;
mAllowAngle = true;
} }
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
// Not all packages are installed, hence ignore those that are not installed yet. // Not all packages are installed, hence ignore those that are not installed yet.
@@ -340,14 +350,26 @@ public final class GameManagerService extends IGameManagerService.Stub {
public static final String MODE_KEY = "mode"; public static final String MODE_KEY = "mode";
public static final String SCALING_KEY = "downscaleFactor"; public static final String SCALING_KEY = "downscaleFactor";
public static final String DEFAULT_SCALING = "1.0"; public static final String DEFAULT_SCALING = "1.0";
public static final String ANGLE_KEY = "useAngle";
private final @GameMode int mGameMode; private final @GameMode int mGameMode;
private final String mScaling; private final String mScaling;
private final boolean mUseAngle;
GameModeConfiguration(KeyValueListParser parser) { GameModeConfiguration(KeyValueListParser parser) {
mGameMode = parser.getInt(MODE_KEY, GameManager.GAME_MODE_UNSUPPORTED); mGameMode = parser.getInt(MODE_KEY, GameManager.GAME_MODE_UNSUPPORTED);
mScaling = !mAllowDownscale || isGameModeOptedIn(mGameMode) // isGameModeOptedIn() returns if an app will handle all of the changes necessary
// for a particular game mode. If so, the Android framework (i.e.
// GameManagerService) will not do anything for the app (like window scaling or
// using ANGLE).
mScaling = !mAllowDownscale || willGamePerformOptimizations(mGameMode)
? DEFAULT_SCALING : parser.getString(SCALING_KEY, DEFAULT_SCALING); ? DEFAULT_SCALING : parser.getString(SCALING_KEY, DEFAULT_SCALING);
// We only want to use ANGLE if:
// - We're allowed to use ANGLE (the app hasn't opted out via the manifest) AND
// - The app has not opted in to performing the work itself AND
// - The Phenotype config has enabled it.
mUseAngle = mAllowAngle && !willGamePerformOptimizations(mGameMode)
&& parser.getBoolean(ANGLE_KEY, false);
} }
public int getGameMode() { public int getGameMode() {
@@ -358,6 +380,10 @@ public final class GameManagerService extends IGameManagerService.Stub {
return mScaling; return mScaling;
} }
public boolean getUseAngle() {
return mUseAngle;
}
public boolean isValid() { public boolean isValid() {
return (mGameMode == GameManager.GAME_MODE_PERFORMANCE return (mGameMode == GameManager.GAME_MODE_PERFORMANCE
|| mGameMode == GameManager.GAME_MODE_BATTERY) || mGameMode == GameManager.GAME_MODE_BATTERY)
@@ -368,7 +394,8 @@ public final class GameManagerService extends IGameManagerService.Stub {
* @hide * @hide
*/ */
public String toString() { public String toString() {
return "[Game Mode:" + mGameMode + ",Scaling:" + mScaling + "]"; return "[Game Mode:" + mGameMode + ",Scaling:" + mScaling + ",Use Angle:"
+ mUseAngle + "]";
} }
/** /**
@@ -384,13 +411,14 @@ public final class GameManagerService extends IGameManagerService.Stub {
} }
/** /**
* Gets whether a package has opted into a game mode via its manifest. * Returns if the app will assume full responsibility for the experience provided by this
* mode. If True, the system will not perform any interventions for the app.
* *
* @return True if the app package has specified in its metadata either: * @return True if the app package has specified in its metadata either:
* "com.android.app.gamemode.performance.enabled" or * "com.android.app.gamemode.performance.enabled" or
* "com.android.app.gamemode.battery.enabled" with a value of "true" * "com.android.app.gamemode.battery.enabled" with a value of "true"
*/ */
public boolean isGameModeOptedIn(@GameMode int gameMode) { public boolean willGamePerformOptimizations(@GameMode int gameMode) {
return (mBatteryModeOptedIn && gameMode == GameManager.GAME_MODE_BATTERY) return (mBatteryModeOptedIn && gameMode == GameManager.GAME_MODE_BATTERY)
|| (mPerfModeOptedIn && gameMode == GameManager.GAME_MODE_PERFORMANCE); || (mPerfModeOptedIn && gameMode == GameManager.GAME_MODE_PERFORMANCE);
} }
@@ -631,7 +659,34 @@ public final class GameManagerService extends IGameManagerService.Stub {
mHandler.sendMessageDelayed(msg, WRITE_SETTINGS_DELAY); mHandler.sendMessageDelayed(msg, WRITE_SETTINGS_DELAY);
} }
} }
updateCompatModeDownscale(packageName, gameMode); updateInterventions(packageName, gameMode);
}
/**
* Get if ANGLE is enabled for the package for the currently enabled game mode.
* Checks that the caller has {@link android.Manifest.permission#MANAGE_GAME_MODE}.
*/
@Override
@RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
public @GameMode boolean getAngleEnabled(String packageName, int userId)
throws SecurityException {
final int gameMode = getGameMode(packageName, userId);
if (gameMode == GameManager.GAME_MODE_UNSUPPORTED) {
return false;
}
synchronized (mDeviceConfigLock) {
final GamePackageConfiguration config = mConfigs.get(packageName);
if (config == null) {
return false;
}
GamePackageConfiguration.GameModeConfiguration gameModeConfiguration =
config.getGameModeConfiguration(gameMode);
if (gameModeConfiguration == null) {
return false;
}
return gameModeConfiguration.getUseAngle();
}
} }
/** /**
@@ -753,7 +808,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
if (DEBUG) { if (DEBUG) {
Slog.v(TAG, dumpDeviceConfigs()); Slog.v(TAG, dumpDeviceConfigs());
} }
if (packageConfig.isGameModeOptedIn(gameMode)) { if (packageConfig.willGamePerformOptimizations(gameMode)) {
disableCompatScale(packageName); disableCompatScale(packageName);
return; return;
} }
@@ -782,6 +837,17 @@ public final class GameManagerService extends IGameManagerService.Stub {
return (bitField & modeToBitmask(gameMode)) != 0; return (bitField & modeToBitmask(gameMode)) != 0;
} }
@RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
private void updateUseAngle(String packageName, @GameMode int gameMode) {
// TODO (b/188475576): Nothing to do yet. Remove if it's still empty when we're ready to
// ship.
}
private void updateInterventions(String packageName, @GameMode int gameMode) {
updateCompatModeDownscale(packageName, gameMode);
updateUseAngle(packageName, gameMode);
}
/** /**
* @hide * @hide
*/ */
@@ -839,11 +905,11 @@ public final class GameManagerService extends IGameManagerService.Stub {
if (newGameMode != gameMode) { if (newGameMode != gameMode) {
setGameMode(packageName, newGameMode, userId); setGameMode(packageName, newGameMode, userId);
} }
updateCompatModeDownscale(packageName, gameMode); updateInterventions(packageName, gameMode);
} }
} }
} catch (Exception e) { } catch (Exception e) {
Slog.e(TAG, "Failed to update compat modes for user: " + userId); Slog.e(TAG, "Failed to update compat modes for user " + userId + ": " + e);
} }
} }

View File

@@ -182,7 +182,14 @@ public class GameManagerServiceTests {
} }
private void mockDeviceConfigPerformance() { private void mockDeviceConfigPerformance() {
String configString = "mode=2,downscaleFactor=0.5"; String configString = "mode=2,downscaleFactor=0.5,useAngle=false";
when(DeviceConfig.getProperty(anyString(), anyString()))
.thenReturn(configString);
}
// ANGLE will be disabled for most apps, so treat enabling ANGLE as a special case.
private void mockDeviceConfigPerformanceEnableAngle() {
String configString = "mode=2,downscaleFactor=0.5,useAngle=true";
when(DeviceConfig.getProperty(anyString(), anyString())) when(DeviceConfig.getProperty(anyString(), anyString()))
.thenReturn(configString); .thenReturn(configString);
} }
@@ -212,7 +219,8 @@ public class GameManagerServiceTests {
} }
private void mockGameModeOptInAll() throws Exception { private void mockGameModeOptInAll() throws Exception {
final ApplicationInfo applicationInfo = new ApplicationInfo(); final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
Bundle metaDataBundle = new Bundle(); Bundle metaDataBundle = new Bundle();
metaDataBundle.putBoolean( metaDataBundle.putBoolean(
GameManagerService.GamePackageConfiguration.METADATA_PERFORMANCE_MODE_ENABLE, true); GameManagerService.GamePackageConfiguration.METADATA_PERFORMANCE_MODE_ENABLE, true);
@@ -224,7 +232,8 @@ public class GameManagerServiceTests {
} }
private void mockGameModeOptInPerformance() throws Exception { private void mockGameModeOptInPerformance() throws Exception {
final ApplicationInfo applicationInfo = new ApplicationInfo(); final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
Bundle metaDataBundle = new Bundle(); Bundle metaDataBundle = new Bundle();
metaDataBundle.putBoolean( metaDataBundle.putBoolean(
GameManagerService.GamePackageConfiguration.METADATA_PERFORMANCE_MODE_ENABLE, true); GameManagerService.GamePackageConfiguration.METADATA_PERFORMANCE_MODE_ENABLE, true);
@@ -234,7 +243,8 @@ public class GameManagerServiceTests {
} }
private void mockGameModeOptInBattery() throws Exception { private void mockGameModeOptInBattery() throws Exception {
final ApplicationInfo applicationInfo = new ApplicationInfo(); final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
Bundle metaDataBundle = new Bundle(); Bundle metaDataBundle = new Bundle();
metaDataBundle.putBoolean( metaDataBundle.putBoolean(
GameManagerService.GamePackageConfiguration.METADATA_BATTERY_MODE_ENABLE, true); GameManagerService.GamePackageConfiguration.METADATA_BATTERY_MODE_ENABLE, true);
@@ -244,7 +254,8 @@ public class GameManagerServiceTests {
} }
private void mockInterventionAllowDownscaleTrue() throws Exception { private void mockInterventionAllowDownscaleTrue() throws Exception {
final ApplicationInfo applicationInfo = new ApplicationInfo(); final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
Bundle metaDataBundle = new Bundle(); Bundle metaDataBundle = new Bundle();
metaDataBundle.putBoolean( metaDataBundle.putBoolean(
GameManagerService.GamePackageConfiguration.METADATA_WM_ALLOW_DOWNSCALE, true); GameManagerService.GamePackageConfiguration.METADATA_WM_ALLOW_DOWNSCALE, true);
@@ -254,7 +265,8 @@ public class GameManagerServiceTests {
} }
private void mockInterventionAllowDownscaleFalse() throws Exception { private void mockInterventionAllowDownscaleFalse() throws Exception {
final ApplicationInfo applicationInfo = new ApplicationInfo(); final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
Bundle metaDataBundle = new Bundle(); Bundle metaDataBundle = new Bundle();
metaDataBundle.putBoolean( metaDataBundle.putBoolean(
GameManagerService.GamePackageConfiguration.METADATA_WM_ALLOW_DOWNSCALE, false); GameManagerService.GamePackageConfiguration.METADATA_WM_ALLOW_DOWNSCALE, false);
@@ -263,6 +275,27 @@ public class GameManagerServiceTests {
.thenReturn(applicationInfo); .thenReturn(applicationInfo);
} }
private void mockInterventionAllowAngleTrue() throws Exception {
final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
Bundle metaDataBundle = new Bundle();
metaDataBundle.putBoolean(
GameManagerService.GamePackageConfiguration.METADATA_ANGLE_ALLOW_ANGLE, true);
when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
.thenReturn(applicationInfo);
}
private void mockInterventionAllowAngleFalse() throws Exception {
final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
Bundle metaDataBundle = new Bundle();
metaDataBundle.putBoolean(
GameManagerService.GamePackageConfiguration.METADATA_ANGLE_ALLOW_ANGLE, false);
applicationInfo.metaData = metaDataBundle;
when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
.thenReturn(applicationInfo);
}
/** /**
* By default game mode is not supported. * By default game mode is not supported.
*/ */
@@ -427,6 +460,19 @@ public class GameManagerServiceTests {
assertEquals(config.getGameModeConfiguration(gameMode).getScaling(), scaling); assertEquals(config.getGameModeConfiguration(gameMode).getScaling(), scaling);
} }
private void checkAngleEnabled(GameManagerService gameManagerService, int gameMode,
boolean angleEnabled) {
gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
// Validate GamePackageConfiguration returns the correct value.
GameManagerService.GamePackageConfiguration config =
gameManagerService.getConfig(mPackageName);
assertEquals(config.getGameModeConfiguration(gameMode).getUseAngle(), angleEnabled);
// Validate GameManagerService.getAngleEnabled() returns the correct value.
assertEquals(gameManagerService.getAngleEnabled(mPackageName, USER_ID_1), angleEnabled);
}
/** /**
* Phenotype device config exists, but is only propagating the default value. * Phenotype device config exists, but is only propagating the default value.
*/ */
@@ -591,6 +637,50 @@ public class GameManagerServiceTests {
checkDownscaling(GameManager.GAME_MODE_PERFORMANCE, "0.5"); checkDownscaling(GameManager.GAME_MODE_PERFORMANCE, "0.5");
} }
/**
* PERFORMANCE game mode is configured through Phenotype. The app hasn't specified any metadata.
*/
@Test
public void testInterventionAllowAngleDefault() throws Exception {
GameManagerService gameManagerService = new GameManagerService(mMockContext);
gameManagerService.onUserStarting(USER_ID_1);
mockDeviceConfigPerformance();
mockModifyGameModeGranted();
checkAngleEnabled(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, false);
}
/**
* PERFORMANCE game mode is configured through Phenotype. The app has opted-out of ANGLE.
*/
@Test
public void testInterventionAllowAngleFalse() throws Exception {
GameManagerService gameManagerService = new GameManagerService(mMockContext);
gameManagerService.onUserStarting(USER_ID_1);
mockDeviceConfigPerformanceEnableAngle();
mockInterventionAllowAngleFalse();
mockModifyGameModeGranted();
checkAngleEnabled(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, false);
}
/**
* PERFORMANCE game mode is configured through Phenotype. The app has redundantly specified
* the ANGLE metadata default value of "true".
*/
@Test
public void testInterventionAllowAngleTrue() throws Exception {
mockDeviceConfigPerformanceEnableAngle();
mockInterventionAllowAngleTrue();
GameManagerService gameManagerService = new GameManagerService(mMockContext);
gameManagerService.onUserStarting(USER_ID_1);
mockModifyGameModeGranted();
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
assertEquals(GameManager.GAME_MODE_PERFORMANCE,
gameManagerService.getGameMode(mPackageName, USER_ID_1));
checkAngleEnabled(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, true);
}
/** /**
* PERFORMANCE game mode is configured through Phenotype, but the app has also opted into the * PERFORMANCE game mode is configured through Phenotype, but the app has also opted into the
* same mode. No interventions for this game mode should be available in this case. * same mode. No interventions for this game mode should be available in this case.