Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 03a46a1f authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Refactoring GameManagerServiceShellCommand"

parents f548eef0 42842fda
Loading
Loading
Loading
Loading
+371 −81
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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());
@@ -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;
@@ -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) {
@@ -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
@@ -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);
            }

            /**
@@ -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 + "]";
            }

            /**
@@ -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"
@@ -743,7 +810,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
                mHandler.sendMessageDelayed(msg, WRITE_SETTINGS_DELAY);
            }
        }
        updateInterventions(packageName, gameMode);
        updateInterventions(packageName, gameMode, userId);
    }

    /**
@@ -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) {
@@ -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);
@@ -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) {
@@ -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);
                }
@@ -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
@@ -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);
@@ -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() {
@@ -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);
                            }
@@ -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);
}
+210 −46

File changed.

Preview size limit exceeded, changes collapsed.

+15 −0
Original line number Diff line number Diff line
@@ -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",
    ],
@@ -103,6 +106,7 @@ cc_defaults {
        "libcrypto",
        "liblog",
        "libgraphicsenv",
        "libgralloctypes",
        "libhardware",
        "libhardware_legacy",
        "libhidlbase",
@@ -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",
@@ -216,3 +224,10 @@ filegroup {
        "com_android_server_am_CachedAppOptimizer.cpp",
    ],
}

filegroup {
    name: "lib_gameManagerService_native",
    srcs: [
        "com_android_server_app_GameManagerService.cpp",
    ],
}
+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
+2 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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