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

This commit is contained in:
TreeHugger Robot
2021-04-15 20:20:29 +00:00
committed by Android (Google) Code Review
3 changed files with 241 additions and 39 deletions

View File

@@ -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);
mConfigs.remove(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()) {

View File

@@ -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"/>

View File

@@ -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);
}
}