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) {