Loading services/core/java/com/android/server/app/GameManagerService.java +371 −81 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.GameManager; import android.app.GameManager.GameMode; Loading Loading @@ -81,6 +82,7 @@ import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.SystemService.TargetUser; import com.android.server.app.GameManagerService.GamePackageConfiguration.GameModeConfiguration; import java.io.FileDescriptor; import java.util.List; Loading Loading @@ -113,6 +115,7 @@ public final class GameManagerService extends IGameManagerService.Stub { private final Context mContext; private final Object mLock = new Object(); private final Object mDeviceConfigLock = new Object(); private final Object mOverrideConfigLock = new Object(); private final Handler mHandler; private final PackageManager mPackageManager; private final IPlatformCompat mPlatformCompat; Loading @@ -122,6 +125,8 @@ public final class GameManagerService extends IGameManagerService.Stub { private final ArrayMap<Integer, GameManagerSettings> mSettings = new ArrayMap<>(); @GuardedBy("mDeviceConfigLock") private final ArrayMap<String, GamePackageConfiguration> mConfigs = new ArrayMap<>(); @GuardedBy("mOverrideConfigLock") private final ArrayMap<String, GamePackageConfiguration> mOverrideConfigs = new ArrayMap<>(); public GameManagerService(Context context) { this(context, createServiceThread().getLooper()); Loading Loading @@ -281,13 +286,51 @@ public final class GameManagerService extends IGameManagerService.Stub { return 0; } public enum FrameRate { FPS_DEFAULT(0), FPS_30(30), FPS_45(45), FPS_60(60), FPS_90(90), FPS_120(120), FPS_INVALID(-1); public final int fps; FrameRate(int fps) { this.fps = fps; } } // Turn the raw string to the corresponding fps int. // Return 0 when disabling, -1 for invalid fps. static int getFpsInt(String raw) { switch (raw) { case "30": return FrameRate.FPS_30.fps; case "45": return FrameRate.FPS_45.fps; case "60": return FrameRate.FPS_60.fps; case "90": return FrameRate.FPS_90.fps; case "120": return FrameRate.FPS_120.fps; case "disable": case "": return FrameRate.FPS_DEFAULT.fps; } return FrameRate.FPS_INVALID.fps; } /** * Called by games to communicate the current state to the platform. * @param packageName The client package name. * @param gameState An object set to the current state. * @param userId The user associated with this state. */ public void setGameState(String packageName, @NonNull GameState gameState, int userId) { public void setGameState(String packageName, @NonNull GameState gameState, @UserIdInt int userId) { if (!isPackageGame(packageName, userId)) { // Restrict to games only. return; Loading Loading @@ -399,11 +442,14 @@ public final class GameManagerService extends IGameManagerService.Stub { public static final String TAG = "GameManagerService_GameModeConfiguration"; 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"; private final @GameMode int mGameMode; private final String mScaling; private String mScaling; private String mFps; private final boolean mUseAngle; GameModeConfiguration(KeyValueListParser parser) { Loading @@ -414,6 +460,8 @@ public final class GameManagerService extends IGameManagerService.Stub { // using ANGLE). mScaling = !mAllowDownscale || willGamePerformOptimizations(mGameMode) ? DEFAULT_SCALING : parser.getString(SCALING_KEY, DEFAULT_SCALING); mFps = parser.getString(FPS_KEY, DEFAULT_FPS); // 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 Loading @@ -430,14 +478,27 @@ public final class GameManagerService extends IGameManagerService.Stub { return mScaling; } public int getFps() { return GameManagerService.getFpsInt(mFps); } public boolean getUseAngle() { return mUseAngle; } public void setScaling(String scaling) { mScaling = scaling; } public void setFpsStr(String fpsStr) { mFps = fpsStr; } public boolean isValid() { return mGameMode == GameManager.GAME_MODE_STANDARD return (mGameMode == GameManager.GAME_MODE_STANDARD || mGameMode == GameManager.GAME_MODE_PERFORMANCE || mGameMode == GameManager.GAME_MODE_BATTERY; || mGameMode == GameManager.GAME_MODE_BATTERY) && !willGamePerformOptimizations(mGameMode); } /** Loading @@ -445,7 +506,7 @@ public final class GameManagerService extends IGameManagerService.Stub { */ public String toString() { return "[Game Mode:" + mGameMode + ",Scaling:" + mScaling + ",Use Angle:" + mUseAngle + "]"; + mUseAngle + ",Fps:" + mFps + "]"; } /** Loading Loading @@ -641,16 +702,22 @@ public final class GameManagerService extends IGameManagerService.Stub { @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public @GameMode int[] getAvailableGameModes(String packageName) throws SecurityException { checkPermission(Manifest.permission.MANAGE_GAME_MODE); GamePackageConfiguration config = null; synchronized (mOverrideConfigLock) { config = mOverrideConfigs.get(packageName); } if (config == null) { synchronized (mDeviceConfigLock) { final GamePackageConfiguration config = mConfigs.get(packageName); config = mConfigs.get(packageName); } } if (config == null) { return new int[]{GameManager.GAME_MODE_UNSUPPORTED}; } return config.getAvailableGameModes(); } } private @GameMode int getGameModeFromSettings(String packageName, int userId) { 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" Loading Loading @@ -743,7 +810,7 @@ public final class GameManagerService extends IGameManagerService.Stub { mHandler.sendMessageDelayed(msg, WRITE_SETTINGS_DELAY); } } updateInterventions(packageName, gameMode); updateInterventions(packageName, gameMode, userId); } /** Loading Loading @@ -876,26 +943,12 @@ public final class GameManagerService extends IGameManagerService.Stub { } } private void updateCompatModeDownscale(String packageName, @GameMode int gameMode) { synchronized (mDeviceConfigLock) { if (gameMode == GameManager.GAME_MODE_STANDARD || gameMode == GameManager.GAME_MODE_UNSUPPORTED) { disableCompatScale(packageName); return; } final GamePackageConfiguration packageConfig = mConfigs.get(packageName); if (packageConfig == null) { disableCompatScale(packageName); Slog.v(TAG, "Package configuration not found for " + packageName); return; } private void updateCompatModeDownscale(GamePackageConfiguration packageConfig, String packageName, @GameMode int gameMode) { if (DEBUG) { Slog.v(TAG, dumpDeviceConfigs()); } if (packageConfig.willGamePerformOptimizations(gameMode)) { disableCompatScale(packageName); return; } final GamePackageConfiguration.GameModeConfiguration modeConfig = packageConfig.getGameModeConfiguration(gameMode); if (modeConfig == null) { Loading @@ -904,14 +957,13 @@ public final class GameManagerService extends IGameManagerService.Stub { } long scaleId = modeConfig.getCompatChangeId(); if (scaleId == 0) { Slog.i(TAG, "Invalid downscaling change id " + scaleId + " for " Slog.w(TAG, "Invalid downscaling change id " + scaleId + " for " + packageName); return; } enableCompatScale(packageName, scaleId); } } private int modeToBitmask(@GameMode int gameMode) { return (1 << gameMode); Loading @@ -927,16 +979,233 @@ public final class GameManagerService extends IGameManagerService.Stub { // ship. } private void updateInterventions(String packageName, @GameMode int gameMode) { updateCompatModeDownscale(packageName, gameMode); private void updateFps(GamePackageConfiguration packageConfig, String packageName, @GameMode int gameMode, @UserIdInt int userId) { final GamePackageConfiguration.GameModeConfiguration modeConfig = packageConfig.getGameModeConfiguration(gameMode); if (modeConfig == null) { Slog.d(TAG, "Game mode " + gameMode + " not found for " + packageName); return; } try { final float fps = modeConfig.getFps(); final int uid = mPackageManager.getPackageUidAsUser(packageName, userId); nativeSetOverrideFrameRate(uid, fps); } catch (PackageManager.NameNotFoundException e) { return; } } private void updateInterventions(String packageName, @GameMode int gameMode, @UserIdInt int userId) { if (gameMode == GameManager.GAME_MODE_STANDARD || gameMode == GameManager.GAME_MODE_UNSUPPORTED) { disableCompatScale(packageName); return; } GamePackageConfiguration packageConfig = null; synchronized (mOverrideConfigLock) { packageConfig = mOverrideConfigs.get(packageName); } if (packageConfig == null) { synchronized (mDeviceConfigLock) { packageConfig = mConfigs.get(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); } /** * Set the override Game Mode Configuration. * Update the config if exists, create one if not. */ @VisibleForTesting @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public void setGameModeConfigOverride(String packageName, @UserIdInt int userId, @GameMode int gameMode, String fpsStr, String scaling) throws SecurityException { checkPermission(Manifest.permission.MANAGE_GAME_MODE); synchronized (mLock) { if (!mSettings.containsKey(userId)) { return; } } // Adding override game mode configuration of the given package name synchronized (mOverrideConfigLock) { // look for the existing override GamePackageConfiguration GamePackageConfiguration overrideConfig = mOverrideConfigs.get(packageName); if (overrideConfig == null) { overrideConfig = new GamePackageConfiguration(packageName, userId); mOverrideConfigs.put(packageName, overrideConfig); } // modify GameModeConfiguration intervention settings GamePackageConfiguration.GameModeConfiguration overrideModeConfig = overrideConfig.getGameModeConfiguration(gameMode); if (fpsStr != null) { overrideModeConfig.setFpsStr(fpsStr); } else { overrideModeConfig.setFpsStr( GamePackageConfiguration.GameModeConfiguration.DEFAULT_FPS); } if (scaling != null) { overrideModeConfig.setScaling(scaling); } else { overrideModeConfig.setScaling( GamePackageConfiguration.GameModeConfiguration.DEFAULT_SCALING); } Slog.i(TAG, "Package Name: " + packageName + " FPS: " + String.valueOf(overrideModeConfig.getFps()) + " Scaling: " + overrideModeConfig.getScaling()); } setGameMode(packageName, gameMode, userId); } /** * Reset the overridden gameModeConfiguration of the given mode. * Remove the override config if game mode is not specified. */ @VisibleForTesting @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public void resetGameModeConfigOverride(String packageName, @UserIdInt int userId, @GameMode int gameModeToReset) throws SecurityException { checkPermission(Manifest.permission.MANAGE_GAME_MODE); synchronized (mLock) { if (!mSettings.containsKey(userId)) { return; } } // resets GamePackageConfiguration of a given packageName. // If a gameMode is specified, only reset the GameModeConfiguration of the gameMode. if (gameModeToReset != -1) { GamePackageConfiguration overrideConfig = null; synchronized (mOverrideConfigLock) { overrideConfig = mOverrideConfigs.get(packageName); } GamePackageConfiguration config = null; synchronized (mDeviceConfigLock) { config = mConfigs.get(packageName); } int[] modes = overrideConfig.getAvailableGameModes(); // First check if the mode to reset exists boolean isGameModeExist = false; for (int mode : modes) { if (gameModeToReset == mode) { isGameModeExist = true; } } if (!isGameModeExist) { return; } // If the game mode to reset is the only mode other than standard mode, // The override config is removed. if (modes.length <= 2) { synchronized (mOverrideConfigLock) { mOverrideConfigs.remove(packageName); } } else { // otherwise we reset the mode by copying the original config. overrideConfig.addModeConfig(config.getGameModeConfiguration(gameModeToReset)); } } else { synchronized (mOverrideConfigLock) { // remove override config if there is one mOverrideConfigs.remove(packageName); } } // Make sure after resetting the game mode is still supported. // If not, set the game mode to standard int gameMode = getGameMode(packageName, userId); int newGameMode = gameMode; GamePackageConfiguration config = null; synchronized (mOverrideConfigLock) { config = mOverrideConfigs.get(packageName); } synchronized (mDeviceConfigLock) { config = mConfigs.get(packageName); } if (config != null) { int modesBitfield = config.getAvailableGameModesBitfield(); // Remove UNSUPPORTED to simplify the logic here, since we really just // want to check if we support selectable game modes modesBitfield &= ~modeToBitmask(GameManager.GAME_MODE_UNSUPPORTED); if (!bitFieldContainsModeBitmask(modesBitfield, gameMode)) { if (bitFieldContainsModeBitmask(modesBitfield, GameManager.GAME_MODE_STANDARD)) { // If the current set mode isn't supported, // but we support STANDARD, then set the mode to STANDARD. newGameMode = GameManager.GAME_MODE_STANDARD; } else { // If we don't support any game modes, then set to UNSUPPORTED newGameMode = GameManager.GAME_MODE_UNSUPPORTED; } } } else if (gameMode != GameManager.GAME_MODE_UNSUPPORTED) { // If we have no config for the package, but the configured mode is not // UNSUPPORTED, then set to UNSUPPORTED newGameMode = GameManager.GAME_MODE_UNSUPPORTED; } if (gameMode != newGameMode) { setGameMode(packageName, GameManager.GAME_MODE_STANDARD, userId); return; } setGameMode(packageName, gameMode, userId); } /** * Returns the string listing all the interventions currently set to a game. */ public String getInterventionList(String packageName) { GamePackageConfiguration packageConfig = null; synchronized (mOverrideConfigLock) { packageConfig = mOverrideConfigs.get(packageName); } if (packageConfig == null) { synchronized (mDeviceConfigLock) { packageConfig = mConfigs.get(packageName); } } StringBuilder listStrSb = new StringBuilder(); if (packageConfig == null) { listStrSb.append("\n No intervention found for package ") .append(packageName); return listStrSb.toString(); } listStrSb.append("\nPackage name: ") .append(packageName) .append(packageConfig.toString()); return listStrSb.toString(); } /** * @hide */ @VisibleForTesting void updateConfigsForUser(int userId, String ...packageNames) { void updateConfigsForUser(@UserIdInt int userId, String ...packageNames) { try { synchronized (mDeviceConfigLock) { for (final String packageName : packageNames) { Loading @@ -954,14 +1223,19 @@ public final class GameManagerService extends IGameManagerService.Stub { } } } synchronized (mLock) { if (!mSettings.containsKey(userId)) { return; } } for (final String packageName : packageNames) { if (mSettings.containsKey(userId)) { int gameMode = getGameMode(packageName, userId); int newGameMode = gameMode; // Make sure the user settings and package configs don't conflict. I.e. the // user setting is set to a mode that no longer available due to config/manifest // changes. Most of the time we won't have to change anything. GamePackageConfiguration config; // Make sure the user settings and package configs don't conflict. // I.e. the user setting is set to a mode that no longer available due to // config/manifest changes. // Most of the time we won't have to change anything. GamePackageConfiguration config = null; synchronized (mDeviceConfigLock) { config = mConfigs.get(packageName); } Loading @@ -973,8 +1247,8 @@ public final class GameManagerService extends IGameManagerService.Stub { if (!bitFieldContainsModeBitmask(modesBitfield, gameMode)) { if (bitFieldContainsModeBitmask(modesBitfield, GameManager.GAME_MODE_STANDARD)) { // If the current set mode isn't supported, but we support STANDARD, // then set the mode to STANDARD. // If the current set mode isn't supported, // but we support STANDARD, then set the mode to STANDARD. newGameMode = GameManager.GAME_MODE_STANDARD; } else { // If we don't support any game modes, then set to UNSUPPORTED Loading @@ -989,8 +1263,7 @@ public final class GameManagerService extends IGameManagerService.Stub { if (newGameMode != gameMode) { setGameMode(packageName, newGameMode, userId); } updateInterventions(packageName, gameMode); } updateInterventions(packageName, gameMode, userId); } } catch (Exception e) { Slog.e(TAG, "Failed to update compat modes for user " + userId + ": " + e); Loading @@ -1011,7 +1284,16 @@ public final class GameManagerService extends IGameManagerService.Stub { */ @VisibleForTesting public GamePackageConfiguration getConfig(String packageName) { return mConfigs.get(packageName); GamePackageConfiguration packageConfig = null; synchronized (mOverrideConfigLock) { packageConfig = mOverrideConfigs.get(packageName); } if (packageConfig == null) { synchronized (mDeviceConfigLock) { packageConfig = mConfigs.get(packageName); } } return packageConfig; } private void registerPackageReceiver() { Loading Loading @@ -1047,6 +1329,9 @@ public final class GameManagerService extends IGameManagerService.Stub { break; case ACTION_PACKAGE_REMOVED: disableCompatScale(packageName); synchronized (mOverrideConfigLock) { mOverrideConfigs.remove(packageName); } synchronized (mDeviceConfigLock) { mConfigs.remove(packageName); } Loading Loading @@ -1083,4 +1368,9 @@ public final class GameManagerService extends IGameManagerService.Stub { handlerThread.start(); return handlerThread; } /** * load dynamic library for frame rate overriding JNI calls */ private static native void nativeSetOverrideFrameRate(int uid, float frameRate); } services/core/java/com/android/server/app/GameManagerShellCommand.java +210 −46 File changed.Preview size limit exceeded, changes collapsed. Show changes services/core/jni/Android.bp +15 −0 Original line number Diff line number Diff line Loading @@ -71,11 +71,14 @@ cc_library_static { "onload.cpp", ":lib_cachedAppOptimizer_native", ":lib_networkStatsFactory_native", ":lib_gameManagerService_native", ], include_dirs: [ "frameworks/base/libs", "frameworks/native/services", "frameworks/native/libs/math/include", "frameworks/native/libs/ui/include", "system/gatekeeper/include", "system/memory/libmeminfo/include", ], Loading Loading @@ -103,6 +106,7 @@ cc_defaults { "libcrypto", "liblog", "libgraphicsenv", "libgralloctypes", "libhardware", "libhardware_legacy", "libhidlbase", Loading Loading @@ -157,6 +161,10 @@ cc_defaults { "android.hardware.gnss.measurement_corrections@1.0", "android.hardware.gnss.visibility_control@1.0", "android.hardware.graphics.bufferqueue@1.0", "android.hardware.graphics.bufferqueue@2.0", "android.hardware.graphics.common@1.2", "android.hardware.graphics.common-V3-ndk", "android.hardware.graphics.mapper@4.0", "android.hardware.input.classifier@1.0", "android.hardware.ir@1.0", "android.hardware.light@2.0", Loading Loading @@ -216,3 +224,10 @@ filegroup { "com_android_server_am_CachedAppOptimizer.cpp", ], } filegroup { name: "lib_gameManagerService_native", srcs: [ "com_android_server_app_GameManagerService.cpp", ], } services/core/jni/com_android_server_app_GameManagerService.cpp 0 → 100644 +44 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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. */ #define LOG_TAG "GameManagerService" #include <android/log.h> #include <gui/SurfaceComposerClient.h> #include <log/log.h> #include <nativehelper/JNIHelp.h> #include "jni.h" namespace android { static void android_server_app_GameManagerService_nativeSetOverrideFrameRate(JNIEnv* env, jclass clazz, jint uid, jfloat frameRate) { SurfaceComposerClient::setOverrideFrameRate(uid, frameRate); } static const JNINativeMethod gMethods[] = { {"nativeSetOverrideFrameRate", "(IF)V", (void*)android_server_app_GameManagerService_nativeSetOverrideFrameRate}, }; int register_android_server_app_GameManagerService(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/server/app/GameManagerService", gMethods, NELEM(gMethods)); } }; // namespace android No newline at end of file services/core/jni/onload.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ int register_android_server_GpuService(JNIEnv* env); int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env); int register_android_server_sensor_SensorService(JavaVM* vm, JNIEnv* env); int register_android_server_companion_virtual_InputController(JNIEnv* env); int register_android_server_app_GameManagerService(JNIEnv* env); }; using namespace android; Loading Loading @@ -121,5 +122,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_stats_pull_StatsPullAtomService(env); register_android_server_sensor_SensorService(vm, env); register_android_server_companion_virtual_InputController(env); register_android_server_app_GameManagerService(env); return JNI_VERSION_1_4; } Loading
services/core/java/com/android/server/app/GameManagerService.java +371 −81 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.GameManager; import android.app.GameManager.GameMode; Loading Loading @@ -81,6 +82,7 @@ import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.SystemService.TargetUser; import com.android.server.app.GameManagerService.GamePackageConfiguration.GameModeConfiguration; import java.io.FileDescriptor; import java.util.List; Loading Loading @@ -113,6 +115,7 @@ public final class GameManagerService extends IGameManagerService.Stub { private final Context mContext; private final Object mLock = new Object(); private final Object mDeviceConfigLock = new Object(); private final Object mOverrideConfigLock = new Object(); private final Handler mHandler; private final PackageManager mPackageManager; private final IPlatformCompat mPlatformCompat; Loading @@ -122,6 +125,8 @@ public final class GameManagerService extends IGameManagerService.Stub { private final ArrayMap<Integer, GameManagerSettings> mSettings = new ArrayMap<>(); @GuardedBy("mDeviceConfigLock") private final ArrayMap<String, GamePackageConfiguration> mConfigs = new ArrayMap<>(); @GuardedBy("mOverrideConfigLock") private final ArrayMap<String, GamePackageConfiguration> mOverrideConfigs = new ArrayMap<>(); public GameManagerService(Context context) { this(context, createServiceThread().getLooper()); Loading Loading @@ -281,13 +286,51 @@ public final class GameManagerService extends IGameManagerService.Stub { return 0; } public enum FrameRate { FPS_DEFAULT(0), FPS_30(30), FPS_45(45), FPS_60(60), FPS_90(90), FPS_120(120), FPS_INVALID(-1); public final int fps; FrameRate(int fps) { this.fps = fps; } } // Turn the raw string to the corresponding fps int. // Return 0 when disabling, -1 for invalid fps. static int getFpsInt(String raw) { switch (raw) { case "30": return FrameRate.FPS_30.fps; case "45": return FrameRate.FPS_45.fps; case "60": return FrameRate.FPS_60.fps; case "90": return FrameRate.FPS_90.fps; case "120": return FrameRate.FPS_120.fps; case "disable": case "": return FrameRate.FPS_DEFAULT.fps; } return FrameRate.FPS_INVALID.fps; } /** * Called by games to communicate the current state to the platform. * @param packageName The client package name. * @param gameState An object set to the current state. * @param userId The user associated with this state. */ public void setGameState(String packageName, @NonNull GameState gameState, int userId) { public void setGameState(String packageName, @NonNull GameState gameState, @UserIdInt int userId) { if (!isPackageGame(packageName, userId)) { // Restrict to games only. return; Loading Loading @@ -399,11 +442,14 @@ public final class GameManagerService extends IGameManagerService.Stub { public static final String TAG = "GameManagerService_GameModeConfiguration"; 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"; private final @GameMode int mGameMode; private final String mScaling; private String mScaling; private String mFps; private final boolean mUseAngle; GameModeConfiguration(KeyValueListParser parser) { Loading @@ -414,6 +460,8 @@ public final class GameManagerService extends IGameManagerService.Stub { // using ANGLE). mScaling = !mAllowDownscale || willGamePerformOptimizations(mGameMode) ? DEFAULT_SCALING : parser.getString(SCALING_KEY, DEFAULT_SCALING); mFps = parser.getString(FPS_KEY, DEFAULT_FPS); // 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 Loading @@ -430,14 +478,27 @@ public final class GameManagerService extends IGameManagerService.Stub { return mScaling; } public int getFps() { return GameManagerService.getFpsInt(mFps); } public boolean getUseAngle() { return mUseAngle; } public void setScaling(String scaling) { mScaling = scaling; } public void setFpsStr(String fpsStr) { mFps = fpsStr; } public boolean isValid() { return mGameMode == GameManager.GAME_MODE_STANDARD return (mGameMode == GameManager.GAME_MODE_STANDARD || mGameMode == GameManager.GAME_MODE_PERFORMANCE || mGameMode == GameManager.GAME_MODE_BATTERY; || mGameMode == GameManager.GAME_MODE_BATTERY) && !willGamePerformOptimizations(mGameMode); } /** Loading @@ -445,7 +506,7 @@ public final class GameManagerService extends IGameManagerService.Stub { */ public String toString() { return "[Game Mode:" + mGameMode + ",Scaling:" + mScaling + ",Use Angle:" + mUseAngle + "]"; + mUseAngle + ",Fps:" + mFps + "]"; } /** Loading Loading @@ -641,16 +702,22 @@ public final class GameManagerService extends IGameManagerService.Stub { @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public @GameMode int[] getAvailableGameModes(String packageName) throws SecurityException { checkPermission(Manifest.permission.MANAGE_GAME_MODE); GamePackageConfiguration config = null; synchronized (mOverrideConfigLock) { config = mOverrideConfigs.get(packageName); } if (config == null) { synchronized (mDeviceConfigLock) { final GamePackageConfiguration config = mConfigs.get(packageName); config = mConfigs.get(packageName); } } if (config == null) { return new int[]{GameManager.GAME_MODE_UNSUPPORTED}; } return config.getAvailableGameModes(); } } private @GameMode int getGameModeFromSettings(String packageName, int userId) { 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" Loading Loading @@ -743,7 +810,7 @@ public final class GameManagerService extends IGameManagerService.Stub { mHandler.sendMessageDelayed(msg, WRITE_SETTINGS_DELAY); } } updateInterventions(packageName, gameMode); updateInterventions(packageName, gameMode, userId); } /** Loading Loading @@ -876,26 +943,12 @@ public final class GameManagerService extends IGameManagerService.Stub { } } private void updateCompatModeDownscale(String packageName, @GameMode int gameMode) { synchronized (mDeviceConfigLock) { if (gameMode == GameManager.GAME_MODE_STANDARD || gameMode == GameManager.GAME_MODE_UNSUPPORTED) { disableCompatScale(packageName); return; } final GamePackageConfiguration packageConfig = mConfigs.get(packageName); if (packageConfig == null) { disableCompatScale(packageName); Slog.v(TAG, "Package configuration not found for " + packageName); return; } private void updateCompatModeDownscale(GamePackageConfiguration packageConfig, String packageName, @GameMode int gameMode) { if (DEBUG) { Slog.v(TAG, dumpDeviceConfigs()); } if (packageConfig.willGamePerformOptimizations(gameMode)) { disableCompatScale(packageName); return; } final GamePackageConfiguration.GameModeConfiguration modeConfig = packageConfig.getGameModeConfiguration(gameMode); if (modeConfig == null) { Loading @@ -904,14 +957,13 @@ public final class GameManagerService extends IGameManagerService.Stub { } long scaleId = modeConfig.getCompatChangeId(); if (scaleId == 0) { Slog.i(TAG, "Invalid downscaling change id " + scaleId + " for " Slog.w(TAG, "Invalid downscaling change id " + scaleId + " for " + packageName); return; } enableCompatScale(packageName, scaleId); } } private int modeToBitmask(@GameMode int gameMode) { return (1 << gameMode); Loading @@ -927,16 +979,233 @@ public final class GameManagerService extends IGameManagerService.Stub { // ship. } private void updateInterventions(String packageName, @GameMode int gameMode) { updateCompatModeDownscale(packageName, gameMode); private void updateFps(GamePackageConfiguration packageConfig, String packageName, @GameMode int gameMode, @UserIdInt int userId) { final GamePackageConfiguration.GameModeConfiguration modeConfig = packageConfig.getGameModeConfiguration(gameMode); if (modeConfig == null) { Slog.d(TAG, "Game mode " + gameMode + " not found for " + packageName); return; } try { final float fps = modeConfig.getFps(); final int uid = mPackageManager.getPackageUidAsUser(packageName, userId); nativeSetOverrideFrameRate(uid, fps); } catch (PackageManager.NameNotFoundException e) { return; } } private void updateInterventions(String packageName, @GameMode int gameMode, @UserIdInt int userId) { if (gameMode == GameManager.GAME_MODE_STANDARD || gameMode == GameManager.GAME_MODE_UNSUPPORTED) { disableCompatScale(packageName); return; } GamePackageConfiguration packageConfig = null; synchronized (mOverrideConfigLock) { packageConfig = mOverrideConfigs.get(packageName); } if (packageConfig == null) { synchronized (mDeviceConfigLock) { packageConfig = mConfigs.get(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); } /** * Set the override Game Mode Configuration. * Update the config if exists, create one if not. */ @VisibleForTesting @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public void setGameModeConfigOverride(String packageName, @UserIdInt int userId, @GameMode int gameMode, String fpsStr, String scaling) throws SecurityException { checkPermission(Manifest.permission.MANAGE_GAME_MODE); synchronized (mLock) { if (!mSettings.containsKey(userId)) { return; } } // Adding override game mode configuration of the given package name synchronized (mOverrideConfigLock) { // look for the existing override GamePackageConfiguration GamePackageConfiguration overrideConfig = mOverrideConfigs.get(packageName); if (overrideConfig == null) { overrideConfig = new GamePackageConfiguration(packageName, userId); mOverrideConfigs.put(packageName, overrideConfig); } // modify GameModeConfiguration intervention settings GamePackageConfiguration.GameModeConfiguration overrideModeConfig = overrideConfig.getGameModeConfiguration(gameMode); if (fpsStr != null) { overrideModeConfig.setFpsStr(fpsStr); } else { overrideModeConfig.setFpsStr( GamePackageConfiguration.GameModeConfiguration.DEFAULT_FPS); } if (scaling != null) { overrideModeConfig.setScaling(scaling); } else { overrideModeConfig.setScaling( GamePackageConfiguration.GameModeConfiguration.DEFAULT_SCALING); } Slog.i(TAG, "Package Name: " + packageName + " FPS: " + String.valueOf(overrideModeConfig.getFps()) + " Scaling: " + overrideModeConfig.getScaling()); } setGameMode(packageName, gameMode, userId); } /** * Reset the overridden gameModeConfiguration of the given mode. * Remove the override config if game mode is not specified. */ @VisibleForTesting @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public void resetGameModeConfigOverride(String packageName, @UserIdInt int userId, @GameMode int gameModeToReset) throws SecurityException { checkPermission(Manifest.permission.MANAGE_GAME_MODE); synchronized (mLock) { if (!mSettings.containsKey(userId)) { return; } } // resets GamePackageConfiguration of a given packageName. // If a gameMode is specified, only reset the GameModeConfiguration of the gameMode. if (gameModeToReset != -1) { GamePackageConfiguration overrideConfig = null; synchronized (mOverrideConfigLock) { overrideConfig = mOverrideConfigs.get(packageName); } GamePackageConfiguration config = null; synchronized (mDeviceConfigLock) { config = mConfigs.get(packageName); } int[] modes = overrideConfig.getAvailableGameModes(); // First check if the mode to reset exists boolean isGameModeExist = false; for (int mode : modes) { if (gameModeToReset == mode) { isGameModeExist = true; } } if (!isGameModeExist) { return; } // If the game mode to reset is the only mode other than standard mode, // The override config is removed. if (modes.length <= 2) { synchronized (mOverrideConfigLock) { mOverrideConfigs.remove(packageName); } } else { // otherwise we reset the mode by copying the original config. overrideConfig.addModeConfig(config.getGameModeConfiguration(gameModeToReset)); } } else { synchronized (mOverrideConfigLock) { // remove override config if there is one mOverrideConfigs.remove(packageName); } } // Make sure after resetting the game mode is still supported. // If not, set the game mode to standard int gameMode = getGameMode(packageName, userId); int newGameMode = gameMode; GamePackageConfiguration config = null; synchronized (mOverrideConfigLock) { config = mOverrideConfigs.get(packageName); } synchronized (mDeviceConfigLock) { config = mConfigs.get(packageName); } if (config != null) { int modesBitfield = config.getAvailableGameModesBitfield(); // Remove UNSUPPORTED to simplify the logic here, since we really just // want to check if we support selectable game modes modesBitfield &= ~modeToBitmask(GameManager.GAME_MODE_UNSUPPORTED); if (!bitFieldContainsModeBitmask(modesBitfield, gameMode)) { if (bitFieldContainsModeBitmask(modesBitfield, GameManager.GAME_MODE_STANDARD)) { // If the current set mode isn't supported, // but we support STANDARD, then set the mode to STANDARD. newGameMode = GameManager.GAME_MODE_STANDARD; } else { // If we don't support any game modes, then set to UNSUPPORTED newGameMode = GameManager.GAME_MODE_UNSUPPORTED; } } } else if (gameMode != GameManager.GAME_MODE_UNSUPPORTED) { // If we have no config for the package, but the configured mode is not // UNSUPPORTED, then set to UNSUPPORTED newGameMode = GameManager.GAME_MODE_UNSUPPORTED; } if (gameMode != newGameMode) { setGameMode(packageName, GameManager.GAME_MODE_STANDARD, userId); return; } setGameMode(packageName, gameMode, userId); } /** * Returns the string listing all the interventions currently set to a game. */ public String getInterventionList(String packageName) { GamePackageConfiguration packageConfig = null; synchronized (mOverrideConfigLock) { packageConfig = mOverrideConfigs.get(packageName); } if (packageConfig == null) { synchronized (mDeviceConfigLock) { packageConfig = mConfigs.get(packageName); } } StringBuilder listStrSb = new StringBuilder(); if (packageConfig == null) { listStrSb.append("\n No intervention found for package ") .append(packageName); return listStrSb.toString(); } listStrSb.append("\nPackage name: ") .append(packageName) .append(packageConfig.toString()); return listStrSb.toString(); } /** * @hide */ @VisibleForTesting void updateConfigsForUser(int userId, String ...packageNames) { void updateConfigsForUser(@UserIdInt int userId, String ...packageNames) { try { synchronized (mDeviceConfigLock) { for (final String packageName : packageNames) { Loading @@ -954,14 +1223,19 @@ public final class GameManagerService extends IGameManagerService.Stub { } } } synchronized (mLock) { if (!mSettings.containsKey(userId)) { return; } } for (final String packageName : packageNames) { if (mSettings.containsKey(userId)) { int gameMode = getGameMode(packageName, userId); int newGameMode = gameMode; // Make sure the user settings and package configs don't conflict. I.e. the // user setting is set to a mode that no longer available due to config/manifest // changes. Most of the time we won't have to change anything. GamePackageConfiguration config; // Make sure the user settings and package configs don't conflict. // I.e. the user setting is set to a mode that no longer available due to // config/manifest changes. // Most of the time we won't have to change anything. GamePackageConfiguration config = null; synchronized (mDeviceConfigLock) { config = mConfigs.get(packageName); } Loading @@ -973,8 +1247,8 @@ public final class GameManagerService extends IGameManagerService.Stub { if (!bitFieldContainsModeBitmask(modesBitfield, gameMode)) { if (bitFieldContainsModeBitmask(modesBitfield, GameManager.GAME_MODE_STANDARD)) { // If the current set mode isn't supported, but we support STANDARD, // then set the mode to STANDARD. // If the current set mode isn't supported, // but we support STANDARD, then set the mode to STANDARD. newGameMode = GameManager.GAME_MODE_STANDARD; } else { // If we don't support any game modes, then set to UNSUPPORTED Loading @@ -989,8 +1263,7 @@ public final class GameManagerService extends IGameManagerService.Stub { if (newGameMode != gameMode) { setGameMode(packageName, newGameMode, userId); } updateInterventions(packageName, gameMode); } updateInterventions(packageName, gameMode, userId); } } catch (Exception e) { Slog.e(TAG, "Failed to update compat modes for user " + userId + ": " + e); Loading @@ -1011,7 +1284,16 @@ public final class GameManagerService extends IGameManagerService.Stub { */ @VisibleForTesting public GamePackageConfiguration getConfig(String packageName) { return mConfigs.get(packageName); GamePackageConfiguration packageConfig = null; synchronized (mOverrideConfigLock) { packageConfig = mOverrideConfigs.get(packageName); } if (packageConfig == null) { synchronized (mDeviceConfigLock) { packageConfig = mConfigs.get(packageName); } } return packageConfig; } private void registerPackageReceiver() { Loading Loading @@ -1047,6 +1329,9 @@ public final class GameManagerService extends IGameManagerService.Stub { break; case ACTION_PACKAGE_REMOVED: disableCompatScale(packageName); synchronized (mOverrideConfigLock) { mOverrideConfigs.remove(packageName); } synchronized (mDeviceConfigLock) { mConfigs.remove(packageName); } Loading Loading @@ -1083,4 +1368,9 @@ public final class GameManagerService extends IGameManagerService.Stub { handlerThread.start(); return handlerThread; } /** * load dynamic library for frame rate overriding JNI calls */ private static native void nativeSetOverrideFrameRate(int uid, float frameRate); }
services/core/java/com/android/server/app/GameManagerShellCommand.java +210 −46 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/core/jni/Android.bp +15 −0 Original line number Diff line number Diff line Loading @@ -71,11 +71,14 @@ cc_library_static { "onload.cpp", ":lib_cachedAppOptimizer_native", ":lib_networkStatsFactory_native", ":lib_gameManagerService_native", ], include_dirs: [ "frameworks/base/libs", "frameworks/native/services", "frameworks/native/libs/math/include", "frameworks/native/libs/ui/include", "system/gatekeeper/include", "system/memory/libmeminfo/include", ], Loading Loading @@ -103,6 +106,7 @@ cc_defaults { "libcrypto", "liblog", "libgraphicsenv", "libgralloctypes", "libhardware", "libhardware_legacy", "libhidlbase", Loading Loading @@ -157,6 +161,10 @@ cc_defaults { "android.hardware.gnss.measurement_corrections@1.0", "android.hardware.gnss.visibility_control@1.0", "android.hardware.graphics.bufferqueue@1.0", "android.hardware.graphics.bufferqueue@2.0", "android.hardware.graphics.common@1.2", "android.hardware.graphics.common-V3-ndk", "android.hardware.graphics.mapper@4.0", "android.hardware.input.classifier@1.0", "android.hardware.ir@1.0", "android.hardware.light@2.0", Loading Loading @@ -216,3 +224,10 @@ filegroup { "com_android_server_am_CachedAppOptimizer.cpp", ], } filegroup { name: "lib_gameManagerService_native", srcs: [ "com_android_server_app_GameManagerService.cpp", ], }
services/core/jni/com_android_server_app_GameManagerService.cpp 0 → 100644 +44 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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. */ #define LOG_TAG "GameManagerService" #include <android/log.h> #include <gui/SurfaceComposerClient.h> #include <log/log.h> #include <nativehelper/JNIHelp.h> #include "jni.h" namespace android { static void android_server_app_GameManagerService_nativeSetOverrideFrameRate(JNIEnv* env, jclass clazz, jint uid, jfloat frameRate) { SurfaceComposerClient::setOverrideFrameRate(uid, frameRate); } static const JNINativeMethod gMethods[] = { {"nativeSetOverrideFrameRate", "(IF)V", (void*)android_server_app_GameManagerService_nativeSetOverrideFrameRate}, }; int register_android_server_app_GameManagerService(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/server/app/GameManagerService", gMethods, NELEM(gMethods)); } }; // namespace android No newline at end of file
services/core/jni/onload.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ int register_android_server_GpuService(JNIEnv* env); int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env); int register_android_server_sensor_SensorService(JavaVM* vm, JNIEnv* env); int register_android_server_companion_virtual_InputController(JNIEnv* env); int register_android_server_app_GameManagerService(JNIEnv* env); }; using namespace android; Loading Loading @@ -121,5 +122,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_stats_pull_StatsPullAtomService(env); register_android_server_sensor_SensorService(vm, env); register_android_server_companion_virtual_InputController(env); register_android_server_app_GameManagerService(env); return JNI_VERSION_1_4; }