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

Commit 57c29409 authored by Xiang Wang's avatar Xiang Wang Committed by Automerger Merge Worker
Browse files

Override config should trigger intervention ignoring opt-in info am: 5abb52c1

parents 7b3207a2 5abb52c1
Loading
Loading
Loading
Loading
+72 −13
Original line number Original line Diff line number Diff line
@@ -117,6 +117,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
import java.util.HashSet;
import java.util.HashSet;
import java.util.List;
import java.util.List;
import java.util.Map;


/**
/**
 * Service to manage game related features.
 * Service to manage game related features.
@@ -556,16 +557,21 @@ public final class GameManagerService extends IGameManagerService.Stub {
        private final String mPackageName;
        private final String mPackageName;
        private final Object mModeConfigLock = new Object();
        private final Object mModeConfigLock = new Object();
        @GuardedBy("mModeConfigLock")
        @GuardedBy("mModeConfigLock")
        private final ArrayMap<Integer, GameModeConfiguration> mModeConfigs;
        private final ArrayMap<Integer, GameModeConfiguration> mModeConfigs = new ArrayMap<>();
        // if adding new properties or make any of the below overridable, the method
        // copyAndApplyOverride should be updated accordingly
        private boolean mPerfModeOptedIn = false;
        private boolean mPerfModeOptedIn = false;
        private boolean mBatteryModeOptedIn = false;
        private boolean mBatteryModeOptedIn = false;
        private boolean mAllowDownscale = true;
        private boolean mAllowDownscale = true;
        private boolean mAllowAngle = true;
        private boolean mAllowAngle = true;
        private boolean mAllowFpsOverride = true;
        private boolean mAllowFpsOverride = true;


        GamePackageConfiguration(String packageName) {
            mPackageName = packageName;
        }

        GamePackageConfiguration(String packageName, int userId) {
        GamePackageConfiguration(String packageName, int userId) {
            mPackageName = packageName;
            mPackageName = packageName;
            mModeConfigs = new ArrayMap<>();


            try {
            try {
                final ApplicationInfo ai = mPackageManager.getApplicationInfoAsUser(packageName,
                final ApplicationInfo ai = mPackageManager.getApplicationInfoAsUser(packageName,
@@ -649,6 +655,13 @@ public final class GameManagerService extends IGameManagerService.Stub {
            return xmlFound;
            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
         * GameModeConfiguration contains all the values for all the interventions associated with
         * a game mode.
         * a game mode.
@@ -661,15 +674,23 @@ public final class GameManagerService extends IGameManagerService.Stub {
            public static final String FPS_KEY = "fps";
            public static final String FPS_KEY = "fps";
            public static final String DEFAULT_SCALING = "1.0";
            public static final String DEFAULT_SCALING = "1.0";
            public static final String DEFAULT_FPS = "";
            public static final String DEFAULT_FPS = "";
            public static final boolean DEFAULT_USE_ANGLE = false;
            public static final int DEFAULT_LOADING_BOOST_DURATION = -1;
            public static final String ANGLE_KEY = "useAngle";
            public static final String ANGLE_KEY = "useAngle";
            public static final String LOADING_BOOST_KEY = "loadingBoost";
            public static final String LOADING_BOOST_KEY = "loadingBoost";


            private final @GameMode int mGameMode;
            private final @GameMode int mGameMode;
            private String mScaling;
            private String mScaling = DEFAULT_SCALING;
            private String mFps;
            private String mFps = DEFAULT_FPS;
            private final boolean mUseAngle;
            private final boolean mUseAngle;
            private final int mLoadingBoostDuration;
            private final int mLoadingBoostDuration;


            GameModeConfiguration(int gameMode) {
                mGameMode = gameMode;
                mUseAngle = DEFAULT_USE_ANGLE;
                mLoadingBoostDuration = DEFAULT_LOADING_BOOST_DURATION;
            }

            GameModeConfiguration(KeyValueListParser parser) {
            GameModeConfiguration(KeyValueListParser parser) {
                mGameMode = parser.getInt(MODE_KEY, GameManager.GAME_MODE_UNSUPPORTED);
                mGameMode = parser.getInt(MODE_KEY, GameManager.GAME_MODE_UNSUPPORTED);
                // isGameModeOptedIn() returns if an app will handle all of the changes necessary
                // isGameModeOptedIn() returns if an app will handle all of the changes necessary
@@ -832,6 +853,42 @@ public final class GameManagerService extends IGameManagerService.Stub {
            }
            }
        }
        }


        GamePackageConfiguration copyAndApplyOverride(GamePackageConfiguration overrideConfig) {
            GamePackageConfiguration copy = new GamePackageConfiguration(mPackageName);
            // if a game mode is overridden, we treat it with the highest priority and reset any
            // opt-in game modes so that interventions are always executed.
            copy.mPerfModeOptedIn = mPerfModeOptedIn && !(overrideConfig != null
                    && overrideConfig.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE)
                    != null);
            copy.mBatteryModeOptedIn = mBatteryModeOptedIn && !(overrideConfig != null
                    && overrideConfig.getGameModeConfiguration(GameManager.GAME_MODE_BATTERY)
                    != null);

            // if any game mode is overridden, we will consider all interventions forced-active,
            // this can be done more granular by checking if a specific intervention is
            // overridden under each game mode override, but only if necessary.
            copy.mAllowDownscale = mAllowDownscale || overrideConfig != null;
            copy.mAllowAngle = mAllowAngle || overrideConfig != null;
            copy.mAllowFpsOverride = mAllowFpsOverride || overrideConfig != null;
            if (overrideConfig != null) {
                synchronized (copy.mModeConfigLock) {
                    synchronized (mModeConfigLock) {
                        for (Map.Entry<Integer, GameModeConfiguration> entry :
                                mModeConfigs.entrySet()) {
                            copy.mModeConfigs.put(entry.getKey(), entry.getValue());
                        }
                    }
                    synchronized (overrideConfig.mModeConfigLock) {
                        for (Map.Entry<Integer, GameModeConfiguration> entry :
                                overrideConfig.mModeConfigs.entrySet()) {
                            copy.mModeConfigs.put(entry.getKey(), entry.getValue());
                        }
                    }
                }
            }
            return copy;
        }

        public String toString() {
        public String toString() {
            synchronized (mModeConfigLock) {
            synchronized (mModeConfigLock) {
                return "[Name:" + mPackageName + " Modes: " + mModeConfigs.toString() + "]";
                return "[Name:" + mPackageName + " Modes: " + mModeConfigs.toString() + "]";
@@ -1402,13 +1459,13 @@ public final class GameManagerService extends IGameManagerService.Stub {
            // look for the existing override GamePackageConfiguration
            // look for the existing override GamePackageConfiguration
            overrideConfig = mOverrideConfigs.get(packageName);
            overrideConfig = mOverrideConfigs.get(packageName);
            if (overrideConfig == null) {
            if (overrideConfig == null) {
                overrideConfig = new GamePackageConfiguration(packageName, userId);
                overrideConfig = new GamePackageConfiguration(packageName);
                mOverrideConfigs.put(packageName, overrideConfig);
                mOverrideConfigs.put(packageName, overrideConfig);
            }
            }
        }
        }
        // modify GameModeConfiguration intervention settings
        // modify GameModeConfiguration intervention settings
        GamePackageConfiguration.GameModeConfiguration overrideModeConfig =
        GamePackageConfiguration.GameModeConfiguration overrideModeConfig =
                overrideConfig.getGameModeConfiguration(gameMode);
                overrideConfig.getOrAddDefaultGameModeConfiguration(gameMode);


        if (fpsStr != null) {
        if (fpsStr != null) {
            overrideModeConfig.setFpsStr(fpsStr);
            overrideModeConfig.setFpsStr(fpsStr);
@@ -1704,16 +1761,18 @@ public final class GameManagerService extends IGameManagerService.Stub {
     */
     */
    @VisibleForTesting
    @VisibleForTesting
    public GamePackageConfiguration getConfig(String packageName) {
    public GamePackageConfiguration getConfig(String packageName) {
        GamePackageConfiguration packageConfig = null;
        GamePackageConfiguration overrideConfig = null;
        synchronized (mOverrideConfigLock) {
        GamePackageConfiguration config;
            packageConfig = mOverrideConfigs.get(packageName);
        }
        if (packageConfig == null) {
        synchronized (mDeviceConfigLock) {
        synchronized (mDeviceConfigLock) {
                packageConfig = mConfigs.get(packageName);
            config = mConfigs.get(packageName);
        }
        synchronized (mOverrideConfigLock) {
            overrideConfig = mOverrideConfigs.get(packageName);
        }
        }
        if (overrideConfig == null || config == null) {
            return overrideConfig == null ? config : overrideConfig;
        }
        }
        return packageConfig;
        return config.copyAndApplyOverride(overrideConfig);
    }
    }


    private void registerPackageReceiver() {
    private void registerPackageReceiver() {
+9 −0
Original line number Original line Diff line number Diff line
<?xml version="1.0" encoding="UTF-8"?>
<game-mode-config
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:supportsPerformanceGameMode="true"
    android:supportsBatteryGameMode="true"
    android:allowGameAngleDriver="false"
    android:allowGameDownscaling="false"
    android:allowGameFpsOverride="false"
/>
 No newline at end of file
+0 −0

File moved.

+0 −0

File moved.

+99 −26
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.app;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertThrows;
@@ -369,38 +370,35 @@ public class GameManagerServiceTests {
                .thenReturn(applicationInfo);
                .thenReturn(applicationInfo);
    }
    }


    private void mockInterventionsEnabledFromXml() throws Exception {
    private void mockInterventionsEnabledNoOptInFromXml() throws Exception {
        final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
        seedGameManagerServiceMetaDataFromFile(mPackageName, 123,
                mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
                "res/xml/game_manager_service_metadata_config_interventions_enabled_no_opt_in.xml");
        Bundle metaDataBundle = new Bundle();
    }
        final int resId = 123;

        metaDataBundle.putInt(
    private void mockInterventionsDisabledNoOptInFromXml() throws Exception {
                GameManagerService.GamePackageConfiguration.METADATA_GAME_MODE_CONFIG, resId);
        seedGameManagerServiceMetaDataFromFile(mPackageName, 123,
        applicationInfo.metaData = metaDataBundle;
                "res/xml/game_manager_service_metadata_config_interventions_disabled_no_opt_in"
        when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
                        + ".xml");
                .thenReturn(applicationInfo);
        seedGameManagerServiceMetaDataFromFile(mPackageName, resId,
                "res/xml/gama_manager_service_metadata_config_enabled.xml");
    }
    }


    private void mockInterventionsDisabledFromXml() throws Exception {
    private void mockInterventionsDisabledAllOptInFromXml() throws Exception {
        seedGameManagerServiceMetaDataFromFile(mPackageName, 123,
                "res/xml/game_manager_service_metadata_config_interventions_disabled_all_opt_in"
                        + ".xml");
    }


    private void seedGameManagerServiceMetaDataFromFile(String packageName, int resId,
            String fileName)
            throws Exception {
        final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
        final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
                mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
                mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
        Bundle metaDataBundle = new Bundle();
        Bundle metaDataBundle = new Bundle();
        final int resId = 123;
        metaDataBundle.putInt(
        metaDataBundle.putInt(
                GameManagerService.GamePackageConfiguration.METADATA_GAME_MODE_CONFIG, resId);
                GameManagerService.GamePackageConfiguration.METADATA_GAME_MODE_CONFIG, resId);
        applicationInfo.metaData = metaDataBundle;
        applicationInfo.metaData = metaDataBundle;
        when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
        when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
                .thenReturn(applicationInfo);
                .thenReturn(applicationInfo);
        seedGameManagerServiceMetaDataFromFile(mPackageName, resId,
                "res/xml/gama_manager_service_metadata_config_disabled.xml");
    }


    private void seedGameManagerServiceMetaDataFromFile(String packageName, int resId,
            String fileName)
            throws Exception {
        AssetManager assetManager =
        AssetManager assetManager =
                InstrumentationRegistry.getInstrumentation().getContext().getAssets();
                InstrumentationRegistry.getInstrumentation().getContext().getAssets();
        XmlResourceParser xmlResourceParser =
        XmlResourceParser xmlResourceParser =
@@ -628,6 +626,12 @@ public class GameManagerServiceTests {
        assertEquals(fps, config.getGameModeConfiguration(gameMode).getFps());
        assertEquals(fps, config.getGameModeConfiguration(gameMode).getFps());
    }
    }


    private boolean checkOptedIn(GameManagerService gameManagerService, int gameMode) {
        GameManagerService.GamePackageConfiguration config =
                gameManagerService.getConfig(mPackageName);
        return config.willGamePerformOptimizations(gameMode);
    }

    /**
    /**
     * Phenotype device config exists, but is only propagating the default value.
     * Phenotype device config exists, but is only propagating the default value.
     */
     */
@@ -743,7 +747,7 @@ public class GameManagerServiceTests {
     * Override device configs for both battery and performance modes exists and are valid.
     * Override device configs for both battery and performance modes exists and are valid.
     */
     */
    @Test
    @Test
    public void testSetDeviceOverrideConfigAll() {
    public void testSetDeviceConfigOverrideAll() {
        mockDeviceConfigAll();
        mockDeviceConfigAll();
        mockModifyGameModeGranted();
        mockModifyGameModeGranted();


@@ -763,6 +767,75 @@ public class GameManagerServiceTests {
        checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 60);
        checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 60);
    }
    }


    @Test
    public void testSetBatteryModeConfigOverride_thenUpdateAllDeviceConfig() throws Exception {
        mockModifyGameModeGranted();
        String configStringBefore =
                "mode=2,downscaleFactor=1.0,fps=90:mode=3,downscaleFactor=0.1,fps=30";
        when(DeviceConfig.getProperty(anyString(), anyString()))
                .thenReturn(configStringBefore);
        mockInterventionsEnabledNoOptInFromXml();
        GameManagerService gameManagerService = new GameManagerService(mMockContext,
                mTestLooper.getLooper());
        startUser(gameManagerService, USER_ID_1);

        checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, "1.0");
        checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90);
        checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.1");
        checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 30);

        gameManagerService.setGameModeConfigOverride(mPackageName, USER_ID_1, 3, "40",
                "0.2");

        checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 40);
        checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.2");

        String configStringAfter =
                "mode=2,downscaleFactor=0.9,fps=60:mode=3,downscaleFactor=0.3,fps=50";
        when(DeviceConfig.getProperty(anyString(), anyString()))
                .thenReturn(configStringAfter);
        gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName);

        // performance mode was not overridden thus it should be updated
        checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, "0.9");
        checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 60);

        // battery mode was overridden thus it should be the same as the override
        checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.2");
        checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 40);
    }

    @Test
    public void testSetBatteryModeConfigOverride_thenOptInBatteryMode() throws Exception {
        mockModifyGameModeGranted();
        String configStringBefore =
                "mode=2,downscaleFactor=1.0,fps=90:mode=3,downscaleFactor=0.1,fps=30";
        when(DeviceConfig.getProperty(anyString(), anyString()))
                .thenReturn(configStringBefore);
        mockInterventionsDisabledNoOptInFromXml();
        GameManagerService gameManagerService = new GameManagerService(mMockContext,
                mTestLooper.getLooper());
        startUser(gameManagerService, USER_ID_1);

        assertFalse(checkOptedIn(gameManagerService, GameManager.GAME_MODE_PERFORMANCE));
        assertFalse(checkOptedIn(gameManagerService, GameManager.GAME_MODE_BATTERY));
        checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0);

        gameManagerService.setGameModeConfigOverride(mPackageName, USER_ID_1, 3, "40",
                "0.2");
        checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0);
        // override will enable the interventions
        checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.2");
        checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 40);

        mockInterventionsDisabledAllOptInFromXml();
        gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName);

        assertTrue(checkOptedIn(gameManagerService, GameManager.GAME_MODE_PERFORMANCE));
        // opt-in is still false for battery mode as override exists
        assertFalse(checkOptedIn(gameManagerService, GameManager.GAME_MODE_BATTERY));
    }

    /**
    /**
     * Override device config for performance mode exists and is valid.
     * Override device config for performance mode exists and is valid.
     */
     */
@@ -1037,7 +1110,7 @@ public class GameManagerServiceTests {
        gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
        gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
        assertEquals(GameManager.GAME_MODE_PERFORMANCE,
        assertEquals(GameManager.GAME_MODE_PERFORMANCE,
                gameManagerService.getGameMode(mPackageName, USER_ID_1));
                gameManagerService.getGameMode(mPackageName, USER_ID_1));
        mockInterventionsEnabledFromXml();
        mockInterventionsEnabledNoOptInFromXml();
        checkLoadingBoost(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0);
        checkLoadingBoost(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0);
    }
    }


@@ -1045,7 +1118,7 @@ public class GameManagerServiceTests {
    public void testGameModeConfigAllowFpsTrue() throws Exception {
    public void testGameModeConfigAllowFpsTrue() throws Exception {
        mockDeviceConfigAll();
        mockDeviceConfigAll();
        mockModifyGameModeGranted();
        mockModifyGameModeGranted();
        mockInterventionsEnabledFromXml();
        mockInterventionsEnabledNoOptInFromXml();
        GameManagerService gameManagerService = new GameManagerService(mMockContext,
        GameManagerService gameManagerService = new GameManagerService(mMockContext,
                mTestLooper.getLooper());
                mTestLooper.getLooper());
        startUser(gameManagerService, USER_ID_1);
        startUser(gameManagerService, USER_ID_1);
@@ -1060,7 +1133,7 @@ public class GameManagerServiceTests {
    public void testGameModeConfigAllowFpsFalse() throws Exception {
    public void testGameModeConfigAllowFpsFalse() throws Exception {
        mockDeviceConfigAll();
        mockDeviceConfigAll();
        mockModifyGameModeGranted();
        mockModifyGameModeGranted();
        mockInterventionsDisabledFromXml();
        mockInterventionsDisabledNoOptInFromXml();
        GameManagerService gameManagerService = new GameManagerService(mMockContext,
        GameManagerService gameManagerService = new GameManagerService(mMockContext,
                mTestLooper.getLooper());
                mTestLooper.getLooper());
        startUser(gameManagerService, USER_ID_1);
        startUser(gameManagerService, USER_ID_1);