From 7998c248ccb3f66676f53e48c59ef6e3b4a84a76 Mon Sep 17 00:00:00 2001 From: Xiang Wang Date: Fri, 14 Jan 2022 02:04:48 +0000 Subject: [PATCH 1/2] 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 --- core/api/current.txt | 4 + core/api/test-current.txt | 1 + core/java/android/app/GameManager.java | 8 +- .../java/android/app/IGameManagerService.aidl | 2 +- core/java/android/os/GraphicsEnvironment.java | 2 +- core/res/res/values/attrs.xml | 14 +++ core/res/res/values/public.xml | 4 + .../server/app/GameManagerService.java | 96 ++++++++++++++++--- .../server/app/GameManagerServiceTests.java | 4 +- 9 files changed, 115 insertions(+), 20 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index c1d692f4b3a66..df3e48db52b0e 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -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; diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 52a180b3c9e07..1d3254449ac68 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -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); } diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java index 289b3486b7fe3..040399ecb83be 100644 --- a/core/java/android/app/GameManager.java +++ b/core/java/android/app/GameManager.java @@ -181,14 +181,18 @@ public final class GameManager { /** * Returns if ANGLE is enabled for a given package and user ID. *

+ * 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(); } diff --git a/core/java/android/app/IGameManagerService.aidl b/core/java/android/app/IGameManagerService.aidl index 3ea0767661bbd..7035ac078334c 100644 --- a/core/java/android/app/IGameManagerService.aidl +++ b/core/java/android/app/IGameManagerService.aidl @@ -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); diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index aa4b83a5c3616..0c3514fce76e3 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -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) { diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 04e29890568a9..2c3071ec1758d 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -8875,6 +8875,20 @@ + + + + + + + + + + + + + + + + diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index 3c9d29d77bbe6..0fc4a6627af56 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -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 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()) { 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 44b81d4d4100c..a0a4d4ee1ea0d 100644 --- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java @@ -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) { From 8f43fdf19ba79330d2d3e3a4de13ef4d2c981def Mon Sep 17 00:00:00 2001 From: Xiang Wang Date: Thu, 20 Jan 2022 22:12:30 +0000 Subject: [PATCH 2/2] Add allowGameFpsOverride intervention flag Similar to Angle intervention, to turn off FPS overriding, the app needs to have this flag disabled. Bug: 214448560 Test: atest GameManagerServicesTest Change-Id: I228beb39e9ba2649ee09fe165c0ff0c3bc7f1887 --- core/api/current.txt | 1 + core/res/res/values/attrs.xml | 2 + core/res/res/values/public.xml | 1 + .../server/app/GameManagerService.java | 8 +- ...nager_service_metadata_config_disabled.xml | 9 ++ ...anager_service_metadata_config_enabled.xml | 9 ++ .../server/app/GameManagerServiceTests.java | 83 ++++++++++++++++++- 7 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_disabled.xml create mode 100644 services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_enabled.xml diff --git a/core/api/current.txt b/core/api/current.txt index df3e48db52b0e..280fe4a34bed3 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -328,6 +328,7 @@ package android { 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 allowGameFpsOverride; field public static final int allowNativeHeapPointerTagging = 16844306; // 0x1010612 field public static final int allowParallelSyncs = 16843570; // 0x1010332 field public static final int allowSingleTap = 16843353; // 0x1010259 diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 2c3071ec1758d..afe0f1bf00019 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -8887,6 +8887,8 @@ + +