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

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

Merge "Add device config tests to GameManagerServiceTests" into sc-dev

parents 05f4f582 b0385b39
Loading
Loading
Loading
Loading
+10 −27
Original line number Diff line number Diff line
@@ -199,13 +199,12 @@ public final class GameManagerService extends IGameManagerService.Stub {
        @Override
        public void onPropertiesChanged(Properties properties) {
            synchronized (mDeviceConfigLock) {
                for (String key : properties.getKeyset()) {
                for (final String packageName : properties.getKeyset()) {
                    try {
                        // Check if the package is installed before caching it.
                        final String packageName = keyToPackageName(key);
                        mPackageManager.getPackageInfo(packageName, 0);
                        final GamePackageConfiguration config =
                                GamePackageConfiguration.fromProperties(key, properties);
                                GamePackageConfiguration.fromProperties(packageName, properties);
                        if (config.isValid()) {
                            putConfig(config);
                        } else {
@@ -290,8 +289,8 @@ public final class GameManagerService extends IGameManagerService.Stub {
        private final String mPackageName;
        private final ArrayMap<Integer, GameModeConfiguration> mModeConfigs;

        private GamePackageConfiguration(String keyName) {
            mPackageName = keyToPackageName(keyName);
        private GamePackageConfiguration(String packageName) {
            mPackageName = packageName;
            mModeConfigs = new ArrayMap<>();
        }

@@ -563,9 +562,9 @@ public final class GameManagerService extends IGameManagerService.Stub {
        }
    }

    private void loadDeviceConfigLocked() {
    void loadDeviceConfigLocked() {
        final List<PackageInfo> packages = mPackageManager.getInstalledPackages(0);
        final String[] packageNames = packages.stream().map(e -> packageNameToKey(e.packageName))
        final String[] packageNames = packages.stream().map(e -> e.packageName)
                .toArray(String[]::new);
        synchronized (mDeviceConfigLock) {
            final Properties properties = DeviceConfig.getProperties(
@@ -680,8 +679,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
                        case ACTION_PACKAGE_CHANGED:
                            synchronized (mDeviceConfigLock) {
                                Properties properties = DeviceConfig.getProperties(
                                        DeviceConfig.NAMESPACE_GAME_OVERLAY,
                                        packageNameToKey(packageName));
                                        DeviceConfig.NAMESPACE_GAME_OVERLAY, packageName);
                                for (String key : properties.getKeyset()) {
                                    GamePackageConfiguration config =
                                            GamePackageConfiguration.fromProperties(key,
@@ -692,7 +690,9 @@ public final class GameManagerService extends IGameManagerService.Stub {
                            break;
                        case ACTION_PACKAGE_REMOVED:
                            disableCompatScale(packageName);
                            synchronized (mDeviceConfigLock) {
                                mConfigs.remove(packageName);
                            }
                            break;
                        default:
                            // do nothing
@@ -710,23 +710,6 @@ public final class GameManagerService extends IGameManagerService.Stub {
        mDeviceConfigListener = new DeviceConfigListener();
    }

    /**
     * Valid package name characters are [a-zA-Z0-9_] with a '.' delimiter. Policy keys can only use
     * [a-zA-Z0-9_] so we must handle periods. We do this by appending a '_' to any existing
     * sequence of '_', then we replace all '.' chars with '_';
     */
    private static String packageNameToKey(String name) {
        return name.replaceAll("(_+)", "_$1").replaceAll("\\.", "_");
    }

    /**
     * Replace the last '_' in a sequence with '.' (this can be one or more chars), then replace the
     * resulting special case '_.' with just '_' to get the original package name.
     */
    private static String keyToPackageName(String key) {
        return key.replaceAll("(_)(?!\\1)", ".").replaceAll("_\\.", "_");
    }

    private String dumpDeviceConfigs() {
        StringBuilder out = new StringBuilder();
        for (String key : mConfigs.keySet()) {
+2 −0
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@
    <uses-permission android:name="android.permission.MANAGE_APPOPS"/>
    <uses-permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"/>
    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"/>
    <uses-permission
        android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>

    <!-- needed by MasterClearReceiverTest to display a system dialog -->
    <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
+229 −12
Original line number Diff line number Diff line
@@ -16,51 +16,66 @@

package com.android.server.app;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;

import android.Manifest;
import android.app.GameManager;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.Supplier;

@RunWith(AndroidJUnit4.class)
@SmallTest
@Presubmit
public class GameManagerServiceTests {

    @Mock MockContext mMockContext;
    private static final String TAG = "GameServiceTests";
    private static final String PACKAGE_NAME_INVALID = "com.android.app";
    private static final int USER_ID_1 = 1001;
    private static final int USER_ID_2 = 1002;

    private MockitoSession mMockingSession;
    private String mPackageName;
    @Mock
    private PackageManager mMockPackageManager;

    // Stolen from ConnectivityServiceTest.MockContext
    static class MockContext extends ContextWrapper {
    class MockContext extends ContextWrapper {
        private static final String TAG = "MockContext";

        // Map of permission name -> PermissionManager.Permission_{GRANTED|DENIED} constant
        private final HashMap<String, Integer> mMockedPermissions = new HashMap<>();

        @Mock
        private final MockPackageManager mMockPackageManager;

        MockContext(Context base) {
            super(base);
            mMockPackageManager = new MockPackageManager();
        }

        /**
@@ -112,15 +127,31 @@ public class GameManagerServiceTests {
        }
    }

    @Mock
    private MockContext mMockContext;

    private String mPackageName;

    @Before
    public void setUp() throws Exception {
        mMockingSession = mockitoSession()
                .initMocks(this)
                .mockStatic(DeviceConfig.class)
                .strictness(Strictness.WARN)
                .startMocking();
        mMockContext = new MockContext(InstrumentationRegistry.getContext());
        mPackageName = mMockContext.getPackageName();
        final ApplicationInfo applicationInfo = new ApplicationInfo();
        applicationInfo.category = ApplicationInfo.CATEGORY_GAME;
        final PackageInfo pi = new PackageInfo();
        pi.packageName = mPackageName;
        final List<PackageInfo> packages = new ArrayList<>();
        packages.add(pi);
        when(mMockPackageManager.getInstalledPackages(anyInt())).thenReturn(packages);
        when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
                .thenReturn(applicationInfo);
    }

    @After
    public void tearDown() throws Exception {
        if (mMockingSession != null) {
            mMockingSession.finishMocking();
        }
    }

    private void mockModifyGameModeGranted() {
@@ -133,6 +164,60 @@ public class GameManagerServiceTests {
                PackageManager.PERMISSION_DENIED);
    }

    private void mockDeviceConfigDefault() {
        DeviceConfig.Properties properties = new DeviceConfig.Properties.Builder(
                DeviceConfig.NAMESPACE_GAME_OVERLAY).setString(mPackageName, "").build();
        when(DeviceConfig.getProperties(anyString(), anyString()))
                .thenReturn(properties);
    }

    private void mockDeviceConfigNone() {
        DeviceConfig.Properties properties = new DeviceConfig.Properties.Builder(
                DeviceConfig.NAMESPACE_GAME_OVERLAY).build();
        when(DeviceConfig.getProperties(anyString(), anyString()))
                .thenReturn(properties);
    }

    private void mockDeviceConfigPerformance() {
        String configString = "mode=2,downscaleFactor=0.5";
        DeviceConfig.Properties properties = new DeviceConfig.Properties.Builder(
                DeviceConfig.NAMESPACE_GAME_OVERLAY).setString(mPackageName, configString).build();
        when(DeviceConfig.getProperties(anyString(), anyString()))
                .thenReturn(properties);
    }

    private void mockDeviceConfigBattery() {
        String configString = "mode=3,downscaleFactor=0.7";
        DeviceConfig.Properties properties = new DeviceConfig.Properties.Builder(
                DeviceConfig.NAMESPACE_GAME_OVERLAY).setString(mPackageName, configString).build();
        when(DeviceConfig.getProperties(anyString(), anyString()))
                .thenReturn(properties);
    }

    private void mockDeviceConfigAll() {
        String configString = "mode=3,downscaleFactor=0.7:mode=2,downscaleFactor=0.5";
        DeviceConfig.Properties properties = new DeviceConfig.Properties.Builder(
                DeviceConfig.NAMESPACE_GAME_OVERLAY).setString(mPackageName, configString).build();
        when(DeviceConfig.getProperties(anyString(), anyString()))
                .thenReturn(properties);
    }

    private void mockDeviceConfigInvalid() {
        String configString = "mode=2,downscaleFactor=0.55";
        DeviceConfig.Properties properties = new DeviceConfig.Properties.Builder(
                DeviceConfig.NAMESPACE_GAME_OVERLAY).setString(mPackageName, configString).build();
        when(DeviceConfig.getProperties(anyString(), anyString()))
                .thenReturn(properties);
    }

    private void mockDeviceConfigMalformed() {
        String configString = "adsljckv=nin3rn9hn1231245:8795tq=21ewuydg";
        DeviceConfig.Properties properties = new DeviceConfig.Properties.Builder(
                DeviceConfig.NAMESPACE_GAME_OVERLAY).setString(mPackageName, configString).build();
        when(DeviceConfig.getProperties(anyString(), anyString()))
                .thenReturn(properties);
    }

    /**
     * By default game mode is not supported.
     */
@@ -190,7 +275,6 @@ public class GameManagerServiceTests {
    public void testGetGameModeInvalidPackageName() {
        GameManagerService gameManagerService = new GameManagerService(mMockContext);
        gameManagerService.onUserStarting(USER_ID_1);

        try {
            assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
                    gameManagerService.getGameMode(PACKAGE_NAME_INVALID,
@@ -268,4 +352,137 @@ public class GameManagerServiceTests {
        assertEquals(GameManager.GAME_MODE_PERFORMANCE,
                gameManagerService.getGameMode(mPackageName, USER_ID_2));
    }

    /**
     * Phonesky device config exists, but is only propagating the default value.
     */
    @Test
    public void testDeviceConfigDefault() {
        mockDeviceConfigDefault();
        mockModifyGameModeGranted();
        GameManagerService gameManagerService = new GameManagerService(mMockContext);
        gameManagerService.onUserStarting(USER_ID_1);
        gameManagerService.loadDeviceConfigLocked();

        int[] modes = gameManagerService.getAvailableGameModes(mPackageName);
        assertEquals(modes.length, 1);
        assertEquals(modes[0], GameManager.GAME_MODE_UNSUPPORTED);
    }

    /**
     * Phonesky device config does not exists.
     */
    @Test
    public void testDeviceConfigNone() {
        mockDeviceConfigNone();
        mockModifyGameModeGranted();
        GameManagerService gameManagerService = new GameManagerService(mMockContext);
        gameManagerService.onUserStarting(USER_ID_1);
        gameManagerService.loadDeviceConfigLocked();

        int[] modes = gameManagerService.getAvailableGameModes(mPackageName);
        assertEquals(modes.length, 1);
        assertEquals(modes[0], GameManager.GAME_MODE_UNSUPPORTED);
    }

    /**
     * Phonesky device config for performance mode exists and is valid.
     */
    @Test
    public void testDeviceConfigPerformance() {
        mockDeviceConfigPerformance();
        mockModifyGameModeGranted();
        GameManagerService gameManagerService = new GameManagerService(mMockContext);
        gameManagerService.onUserStarting(USER_ID_1);
        gameManagerService.loadDeviceConfigLocked();

        boolean perfModeExists = false;
        int[] modes = gameManagerService.getAvailableGameModes(mPackageName);
        for (int mode : modes) {
            if (mode == GameManager.GAME_MODE_PERFORMANCE) {
                perfModeExists = true;
            }
        }
        assertEquals(modes.length, 1);
        assertTrue(perfModeExists);
    }

    /**
     * Phonesky device config for battery mode exists and is valid.
     */
    @Test
    public void testDeviceConfigBattery() {
        mockDeviceConfigBattery();
        mockModifyGameModeGranted();
        GameManagerService gameManagerService = new GameManagerService(mMockContext);
        gameManagerService.onUserStarting(USER_ID_1);
        gameManagerService.loadDeviceConfigLocked();

        boolean batteryModeExists = false;
        int[] modes = gameManagerService.getAvailableGameModes(mPackageName);
        for (int mode : modes) {
            if (mode == GameManager.GAME_MODE_BATTERY) {
                batteryModeExists = true;
            }
        }
        assertEquals(modes.length, 1);
        assertTrue(batteryModeExists);
    }

    /**
     * Phonesky device configs for both battery and performance modes exists and are valid.
     */
    @Test
    public void testDeviceConfigAll() {
        mockDeviceConfigAll();
        mockModifyGameModeGranted();
        GameManagerService gameManagerService = new GameManagerService(mMockContext);
        gameManagerService.onUserStarting(USER_ID_1);
        gameManagerService.loadDeviceConfigLocked();

        boolean batteryModeExists = false;
        boolean perfModeExists = false;
        int[] modes = gameManagerService.getAvailableGameModes(mPackageName);
        for (int mode : modes) {
            if (mode == GameManager.GAME_MODE_BATTERY) {
                batteryModeExists = true;
            } else if (mode == GameManager.GAME_MODE_PERFORMANCE) {
                perfModeExists = true;
            }
        }
        assertTrue(batteryModeExists);
        assertTrue(perfModeExists);
    }

    /**
     * Phonesky device config contains values that parse correctly but are not valid in game mode.
     */
    @Test
    public void testDeviceConfigInvalid() {
        mockDeviceConfigInvalid();
        mockModifyGameModeGranted();
        GameManagerService gameManagerService = new GameManagerService(mMockContext);
        gameManagerService.onUserStarting(USER_ID_1);
        gameManagerService.loadDeviceConfigLocked();

        int[] modes = gameManagerService.getAvailableGameModes(mPackageName);
        assertEquals(modes.length, 1);
        assertEquals(modes[0], GameManager.GAME_MODE_UNSUPPORTED);
    }

    /**
     * Phonesky device config is garbage.
     */
    @Test
    public void testDeviceConfigMalformed() {
        mockDeviceConfigMalformed();
        mockModifyGameModeGranted();
        GameManagerService gameManagerService = new GameManagerService(mMockContext);
        gameManagerService.onUserStarting(USER_ID_1);
        gameManagerService.loadDeviceConfigLocked();

        int[] modes = gameManagerService.getAvailableGameModes(mPackageName);
        assertEquals(modes.length, 1);
        assertEquals(modes[0], GameManager.GAME_MODE_UNSUPPORTED);
    }
}