diff options
7 files changed, 378 insertions, 264 deletions
diff --git a/core/java/android/app/GameManagerInternal.java b/core/java/android/app/GameManagerInternal.java new file mode 100644 index 000000000000..c8ff2a84a536 --- /dev/null +++ b/core/java/android/app/GameManagerInternal.java @@ -0,0 +1,30 @@ +/* + * 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; + +/** + * Game manager local system service interface. + * + * @hide Only for use within the system server. + */ + +public abstract class GameManagerInternal { + /** + * Used by the CompatModePackages to read game's compat scaling override. + */ + public abstract float getResolutionScalingFactor(String packageName, int userId); +} diff --git a/core/java/android/app/IGameManagerService.aidl b/core/java/android/app/IGameManagerService.aidl index e60a74acdc1c..481e7b0050ab 100644 --- a/core/java/android/app/IGameManagerService.aidl +++ b/core/java/android/app/IGameManagerService.aidl @@ -31,4 +31,6 @@ interface IGameManagerService { void setGameState(String packageName, in GameState gameState, int userId); GameModeInfo getGameModeInfo(String packageName, int userId); void setGameServiceProvider(String packageName); + void updateResolutionScalingFactor(String packageName, int gameMode, float scalingFactor, int userId); + float getResolutionScalingFactor(String packageName, int gameMode, int userId); } diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index d5e893984bf3..854b818c095f 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -25,20 +25,6 @@ import static com.android.internal.R.styleable.GameModeConfig_allowGameDownscali import static com.android.internal.R.styleable.GameModeConfig_allowGameFpsOverride; 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; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_40; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_45; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_50; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_55; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_60; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_65; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_70; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_75; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_80; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_85; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_90; import android.Manifest; import android.annotation.NonNull; @@ -48,10 +34,10 @@ import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.GameManager; import android.app.GameManager.GameMode; +import android.app.GameManagerInternal; import android.app.GameModeInfo; import android.app.GameState; import android.app.IGameManagerService; -import android.app.compat.PackageOverride; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -75,9 +61,7 @@ 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.ServiceManager; import android.os.ShellCallback; import android.os.UserManager; import android.provider.DeviceConfig; @@ -92,8 +76,6 @@ import android.util.Xml; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.compat.CompatibilityOverrideConfig; -import com.android.internal.compat.IPlatformCompat; import com.android.internal.os.BackgroundThread; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; @@ -140,10 +122,6 @@ public final class GameManagerService extends IGameManagerService.Stub { static final int WRITE_SETTINGS_DELAY = 10 * 1000; // 10 seconds static final int LOADING_BOOST_MAX_DURATION = 5 * 1000; // 5 seconds - static final PackageOverride COMPAT_ENABLED = new PackageOverride.Builder().setEnabled(true) - .build(); - static final PackageOverride COMPAT_DISABLED = new PackageOverride.Builder().setEnabled(false) - .build(); private static final String PACKAGE_NAME_MSG_KEY = "packageName"; private static final String USER_ID_MSG_KEY = "userId"; private static final String GAME_MODE_INTERVENTION_LIST_FILE_NAME = @@ -156,7 +134,6 @@ public final class GameManagerService extends IGameManagerService.Stub { private final Handler mHandler; private final PackageManager mPackageManager; private final UserManager mUserManager; - private final IPlatformCompat mPlatformCompat; private final PowerManagerInternal mPowerManagerInternal; private final File mSystemDir; @VisibleForTesting @@ -180,8 +157,6 @@ public final class GameManagerService extends IGameManagerService.Stub { mHandler = new SettingsHandler(looper); mPackageManager = mContext.getPackageManager(); mUserManager = mContext.getSystemService(UserManager.class); - mPlatformCompat = IPlatformCompat.Stub.asInterface( - ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class); mSystemDir = new File(Environment.getDataDirectory(), "system"); mSystemDir.mkdirs(); @@ -212,8 +187,6 @@ public final class GameManagerService extends IGameManagerService.Stub { mHandler = new SettingsHandler(looper); mPackageManager = mContext.getPackageManager(); mUserManager = mContext.getSystemService(UserManager.class); - mPlatformCompat = IPlatformCompat.Stub.asInterface( - ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class); mSystemDir = new File(dataDir, "system"); mSystemDir.mkdirs(); @@ -326,10 +299,6 @@ public final class GameManagerService extends IGameManagerService.Stub { break; } case POPULATE_GAME_MODE_SETTINGS: { - // Scan all game packages and re-enforce the configured compat mode overrides - // as the DeviceConfig may have be wiped/since last reboot and we can't risk - // having overrides configured for packages that no longer have any DeviceConfig - // and thus any way to escape compat mode. removeMessages(POPULATE_GAME_MODE_SETTINGS, msg.obj); final int userId = (int) msg.obj; final String[] packageNames = getInstalledGamePackageNames(userId); @@ -412,39 +381,6 @@ public final class GameManagerService extends IGameManagerService.Stub { } } - // Turn the raw string to the corresponding CompatChange id. - static long getCompatChangeId(String raw) { - switch (raw) { - case "0.3": - return DOWNSCALE_30; - case "0.35": - return DOWNSCALE_35; - case "0.4": - return DOWNSCALE_40; - case "0.45": - return DOWNSCALE_45; - case "0.5": - return DOWNSCALE_50; - case "0.55": - return DOWNSCALE_55; - case "0.6": - return DOWNSCALE_60; - case "0.65": - return DOWNSCALE_65; - case "0.7": - return DOWNSCALE_70; - case "0.75": - return DOWNSCALE_75; - case "0.8": - return DOWNSCALE_80; - case "0.85": - return DOWNSCALE_85; - case "0.9": - return DOWNSCALE_90; - } - return 0; - } - public enum FrameRate { FPS_DEFAULT(0), FPS_30(30), @@ -649,6 +585,13 @@ public final class GameManagerService extends IGameManagerService.Stub { return xmlFound; } + GameModeConfiguration getOrAddDefaultGameModeConfiguration(int gameMode) { + synchronized (mModeConfigLock) { + mModeConfigs.putIfAbsent(gameMode, new GameModeConfiguration(gameMode)); + return mModeConfigs.get(gameMode); + } + } + /** * GameModeConfiguration contains all the values for all the interventions associated with * a game mode. @@ -659,17 +602,26 @@ public final class GameManagerService extends IGameManagerService.Stub { public static final String MODE_KEY = "mode"; public static final String SCALING_KEY = "downscaleFactor"; public static final String FPS_KEY = "fps"; - public static final String DEFAULT_SCALING = "1.0"; - public static final String DEFAULT_FPS = ""; public static final String ANGLE_KEY = "useAngle"; public static final String LOADING_BOOST_KEY = "loadingBoost"; + public static final float DEFAULT_SCALING = -1f; + public static final String DEFAULT_FPS = ""; + public static final boolean DEFAULT_USE_ANGLE = false; + public static final int DEFAULT_LOADING_BOOST_DURATION = -1; + private final @GameMode int mGameMode; - private String mScaling; - private String mFps; + private float mScaling = DEFAULT_SCALING; + private String mFps = DEFAULT_FPS; private final boolean mUseAngle; private final int mLoadingBoostDuration; + GameModeConfiguration(int gameMode) { + mGameMode = gameMode; + mUseAngle = DEFAULT_USE_ANGLE; + mLoadingBoostDuration = DEFAULT_LOADING_BOOST_DURATION; + } + GameModeConfiguration(KeyValueListParser parser) { mGameMode = parser.getInt(MODE_KEY, GameManager.GAME_MODE_UNSUPPORTED); // isGameModeOptedIn() returns if an app will handle all of the changes necessary @@ -677,7 +629,7 @@ public final class GameManagerService extends IGameManagerService.Stub { // 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.getFloat(SCALING_KEY, DEFAULT_SCALING); mFps = mAllowFpsOverride && !willGamePerformOptimizations(mGameMode) ? parser.getString(FPS_KEY, DEFAULT_FPS) : DEFAULT_FPS; @@ -686,17 +638,18 @@ public final class GameManagerService extends IGameManagerService.Stub { // - 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); + && parser.getBoolean(ANGLE_KEY, DEFAULT_USE_ANGLE); - mLoadingBoostDuration = willGamePerformOptimizations(mGameMode) ? -1 - : parser.getInt(LOADING_BOOST_KEY, -1); + mLoadingBoostDuration = willGamePerformOptimizations(mGameMode) + ? DEFAULT_LOADING_BOOST_DURATION + : parser.getInt(LOADING_BOOST_KEY, DEFAULT_LOADING_BOOST_DURATION); } public int getGameMode() { return mGameMode; } - public synchronized String getScaling() { + public synchronized float getScaling() { return mScaling; } @@ -712,7 +665,7 @@ public final class GameManagerService extends IGameManagerService.Stub { return mLoadingBoostDuration; } - public synchronized void setScaling(String scaling) { + public synchronized void setScaling(float scaling) { mScaling = scaling; } @@ -735,13 +688,6 @@ public final class GameManagerService extends IGameManagerService.Stub { + mUseAngle + ",Fps:" + mFps + ",Loading Boost Duration:" + mLoadingBoostDuration + "]"; } - - /** - * Get the corresponding compat change id for the current scaling string. - */ - public long getCompatChangeId() { - return GameManagerService.getCompatChangeId(mScaling); - } } public String getPackageName() { @@ -813,7 +759,7 @@ public final class GameManagerService extends IGameManagerService.Stub { } /** - * Insert a new GameModeConfiguration + * Inserts a new GameModeConfiguration */ public void addModeConfig(GameModeConfiguration config) { if (config.isActive()) { @@ -839,6 +785,14 @@ 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); + return getResolutionScalingFactorInternal(packageName, gameMode, userId); + } + } + /** * SystemService lifecycle for GameService. * @@ -849,13 +803,13 @@ public final class GameManagerService extends IGameManagerService.Stub { public Lifecycle(Context context) { super(context); + mService = new GameManagerService(context); } @Override public void onStart() { - final Context context = getContext(); - mService = new GameManagerService(context); publishBinderService(Context.GAME_SERVICE, mService); + mService.publishLocalService(); mService.registerDeviceConfigListener(); mService.registerPackageReceiver(); } @@ -937,8 +891,8 @@ public final class GameManagerService extends IGameManagerService.Stub { private @GameMode int getGameModeFromSettings(String packageName, @UserIdInt int userId) { synchronized (mLock) { if (!mSettings.containsKey(userId)) { - Slog.w(TAG, "User ID '" + userId + "' does not have a Game Mode" - + " selected for package: '" + packageName + "'"); + Slog.d(TAG, "User ID '" + userId + "' does not have a Game Mode" + + " selected for package: '" + packageName + "'"); return GameManager.GAME_MODE_UNSUPPORTED; } @@ -1163,6 +1117,66 @@ public final class GameManagerService extends IGameManagerService.Stub { mGameServiceController.setGameServiceProvider(packageName); } + + /** + * Updates the resolution scaling factor for the package's target game mode and activates it. + * + * @param scalingFactor enable scaling override over any other compat scaling if positive, + * or disable the override otherwise + * @throws SecurityException if caller doesn't have + * {@link android.Manifest.permission#MANAGE_GAME_MODE} + * permission. + * @throws IllegalArgumentException if the user ID provided doesn't exist. + */ + @Override + @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) + public void updateResolutionScalingFactor(String packageName, int gameMode, float scalingFactor, + int userId) throws SecurityException, IllegalArgumentException { + checkPermission(Manifest.permission.MANAGE_GAME_MODE); + synchronized (mLock) { + if (!mSettings.containsKey(userId)) { + throw new IllegalArgumentException("User " + userId + " wasn't started"); + } + } + setGameModeConfigOverride(packageName, userId, gameMode, null /*fpsStr*/, + Float.toString(scalingFactor)); + } + + /** + * Gets the resolution scaling factor for the package's target game mode. + * + * @return scaling factor for the game mode if exists or negative value otherwise. + * @throws SecurityException if caller doesn't have + * {@link android.Manifest.permission#MANAGE_GAME_MODE} + * permission. + * @throws IllegalArgumentException if the user ID provided doesn't exist. + */ + @Override + @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) + public float getResolutionScalingFactor(String packageName, int gameMode, int userId) + throws SecurityException, IllegalArgumentException { + checkPermission(Manifest.permission.MANAGE_GAME_MODE); + synchronized (mLock) { + if (!mSettings.containsKey(userId)) { + throw new IllegalArgumentException("User " + userId + " wasn't started"); + } + } + return getResolutionScalingFactorInternal(packageName, gameMode, userId); + } + + float getResolutionScalingFactorInternal(String packageName, int gameMode, int userId) { + final GamePackageConfiguration packageConfig = getConfig(packageName); + if (packageConfig == null) { + return GamePackageConfiguration.GameModeConfiguration.DEFAULT_SCALING; + } + final GamePackageConfiguration.GameModeConfiguration modeConfig = + packageConfig.getGameModeConfiguration(gameMode); + if (modeConfig != null) { + return modeConfig.getScaling(); + } + return GamePackageConfiguration.GameModeConfiguration.DEFAULT_SCALING; + } + /** * Notified when boot is completed. */ @@ -1239,28 +1253,6 @@ public final class GameManagerService extends IGameManagerService.Stub { } /** - * @hide - */ - @VisibleForTesting - public void disableCompatScale(String packageName) { - final long uid = Binder.clearCallingIdentity(); - try { - Slog.i(TAG, "Disabling downscale for " + packageName); - final ArrayMap<Long, PackageOverride> overrides = new ArrayMap<>(); - overrides.put(DOWNSCALED, COMPAT_DISABLED); - final CompatibilityOverrideConfig changeConfig = new CompatibilityOverrideConfig( - overrides); - try { - mPlatformCompat.putOverridesOnReleaseBuilds(changeConfig, packageName); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to call IPlatformCompat#putOverridesOnReleaseBuilds", e); - } - } finally { - Binder.restoreCallingIdentity(uid); - } - } - - /** * Remove frame rate override due to mode switch */ private void resetFps(String packageName, @UserIdInt int userId) { @@ -1273,60 +1265,6 @@ public final class GameManagerService extends IGameManagerService.Stub { } } - private void enableCompatScale(String packageName, long scaleId) { - final long uid = Binder.clearCallingIdentity(); - try { - Slog.i(TAG, "Enabling downscale: " + scaleId + " for " + packageName); - final ArrayMap<Long, PackageOverride> overrides = new ArrayMap<>(); - overrides.put(DOWNSCALED, COMPAT_ENABLED); - overrides.put(DOWNSCALE_30, COMPAT_DISABLED); - overrides.put(DOWNSCALE_35, COMPAT_DISABLED); - overrides.put(DOWNSCALE_40, COMPAT_DISABLED); - overrides.put(DOWNSCALE_45, COMPAT_DISABLED); - overrides.put(DOWNSCALE_50, COMPAT_DISABLED); - overrides.put(DOWNSCALE_55, COMPAT_DISABLED); - overrides.put(DOWNSCALE_60, COMPAT_DISABLED); - overrides.put(DOWNSCALE_65, COMPAT_DISABLED); - overrides.put(DOWNSCALE_70, COMPAT_DISABLED); - overrides.put(DOWNSCALE_75, COMPAT_DISABLED); - overrides.put(DOWNSCALE_80, COMPAT_DISABLED); - overrides.put(DOWNSCALE_85, COMPAT_DISABLED); - overrides.put(DOWNSCALE_90, COMPAT_DISABLED); - overrides.put(scaleId, COMPAT_ENABLED); - final CompatibilityOverrideConfig changeConfig = new CompatibilityOverrideConfig( - overrides); - try { - mPlatformCompat.putOverridesOnReleaseBuilds(changeConfig, packageName); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to call IPlatformCompat#putOverridesOnReleaseBuilds", e); - } - } finally { - Binder.restoreCallingIdentity(uid); - } - } - - private void updateCompatModeDownscale(GamePackageConfiguration packageConfig, - String packageName, @GameMode int gameMode) { - - if (DEBUG) { - Slog.v(TAG, dumpDeviceConfigs()); - } - final GamePackageConfiguration.GameModeConfiguration modeConfig = - packageConfig.getGameModeConfiguration(gameMode); - if (modeConfig == null) { - Slog.i(TAG, "Game mode " + gameMode + " not found for " + packageName); - return; - } - long scaleId = modeConfig.getCompatChangeId(); - if (scaleId == 0) { - Slog.w(TAG, "Invalid downscaling change id " + scaleId + " for " - + packageName); - return; - } - - enableCompatScale(packageName, scaleId); - } - private int modeToBitmask(@GameMode int gameMode) { return (1 << gameMode); } @@ -1364,20 +1302,17 @@ public final class GameManagerService extends IGameManagerService.Stub { @GameMode int gameMode, @UserIdInt int userId) { if (gameMode == GameManager.GAME_MODE_STANDARD || gameMode == GameManager.GAME_MODE_UNSUPPORTED) { - disableCompatScale(packageName); resetFps(packageName, userId); return; } final GamePackageConfiguration packageConfig = getConfig(packageName); if (packageConfig == null) { - disableCompatScale(packageName); Slog.v(TAG, "Package configuration not found for " + packageName); return; } if (packageConfig.willGamePerformOptimizations(gameMode)) { return; } - updateCompatModeDownscale(packageConfig, packageName, gameMode); updateFps(packageConfig, packageName, gameMode, userId); updateUseAngle(packageName, gameMode); } @@ -1408,7 +1343,7 @@ public final class GameManagerService extends IGameManagerService.Stub { } // modify GameModeConfiguration intervention settings GamePackageConfiguration.GameModeConfiguration overrideModeConfig = - overrideConfig.getGameModeConfiguration(gameMode); + overrideConfig.getOrAddDefaultGameModeConfiguration(gameMode); if (fpsStr != null) { overrideModeConfig.setFpsStr(fpsStr); @@ -1417,10 +1352,7 @@ public final class GameManagerService extends IGameManagerService.Stub { GamePackageConfiguration.GameModeConfiguration.DEFAULT_FPS); } if (scaling != null) { - overrideModeConfig.setScaling(scaling); - } else { - overrideModeConfig.setScaling( - GamePackageConfiguration.GameModeConfiguration.DEFAULT_SCALING); + overrideModeConfig.setScaling(Float.parseFloat(scaling)); } Slog.i(TAG, "Package Name: " + packageName + " FPS: " + String.valueOf(overrideModeConfig.getFps()) @@ -1470,7 +1402,7 @@ public final class GameManagerService extends IGameManagerService.Stub { } // If the game mode to reset is the only mode other than standard mode, - // The override config is removed. + // the override config is removed. if (modes.length <= 2) { synchronized (mOverrideConfigLock) { mOverrideConfigs.remove(packageName); @@ -1595,7 +1527,7 @@ public final class GameManagerService extends IGameManagerService.Stub { } } } catch (Exception e) { - Slog.e(TAG, "Failed to update compat modes for user " + userId + ": " + e); + Slog.e(TAG, "Failed to update configs for user " + userId + ": " + e); } final Message msg = mHandler.obtainMessage(WRITE_GAME_MODE_INTERVENTION_LIST_FILE); @@ -1646,7 +1578,7 @@ public final class GameManagerService extends IGameManagerService.Stub { final int useAngle = gameModeConfiguration.getUseAngle() ? 1 : 0; sb.append(TextUtils.formatSimple("angle=%d", useAngle)); sb.append(","); - final String scaling = gameModeConfiguration.getScaling(); + final float scaling = gameModeConfiguration.getScaling(); sb.append("scaling="); sb.append(scaling); sb.append(","); @@ -1746,14 +1678,6 @@ public final class GameManagerService extends IGameManagerService.Stub { updateConfigsForUser(userId, true /*checkGamePackage*/, packageName); break; case ACTION_PACKAGE_REMOVED: - disableCompatScale(packageName); - // If EXTRA_REPLACING is true, it means there will be an - // ACTION_PACKAGE_ADDED triggered after this because this - // is an updated package that gets installed. Hence, disable - // resolution downscaling effort but avoid removing the server - // or commandline overriding configurations because those will - // not change but the package game mode configurations may change - // which may opt in and/or opt out some game mode configurations. if (!intent.getBooleanExtra(EXTRA_REPLACING, false)) { synchronized (mOverrideConfigLock) { mOverrideConfigs.remove(packageName); @@ -1785,6 +1709,10 @@ public final class GameManagerService extends IGameManagerService.Stub { mDeviceConfigListener = new DeviceConfigListener(); } + private void publishLocalService() { + LocalServices.addService(GameManagerInternal.class, new LocalService()); + } + private String dumpDeviceConfigs() { StringBuilder out = new StringBuilder(); for (String key : mConfigs.keySet()) { diff --git a/services/core/java/com/android/server/app/GameManagerShellCommand.java b/services/core/java/com/android/server/app/GameManagerShellCommand.java index 470c320dbd7d..487d19aa6aba 100644 --- a/services/core/java/com/android/server/app/GameManagerShellCommand.java +++ b/services/core/java/com/android/server/app/GameManagerShellCommand.java @@ -16,21 +16,6 @@ package com.android.server.app; -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; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_40; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_45; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_50; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_55; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_60; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_65; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_70; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_75; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_80; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_85; -import static com.android.server.wm.CompatModePackages.DOWNSCALE_90; - import android.app.ActivityManager; import android.app.GameManager; import android.app.IGameManagerService; @@ -39,7 +24,6 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; import android.os.ShellCommand; -import android.util.ArraySet; import java.io.PrintWriter; import java.util.Locale; @@ -53,23 +37,6 @@ public class GameManagerShellCommand extends ShellCommand { public GameManagerShellCommand() {} - private static final ArraySet<Long> DOWNSCALE_CHANGE_IDS = new ArraySet<>(new Long[]{ - DOWNSCALED, - DOWNSCALE_90, - DOWNSCALE_85, - DOWNSCALE_80, - DOWNSCALE_75, - DOWNSCALE_70, - DOWNSCALE_65, - DOWNSCALE_60, - DOWNSCALE_55, - DOWNSCALE_50, - DOWNSCALE_45, - DOWNSCALE_40, - DOWNSCALE_35, - DOWNSCALE_30, - }); - @Override public int onCommand(String cmd) { if (cmd == null) { @@ -212,11 +179,15 @@ public class GameManagerShellCommand extends ShellCommand { case "--downscale": if (downscaleRatio == null) { downscaleRatio = getNextArgRequired(); - if (downscaleRatio != null - && GameManagerService.getCompatChangeId(downscaleRatio) == 0 - && !downscaleRatio.equals("disable")) { - pw.println("Invalid scaling ratio '" + downscaleRatio + "'"); - return -1; + if ("disable".equals(downscaleRatio)) { + downscaleRatio = "-1"; + } else { + try { + Float.parseFloat(downscaleRatio); + } catch (NumberFormatException e) { + pw.println("Invalid scaling ratio '" + downscaleRatio + "'"); + return -1; + } } } else { pw.println("Duplicate option '" + option + "'"); @@ -249,40 +220,16 @@ public class GameManagerShellCommand extends ShellCommand { final GameManagerService gameManagerService = (GameManagerService) ServiceManager.getService(Context.GAME_SERVICE); - boolean batteryModeSupported = false; - boolean perfModeSupported = false; - int [] modes = gameManagerService.getAvailableGameModes(packageName); - - for (int mode : modes) { - if (mode == GameManager.GAME_MODE_PERFORMANCE) { - perfModeSupported = true; - } else if (mode == GameManager.GAME_MODE_BATTERY) { - batteryModeSupported = true; - } - } - switch (gameMode.toLowerCase(Locale.getDefault())) { case "2": case "performance": - if (perfModeSupported) { - gameManagerService.setGameModeConfigOverride(packageName, userId, - GameManager.GAME_MODE_PERFORMANCE, fpsStr, downscaleRatio); - } else { - pw.println("Game mode: " + gameMode + " not supported by " - + packageName); - return -1; - } + gameManagerService.setGameModeConfigOverride(packageName, userId, + GameManager.GAME_MODE_PERFORMANCE, fpsStr, downscaleRatio); break; case "3": case "battery": - if (batteryModeSupported) { - gameManagerService.setGameModeConfigOverride(packageName, userId, - GameManager.GAME_MODE_BATTERY, fpsStr, downscaleRatio); - } else { - pw.println("Game mode: " + gameMode + " not supported by " - + packageName); - return -1; - } + gameManagerService.setGameModeConfigOverride(packageName, userId, + GameManager.GAME_MODE_BATTERY, fpsStr, downscaleRatio); break; default: pw.println("Invalid game mode: " + gameMode); diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java index 2ea043a5c623..6f1945033af9 100644 --- a/services/core/java/com/android/server/wm/CompatModePackages.java +++ b/services/core/java/com/android/server/wm/CompatModePackages.java @@ -24,6 +24,7 @@ import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; import android.app.ActivityManager; import android.app.AppGlobals; +import android.app.GameManagerInternal; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.Disabled; @@ -48,6 +49,7 @@ import android.util.TypedXmlSerializer; import android.util.Xml; import com.android.internal.protolog.common.ProtoLog; +import com.android.server.LocalServices; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -64,6 +66,7 @@ public final class CompatModePackages { private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION; private final ActivityTaskManagerService mService; + private GameManagerInternal mGameManager; private final AtomicFile mFile; // Compatibility state: no longer ask user to select the mode. @@ -375,6 +378,18 @@ public final class CompatModePackages { float getCompatScale(String packageName, int uid) { final UserHandle userHandle = UserHandle.getUserHandleForUid(uid); + if (mGameManager == null) { + mGameManager = LocalServices.getService(GameManagerInternal.class); + } + if (mGameManager != null) { + final int userId = userHandle.getIdentifier(); + final float scalingFactor = mGameManager.getResolutionScalingFactor(packageName, + userId); + if (scalingFactor > 0) { + return 1f / scalingFactor; + } + } + if (CompatChanges.isChangeEnabled(DOWNSCALED, packageName, userHandle)) { if (CompatChanges.isChangeEnabled(DOWNSCALE_90, packageName, userHandle)) { return 1f / 0.9f; 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 d325e47f7687..b53a2c69708d 100644 --- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java @@ -201,7 +201,6 @@ public class GameManagerServiceTests { public void tearDown() throws Exception { LocalServices.removeServiceForTest(PowerManagerInternal.class); GameManagerService gameManagerService = new GameManagerService(mMockContext); - gameManagerService.disableCompatScale(mPackageName); if (mMockingSession != null) { mMockingSession.finishMocking(); } @@ -578,7 +577,7 @@ public class GameManagerServiceTests { } private void checkDownscaling(GameManagerService gameManagerService, - int gameMode, String scaling) { + int gameMode, float scaling) { if (gameManagerService == null) { gameManagerService = new GameManagerService(mMockContext, mTestLooper.getLooper()); startUser(gameManagerService, USER_ID_1); @@ -586,7 +585,7 @@ public class GameManagerServiceTests { } GameManagerService.GamePackageConfiguration config = gameManagerService.getConfig(mPackageName); - assertEquals(config.getGameModeConfiguration(gameMode).getScaling(), scaling); + assertEquals(scaling, config.getGameModeConfiguration(gameMode).getScaling(), 0.01f); } private void checkAngleEnabled(GameManagerService gameManagerService, int gameMode, @@ -715,7 +714,7 @@ public class GameManagerServiceTests { checkReportedModes(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_STANDARD); - checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, "0.3"); + checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0.3f); checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 120); } @@ -735,7 +734,7 @@ public class GameManagerServiceTests { checkReportedModes(gameManagerService, GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD); - checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.5"); + checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, 0.5f); checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 60); } @@ -757,9 +756,9 @@ public class GameManagerServiceTests { checkReportedModes(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD); - checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, "0.3"); + checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0.3f); checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 120); - checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.5"); + checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, 0.5f); checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 60); } @@ -782,7 +781,7 @@ public class GameManagerServiceTests { checkReportedModes(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_STANDARD); - checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, "0.5"); + checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0.5f); checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90); } @@ -805,7 +804,7 @@ public class GameManagerServiceTests { checkReportedModes(gameManagerService, GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD); - checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.7"); + checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, 0.7f); checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 30); } @@ -829,9 +828,9 @@ public class GameManagerServiceTests { checkReportedModes(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD); - checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, "0.5"); + checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0.5f); checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90); - checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.7"); + checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, 0.7f); checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 30); } @@ -858,9 +857,9 @@ public class GameManagerServiceTests { checkReportedModes(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD); - checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, "0.3"); + checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0.3f); checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 120); - checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.7"); + checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, 0.7f); checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 30); } @@ -933,7 +932,7 @@ public class GameManagerServiceTests { public void testInterventionAllowScalingDefault() throws Exception { mockDeviceConfigPerformance(); mockModifyGameModeGranted(); - checkDownscaling(null, GameManager.GAME_MODE_PERFORMANCE, "0.5"); + checkDownscaling(null, GameManager.GAME_MODE_PERFORMANCE, 0.5f); } /** @@ -944,7 +943,7 @@ public class GameManagerServiceTests { mockDeviceConfigPerformance(); mockInterventionAllowDownscaleFalse(); mockModifyGameModeGranted(); - checkDownscaling(null, GameManager.GAME_MODE_PERFORMANCE, "1.0"); + checkDownscaling(null, GameManager.GAME_MODE_PERFORMANCE, -1.0f); } /** @@ -956,7 +955,7 @@ public class GameManagerServiceTests { mockDeviceConfigPerformance(); mockInterventionAllowDownscaleTrue(); mockModifyGameModeGranted(); - checkDownscaling(null, GameManager.GAME_MODE_PERFORMANCE, "0.5"); + checkDownscaling(null, GameManager.GAME_MODE_PERFORMANCE, 0.5f); } /** @@ -1404,4 +1403,102 @@ public class GameManagerServiceTests { assertEquals(splitLine[6], "angle=0,scaling=0.7,fps=30"); } + + @Test + public void testUpdateResolutionScalingFactor() { + mockModifyGameModeGranted(); + mockDeviceConfigBattery(); + GameManagerService gameManagerService = + new GameManagerService(mMockContext, mTestLooper.getLooper()); + startUser(gameManagerService, USER_ID_1); + float scalingFactor = 0.123f; + gameManagerService.updateResolutionScalingFactor(mPackageName, + GameManager.GAME_MODE_BATTERY, scalingFactor, + USER_ID_1); + assertEquals(scalingFactor, gameManagerService.getResolutionScalingFactor(mPackageName, + GameManager.GAME_MODE_BATTERY, USER_ID_1), 0.001f); + scalingFactor = 0.321f; + gameManagerService.updateResolutionScalingFactor(mPackageName, + GameManager.GAME_MODE_BATTERY, scalingFactor, + USER_ID_1); + assertEquals(scalingFactor, gameManagerService.getResolutionScalingFactor(mPackageName, + GameManager.GAME_MODE_BATTERY, USER_ID_1), 0.001f); + } + + @Test + public void testUpdateResolutionScalingFactor_noDeviceConfig() { + mockModifyGameModeGranted(); + GameManagerService gameManagerService = + new GameManagerService(mMockContext, mTestLooper.getLooper()); + startUser(gameManagerService, USER_ID_1); + float scalingFactor = 0.123f; + gameManagerService.updateResolutionScalingFactor(mPackageName, + GameManager.GAME_MODE_BATTERY, scalingFactor, + USER_ID_1); + assertEquals(scalingFactor, gameManagerService.getResolutionScalingFactor(mPackageName, + GameManager.GAME_MODE_BATTERY, USER_ID_1), 0.001f); + scalingFactor = 0.321f; + gameManagerService.updateResolutionScalingFactor(mPackageName, + GameManager.GAME_MODE_BATTERY, scalingFactor, + USER_ID_1); + assertEquals(scalingFactor, gameManagerService.getResolutionScalingFactor(mPackageName, + GameManager.GAME_MODE_BATTERY, + USER_ID_1), 0.001f); + } + + @Test + public void testUpdateResolutionScalingFactor_permissionDenied() { + mockModifyGameModeDenied(); + mockDeviceConfigAll(); + GameManagerService gameManagerService = + new GameManagerService(mMockContext, mTestLooper.getLooper()); + startUser(gameManagerService, USER_ID_1); + float scalingFactor = 0.123f; + assertThrows(SecurityException.class, () -> { + gameManagerService.updateResolutionScalingFactor(mPackageName, + GameManager.GAME_MODE_BATTERY, scalingFactor, + USER_ID_1); + }); + mockModifyGameModeGranted(); + assertEquals(0.7f, gameManagerService.getResolutionScalingFactor(mPackageName, + GameManager.GAME_MODE_BATTERY, USER_ID_1), 0.001f); + } + + @Test + public void testUpdateResolutionScalingFactor_noUserId() { + mockModifyGameModeGranted(); + GameManagerService gameManagerService = + new GameManagerService(mMockContext, mTestLooper.getLooper()); + startUser(gameManagerService, USER_ID_2); + final float scalingFactor = 0.123f; + assertThrows(IllegalArgumentException.class, () -> { + gameManagerService.updateResolutionScalingFactor(mPackageName, + GameManager.GAME_MODE_BATTERY, scalingFactor, + USER_ID_1); + }); + } + + @Test + public void testGetResolutionScalingFactor_permissionDenied() { + mockModifyGameModeDenied(); + mockDeviceConfigAll(); + GameManagerService gameManagerService = + new GameManagerService(mMockContext, mTestLooper.getLooper()); + startUser(gameManagerService, USER_ID_1); + assertThrows(SecurityException.class, () -> { + gameManagerService.getResolutionScalingFactor(mPackageName, + GameManager.GAME_MODE_BATTERY, USER_ID_1); + }); + } + + @Test + public void testGetResolutionScalingFactor_noUserId() { + mockModifyGameModeDenied(); + mockDeviceConfigAll(); + GameManagerService gameManagerService = + new GameManagerService(mMockContext, mTestLooper.getLooper()); + startUser(gameManagerService, USER_ID_2); + assertEquals(-1f, gameManagerService.getResolutionScalingFactor(mPackageName, + GameManager.GAME_MODE_BATTERY, USER_ID_1), 0.001f); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/CompatModePackagesTests.java b/services/tests/wmtests/src/com/android/server/wm/CompatModePackagesTests.java new file mode 100644 index 000000000000..1f7b65e8b701 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/CompatModePackagesTests.java @@ -0,0 +1,95 @@ +/* + * 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 com.android.server.wm; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; + +import android.app.GameManagerInternal; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; + +import com.android.server.LocalServices; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests for the {@link CompatModePackages} class. + * + * Build/Install/Run: + * atest WmTests:CompatModePackagesTests + */ +@SmallTest +@Presubmit +public class CompatModePackagesTests extends SystemServiceTestsBase { + ActivityTaskManagerService mAtm; + GameManagerInternal mGm; + static final String TEST_PACKAGE = "compat.mode.packages"; + static final int TEST_USER_ID = 1; + + @Before + public void setUp() { + mAtm = mSystemServicesTestRule.getActivityTaskManagerService(); + mGm = mock(GameManagerInternal.class); + } + + @After + public void tearDown() { + LocalServices.removeServiceForTest(GameManagerInternal.class); + } + + @Test + public void testGetCompatScale_gameManagerReturnsPositive() { + LocalServices.addService(GameManagerInternal.class, mGm); + float scale = 0.25f; + doReturn(scale).when(mGm).getResolutionScalingFactor(anyString(), anyInt()); + assertEquals(mAtm.mCompatModePackages.getCompatScale(TEST_PACKAGE, TEST_USER_ID), 1 / scale, + 0.01f); + } + + @Test + public void testGetCompatScale_gameManagerReturnsZero() { + LocalServices.addService(GameManagerInternal.class, mGm); + float scale = 0f; + doReturn(scale).when(mGm).getResolutionScalingFactor(anyString(), anyInt()); + assertEquals(mAtm.mCompatModePackages.getCompatScale(TEST_PACKAGE, TEST_USER_ID), 1f, + 0.01f); + } + + @Test + public void testGetCompatScale_gameManagerReturnsNegative() { + LocalServices.addService(GameManagerInternal.class, mGm); + float scale = -1f; + doReturn(scale).when(mGm).getResolutionScalingFactor(anyString(), anyInt()); + assertEquals(mAtm.mCompatModePackages.getCompatScale(TEST_PACKAGE, TEST_USER_ID), 1f, + 0.01f); + } + + @Test + public void testGetCompatScale_noGameManager() { + assertEquals(mAtm.mCompatModePackages.getCompatScale(TEST_PACKAGE, TEST_USER_ID), 1f, + 0.01f); + } + +} |