Introduce new game mode config xml resource file

If the new resource file parser fail to parse the boolean values from
the resource file due to tag not found in manifest or missing file, the
existing metadata values will be used to populate pre-existing flags

Bug: 214448560
Test: atest GameManagerTest
Change-Id: I1543a1bb84379a2e9322a65d41e44fa6014821b9
This commit is contained in:
Xiang Wang
2022-01-14 02:04:48 +00:00
parent 052cb99b8f
commit 7998c248cc
9 changed files with 115 additions and 20 deletions

View File

@@ -326,6 +326,8 @@ package android {
field public static final int allowClearUserData = 16842757; // 0x1010005
field public static final int allowClickWhenDisabled = 16844312; // 0x1010618
field public static final int allowEmbedded = 16843765; // 0x10103f5
field public static final int allowGameAngleDriver;
field public static final int allowGameDownscaling;
field public static final int allowNativeHeapPointerTagging = 16844306; // 0x1010612
field public static final int allowParallelSyncs = 16843570; // 0x1010332
field public static final int allowSingleTap = 16843353; // 0x1010259
@@ -1435,10 +1437,12 @@ package android {
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportedTypes;
field public static final int supportsAssist = 16844016; // 0x10104f0
field public static final int supportsBatteryGameMode;
field public static final int supportsInlineSuggestions = 16844301; // 0x101060d
field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
field public static final int supportsLocalInteraction = 16844047; // 0x101050f
field public static final int supportsMultipleDisplays = 16844182; // 0x1010596
field public static final int supportsPerformanceGameMode;
field public static final int supportsPictureInPicture = 16844023; // 0x10104f7
field public static final int supportsRtl = 16843695; // 0x10103af
field public static final int supportsStylusHandwriting;

View File

@@ -278,6 +278,7 @@ package android.app {
}
public final class GameManager {
method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE) public boolean isAngleEnabled(@NonNull String);
method public void setGameServiceProvider(@Nullable String);
}

View File

@@ -181,14 +181,18 @@ public final class GameManager {
/**
* Returns if ANGLE is enabled for a given package and user ID.
* <p>
* ANGLE (Almost Native Graphics Layer Engine) can translate OpenGL ES commands to Vulkan
* commands. Enabling ANGLE may improve the performance and/or reduce the power consumption of
* applications.
* The caller must have {@link android.Manifest.permission#MANAGE_GAME_MODE}.
*
* @hide
*/
@TestApi
@RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
public @GameMode boolean getAngleEnabled(@NonNull String packageName) {
public @GameMode boolean isAngleEnabled(@NonNull String packageName) {
try {
return mService.getAngleEnabled(packageName, mContext.getUserId());
return mService.isAngleEnabled(packageName, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}

View File

@@ -26,7 +26,7 @@ interface IGameManagerService {
int getGameMode(String packageName, int userId);
void setGameMode(String packageName, int gameMode, int userId);
int[] getAvailableGameModes(String packageName);
boolean getAngleEnabled(String packageName, int userId);
boolean isAngleEnabled(String packageName, int userId);
void setGameState(String packageName, in GameState gameState, int userId);
GameModeInfo getGameModeInfo(String packageName, int userId);
void setGameServiceProvider(String packageName);

View File

@@ -165,7 +165,7 @@ public class GraphicsEnvironment {
private boolean isAngleEnabledByGameMode(Context context, String packageName) {
try {
final boolean gameModeEnabledAngle =
(mGameManager != null) && mGameManager.getAngleEnabled(packageName);
(mGameManager != null) && mGameManager.isAngleEnabled(packageName);
Log.v(TAG, "ANGLE GameManagerService for " + packageName + ": " + gameModeEnabledAngle);
return gameModeEnabledAngle;
} catch (SecurityException e) {

View File

@@ -8875,6 +8875,20 @@
<attr name="gameSessionService" format="string" />
</declare-styleable>
<!-- Use <code>game-mode-config</code> as the root tag of the XML resource that
describes a GameModeConfig.
Described here are the attributes that can be included in that tag. -->
<declare-styleable name="GameModeConfig">
<!-- Set true to opt in BATTERY mode. -->
<attr name="supportsBatteryGameMode" format="boolean" />
<!-- Set true to opt in PERFORMANCE mode. -->
<attr name="supportsPerformanceGameMode" format="boolean" />
<!-- Set true to enable ANGLE. -->
<attr name="allowGameAngleDriver" format="boolean" />
<!-- Set true to allow resolution downscaling intervention. -->
<attr name="allowGameDownscaling" format="boolean" />
</declare-styleable>
<!-- Use <code>voice-enrollment-application</code>
as the root tag of the XML resource that escribes the supported keyphrases (hotwords)
by the enrollment application.

View File

@@ -3255,6 +3255,10 @@
<public name="showClockAndComplications" />
<!-- @hide @SystemApi -->
<public name="gameSessionService" />
<public name="supportsBatteryGameMode" />
<public name="supportsPerformanceGameMode" />
<public name="allowGameAngleDriver" />
<public name="allowGameDownscaling" />
<public name="localeConfig" />
<public name="showBackground" />
<public name="inheritKeyStoreKeys" />

View File

@@ -20,6 +20,10 @@ import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_PACKAGE_CHANGED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static com.android.internal.R.styleable.GameModeConfig_allowGameAngleDriver;
import static com.android.internal.R.styleable.GameModeConfig_allowGameDownscaling;
import static com.android.internal.R.styleable.GameModeConfig_supportsBatteryGameMode;
import static com.android.internal.R.styleable.GameModeConfig_supportsPerformanceGameMode;
import static com.android.server.wm.CompatModePackages.DOWNSCALED;
import static com.android.server.wm.CompatModePackages.DOWNSCALE_30;
import static com.android.server.wm.CompatModePackages.DOWNSCALE_35;
@@ -54,6 +58,10 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.hardware.power.Mode;
import android.net.Uri;
import android.os.Binder;
@@ -71,8 +79,10 @@ import android.os.ShellCallback;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.KeyValueListParser;
import android.util.Slog;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -84,7 +94,11 @@ import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.SystemService.TargetUser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
@@ -425,6 +439,13 @@ public final class GameManagerService extends IGameManagerService.Stub {
public static final String METADATA_BATTERY_MODE_ENABLE =
"com.android.app.gamemode.battery.enabled";
/**
* Metadata that allows a game to specify all intervention information with an XML file in
* the application field.
*/
public static final String METADATA_GAME_MODE_CONFIG = "android.game_mode_config";
private static final String GAME_MODE_CONFIG_NODE_NAME = "game-mode-config";
private final String mPackageName;
private final ArrayMap<Integer, GameModeConfiguration> mModeConfigs;
private boolean mPerfModeOptedIn;
@@ -438,18 +459,20 @@ public final class GameManagerService extends IGameManagerService.Stub {
try {
final ApplicationInfo ai = mPackageManager.getApplicationInfoAsUser(packageName,
PackageManager.GET_META_DATA, userId);
if (ai.metaData != null) {
mPerfModeOptedIn = ai.metaData.getBoolean(METADATA_PERFORMANCE_MODE_ENABLE);
mBatteryModeOptedIn = ai.metaData.getBoolean(METADATA_BATTERY_MODE_ENABLE);
mAllowDownscale = ai.metaData.getBoolean(METADATA_WM_ALLOW_DOWNSCALE, true);
mAllowAngle = ai.metaData.getBoolean(METADATA_ANGLE_ALLOW_ANGLE, true);
} else {
mPerfModeOptedIn = false;
mBatteryModeOptedIn = false;
mAllowDownscale = true;
mAllowAngle = true;
if (!parseInterventionFromXml(ai, packageName)) {
if (ai.metaData != null) {
mPerfModeOptedIn = ai.metaData.getBoolean(METADATA_PERFORMANCE_MODE_ENABLE);
mBatteryModeOptedIn = ai.metaData.getBoolean(METADATA_BATTERY_MODE_ENABLE);
mAllowDownscale = ai.metaData.getBoolean(METADATA_WM_ALLOW_DOWNSCALE, true);
mAllowAngle = ai.metaData.getBoolean(METADATA_ANGLE_ALLOW_ANGLE, true);
} else {
mPerfModeOptedIn = false;
mBatteryModeOptedIn = false;
mAllowDownscale = true;
mAllowAngle = true;
}
}
} catch (PackageManager.NameNotFoundException e) {
} catch (NameNotFoundException e) {
// Not all packages are installed, hence ignore those that are not installed yet.
Slog.v(TAG, "Failed to get package metadata");
}
@@ -469,6 +492,51 @@ public final class GameManagerService extends IGameManagerService.Stub {
}
}
private boolean parseInterventionFromXml(ApplicationInfo ai, String packageName) {
boolean xmlFound = false;
try (XmlResourceParser parser = ai.loadXmlMetaData(mPackageManager,
METADATA_GAME_MODE_CONFIG)) {
if (parser == null) {
Slog.v(TAG, "No " + METADATA_GAME_MODE_CONFIG
+ " meta-data found for package " + mPackageName);
} else {
xmlFound = true;
final Resources resources = mPackageManager.getResourcesForApplication(
packageName);
final AttributeSet attributeSet = Xml.asAttributeSet(parser);
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& type != XmlPullParser.START_TAG) {
// Do nothing
}
boolean isStartingTagGameModeConfig =
GAME_MODE_CONFIG_NODE_NAME.equals(parser.getName());
if (!isStartingTagGameModeConfig) {
Slog.w(TAG, "Meta-data does not start with "
+ GAME_MODE_CONFIG_NODE_NAME
+ " tag");
} else {
final TypedArray array = resources.obtainAttributes(attributeSet,
com.android.internal.R.styleable.GameModeConfig);
mPerfModeOptedIn = array.getBoolean(
GameModeConfig_supportsPerformanceGameMode, false);
mBatteryModeOptedIn = array.getBoolean(
GameModeConfig_supportsBatteryGameMode,
false);
mAllowDownscale = array.getBoolean(GameModeConfig_allowGameDownscaling,
true);
mAllowAngle = array.getBoolean(GameModeConfig_allowGameAngleDriver, true);
array.recycle();
}
}
} catch (NameNotFoundException | XmlPullParserException | IOException ex) {
Slog.e(TAG, "Error while parsing XML meta-data for "
+ METADATA_GAME_MODE_CONFIG);
}
return xmlFound;
}
/**
* GameModeConfiguration contains all the values for all the interventions associated with
* a game mode.
@@ -691,7 +759,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
try {
return mPackageManager.getPackageUidAsUser(packageName, userId)
== Binder.getCallingUid();
} catch (PackageManager.NameNotFoundException e) {
} catch (NameNotFoundException e) {
return false;
}
}
@@ -855,7 +923,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
*/
@Override
@RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
public @GameMode boolean getAngleEnabled(String packageName, int userId)
public @GameMode boolean isAngleEnabled(String packageName, int userId)
throws SecurityException {
final int gameMode = getGameMode(packageName, userId);
if (gameMode == GameManager.GAME_MODE_UNSUPPORTED) {
@@ -1413,7 +1481,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
if (applicationInfo.category != ApplicationInfo.CATEGORY_GAME) {
return;
}
} catch (PackageManager.NameNotFoundException e) {
} catch (NameNotFoundException e) {
// Ignore the exception.
}
switch (intent.getAction()) {

View File

@@ -511,8 +511,8 @@ public class GameManagerServiceTests {
gameManagerService.getConfig(mPackageName);
assertEquals(config.getGameModeConfiguration(gameMode).getUseAngle(), angleEnabled);
// Validate GameManagerService.getAngleEnabled() returns the correct value.
assertEquals(gameManagerService.getAngleEnabled(mPackageName, USER_ID_1), angleEnabled);
// Validate GameManagerService.isAngleEnabled() returns the correct value.
assertEquals(gameManagerService.isAngleEnabled(mPackageName, USER_ID_1), angleEnabled);
}
private void checkFps(GameManagerService gameManagerService, int gameMode, int fps) {