Merge "Add writing function to intervention list" into tm-qpr-dev
This commit is contained in:
@@ -60,6 +60,7 @@ import android.content.pm.ApplicationInfo;
|
|||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
|
import android.content.pm.UserInfo;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.content.res.XmlResourceParser;
|
import android.content.res.XmlResourceParser;
|
||||||
@@ -68,6 +69,7 @@ import android.net.Uri;
|
|||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
import android.os.FileUtils;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
@@ -77,9 +79,12 @@ import android.os.RemoteException;
|
|||||||
import android.os.ResultReceiver;
|
import android.os.ResultReceiver;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
import android.os.ShellCallback;
|
import android.os.ShellCallback;
|
||||||
|
import android.os.UserManager;
|
||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
import android.provider.DeviceConfig.Properties;
|
import android.provider.DeviceConfig.Properties;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
|
import android.util.AtomicFile;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.KeyValueListParser;
|
import android.util.KeyValueListParser;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
@@ -90,6 +95,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
|||||||
import com.android.internal.compat.CompatibilityOverrideConfig;
|
import com.android.internal.compat.CompatibilityOverrideConfig;
|
||||||
import com.android.internal.compat.IPlatformCompat;
|
import com.android.internal.compat.IPlatformCompat;
|
||||||
import com.android.internal.os.BackgroundThread;
|
import com.android.internal.os.BackgroundThread;
|
||||||
|
import com.android.internal.util.ArrayUtils;
|
||||||
import com.android.internal.util.FrameworkStatsLog;
|
import com.android.internal.util.FrameworkStatsLog;
|
||||||
import com.android.server.LocalServices;
|
import com.android.server.LocalServices;
|
||||||
import com.android.server.ServiceThread;
|
import com.android.server.ServiceThread;
|
||||||
@@ -99,9 +105,17 @@ import com.android.server.SystemService.TargetUser;
|
|||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,6 +136,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
|
|||||||
static final int POPULATE_GAME_MODE_SETTINGS = 3;
|
static final int POPULATE_GAME_MODE_SETTINGS = 3;
|
||||||
static final int SET_GAME_STATE = 4;
|
static final int SET_GAME_STATE = 4;
|
||||||
static final int CANCEL_GAME_LOADING_MODE = 5;
|
static final int CANCEL_GAME_LOADING_MODE = 5;
|
||||||
|
static final int WRITE_GAME_MODE_INTERVENTION_LIST_FILE = 6;
|
||||||
static final int WRITE_SETTINGS_DELAY = 10 * 1000; // 10 seconds
|
static final int WRITE_SETTINGS_DELAY = 10 * 1000; // 10 seconds
|
||||||
static final int LOADING_BOOST_MAX_DURATION = 5 * 1000; // 5 seconds
|
static final int LOADING_BOOST_MAX_DURATION = 5 * 1000; // 5 seconds
|
||||||
|
|
||||||
@@ -131,6 +146,8 @@ public final class GameManagerService extends IGameManagerService.Stub {
|
|||||||
.build();
|
.build();
|
||||||
private static final String PACKAGE_NAME_MSG_KEY = "packageName";
|
private static final String PACKAGE_NAME_MSG_KEY = "packageName";
|
||||||
private static final String USER_ID_MSG_KEY = "userId";
|
private static final String USER_ID_MSG_KEY = "userId";
|
||||||
|
private static final String GAME_MODE_INTERVENTION_LIST_FILE_NAME =
|
||||||
|
"game_mode_intervention.list";
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final Object mLock = new Object();
|
private final Object mLock = new Object();
|
||||||
@@ -138,8 +155,12 @@ public final class GameManagerService extends IGameManagerService.Stub {
|
|||||||
private final Object mOverrideConfigLock = new Object();
|
private final Object mOverrideConfigLock = new Object();
|
||||||
private final Handler mHandler;
|
private final Handler mHandler;
|
||||||
private final PackageManager mPackageManager;
|
private final PackageManager mPackageManager;
|
||||||
|
private final UserManager mUserManager;
|
||||||
private final IPlatformCompat mPlatformCompat;
|
private final IPlatformCompat mPlatformCompat;
|
||||||
private final PowerManagerInternal mPowerManagerInternal;
|
private final PowerManagerInternal mPowerManagerInternal;
|
||||||
|
private final File mSystemDir;
|
||||||
|
@VisibleForTesting
|
||||||
|
final AtomicFile mGameModeInterventionListFile;
|
||||||
private DeviceConfigListener mDeviceConfigListener;
|
private DeviceConfigListener mDeviceConfigListener;
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private final ArrayMap<Integer, GameManagerSettings> mSettings = new ArrayMap<>();
|
private final ArrayMap<Integer, GameManagerSettings> mSettings = new ArrayMap<>();
|
||||||
@@ -158,9 +179,53 @@ public final class GameManagerService extends IGameManagerService.Stub {
|
|||||||
mContext = context;
|
mContext = context;
|
||||||
mHandler = new SettingsHandler(looper);
|
mHandler = new SettingsHandler(looper);
|
||||||
mPackageManager = mContext.getPackageManager();
|
mPackageManager = mContext.getPackageManager();
|
||||||
|
mUserManager = mContext.getSystemService(UserManager.class);
|
||||||
mPlatformCompat = IPlatformCompat.Stub.asInterface(
|
mPlatformCompat = IPlatformCompat.Stub.asInterface(
|
||||||
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
|
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
|
||||||
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
|
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
|
||||||
|
mSystemDir = new File(Environment.getDataDirectory(), "system");
|
||||||
|
mSystemDir.mkdirs();
|
||||||
|
FileUtils.setPermissions(mSystemDir.toString(),
|
||||||
|
FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH,
|
||||||
|
-1, -1);
|
||||||
|
mGameModeInterventionListFile = new AtomicFile(new File(mSystemDir,
|
||||||
|
GAME_MODE_INTERVENTION_LIST_FILE_NAME));
|
||||||
|
FileUtils.setPermissions(mGameModeInterventionListFile.getBaseFile().getAbsolutePath(),
|
||||||
|
FileUtils.S_IRUSR | FileUtils.S_IWUSR
|
||||||
|
| FileUtils.S_IRGRP | FileUtils.S_IWGRP,
|
||||||
|
-1, -1);
|
||||||
|
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_GAME_SERVICE)) {
|
||||||
|
mGameServiceController = new GameServiceController(
|
||||||
|
context, BackgroundThread.getExecutor(),
|
||||||
|
new GameServiceProviderSelectorImpl(
|
||||||
|
context.getResources(),
|
||||||
|
context.getPackageManager()),
|
||||||
|
new GameServiceProviderInstanceFactoryImpl(context));
|
||||||
|
} else {
|
||||||
|
mGameServiceController = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
|
||||||
|
GameManagerService(Context context, Looper looper, File dataDir) {
|
||||||
|
mContext = context;
|
||||||
|
mHandler = new SettingsHandler(looper);
|
||||||
|
mPackageManager = mContext.getPackageManager();
|
||||||
|
mUserManager = mContext.getSystemService(UserManager.class);
|
||||||
|
mPlatformCompat = IPlatformCompat.Stub.asInterface(
|
||||||
|
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
|
||||||
|
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
|
||||||
|
mSystemDir = new File(dataDir, "system");
|
||||||
|
mSystemDir.mkdirs();
|
||||||
|
FileUtils.setPermissions(mSystemDir.toString(),
|
||||||
|
FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH,
|
||||||
|
-1, -1);
|
||||||
|
mGameModeInterventionListFile = new AtomicFile(new File(mSystemDir,
|
||||||
|
GAME_MODE_INTERVENTION_LIST_FILE_NAME));
|
||||||
|
FileUtils.setPermissions(mGameModeInterventionListFile.getBaseFile().getAbsolutePath(),
|
||||||
|
FileUtils.S_IRUSR | FileUtils.S_IWUSR
|
||||||
|
| FileUtils.S_IRGRP | FileUtils.S_IWGRP,
|
||||||
|
-1, -1);
|
||||||
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_GAME_SERVICE)) {
|
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_GAME_SERVICE)) {
|
||||||
mGameServiceController = new GameServiceController(
|
mGameServiceController = new GameServiceController(
|
||||||
context, BackgroundThread.getExecutor(),
|
context, BackgroundThread.getExecutor(),
|
||||||
@@ -306,6 +371,22 @@ public final class GameManagerService extends IGameManagerService.Stub {
|
|||||||
mPowerManagerInternal.setPowerMode(Mode.GAME_LOADING, false);
|
mPowerManagerInternal.setPowerMode(Mode.GAME_LOADING, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case WRITE_GAME_MODE_INTERVENTION_LIST_FILE: {
|
||||||
|
final int userId = (int) msg.obj;
|
||||||
|
if (userId < 0) {
|
||||||
|
Slog.wtf(TAG, "Attempt to write setting for invalid user: " + userId);
|
||||||
|
synchronized (mLock) {
|
||||||
|
removeMessages(WRITE_GAME_MODE_INTERVENTION_LIST_FILE, null);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
|
||||||
|
removeMessages(WRITE_GAME_MODE_INTERVENTION_LIST_FILE, null);
|
||||||
|
writeGameModeInterventionsToFile(userId);
|
||||||
|
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -955,6 +1036,11 @@ public final class GameManagerService extends IGameManagerService.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateInterventions(packageName, gameMode, userId);
|
updateInterventions(packageName, gameMode, userId);
|
||||||
|
final Message msg = mHandler.obtainMessage(WRITE_GAME_MODE_INTERVENTION_LIST_FILE);
|
||||||
|
msg.obj = userId;
|
||||||
|
if (!mHandler.hasEqualMessages(WRITE_GAME_MODE_INTERVENTION_LIST_FILE, userId)) {
|
||||||
|
mHandler.sendMessage(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1520,15 +1606,98 @@ public final class GameManagerService extends IGameManagerService.Stub {
|
|||||||
final int newGameMode = getNewGameMode(gameMode, config);
|
final int newGameMode = getNewGameMode(gameMode, config);
|
||||||
if (newGameMode != gameMode) {
|
if (newGameMode != gameMode) {
|
||||||
setGameMode(packageName, newGameMode, userId);
|
setGameMode(packageName, newGameMode, userId);
|
||||||
}
|
} else {
|
||||||
|
// Make sure we handle the case when the interventions are changed while
|
||||||
|
// the game mode remains the same. We call only updateInterventions() here.
|
||||||
updateInterventions(packageName, gameMode, userId);
|
updateInterventions(packageName, gameMode, userId);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Slog.e(TAG, "Failed to update compat modes for user " + userId + ": " + e);
|
Slog.e(TAG, "Failed to update compat modes for user " + userId + ": " + e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final Message msg = mHandler.obtainMessage(WRITE_GAME_MODE_INTERVENTION_LIST_FILE);
|
||||||
|
msg.obj = userId;
|
||||||
|
if (!mHandler.hasEqualMessages(WRITE_GAME_MODE_INTERVENTION_LIST_FILE, userId)) {
|
||||||
|
mHandler.sendMessage(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] getInstalledGamePackageNames(int userId) {
|
/*
|
||||||
|
Write the interventions and mode of each game to file /system/data/game_mode_intervention.list
|
||||||
|
Each line will contain the information of each game, separated by tab.
|
||||||
|
The format of the output is:
|
||||||
|
<package name> <UID> <current mode> <game mode 1> <interventions> <game mode 2> <interventions>
|
||||||
|
For example:
|
||||||
|
com.android.app1 1425 1 2 angle=0,scaling=1.0,fps=60 3 angle=1,scaling=0.5,fps=30
|
||||||
|
*/
|
||||||
|
private void writeGameModeInterventionsToFile(@UserIdInt int userId) {
|
||||||
|
FileOutputStream fileOutputStream = null;
|
||||||
|
BufferedWriter bufferedWriter;
|
||||||
|
try {
|
||||||
|
fileOutputStream = mGameModeInterventionListFile.startWrite();
|
||||||
|
bufferedWriter = new BufferedWriter(new OutputStreamWriter(fileOutputStream,
|
||||||
|
Charset.defaultCharset()));
|
||||||
|
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
final List<String> installedGamesList = getInstalledGamePackageNamesByAllUsers(userId);
|
||||||
|
for (final String packageName : installedGamesList) {
|
||||||
|
GamePackageConfiguration packageConfig = getConfig(packageName);
|
||||||
|
if (packageConfig == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sb.append(packageName);
|
||||||
|
sb.append("\t");
|
||||||
|
sb.append(mPackageManager.getPackageUidAsUser(packageName, userId));
|
||||||
|
sb.append("\t");
|
||||||
|
sb.append(getGameMode(packageName, userId));
|
||||||
|
sb.append("\t");
|
||||||
|
final int[] modes = packageConfig.getAvailableGameModes();
|
||||||
|
for (int mode : modes) {
|
||||||
|
final GamePackageConfiguration.GameModeConfiguration gameModeConfiguration =
|
||||||
|
packageConfig.getGameModeConfiguration(mode);
|
||||||
|
if (gameModeConfiguration == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sb.append(mode);
|
||||||
|
sb.append("\t");
|
||||||
|
final int useAngle = gameModeConfiguration.getUseAngle() ? 1 : 0;
|
||||||
|
sb.append(TextUtils.formatSimple("angle=%d", useAngle));
|
||||||
|
sb.append(",");
|
||||||
|
final String scaling = gameModeConfiguration.getScaling();
|
||||||
|
sb.append("scaling=");
|
||||||
|
sb.append(scaling);
|
||||||
|
sb.append(",");
|
||||||
|
final int fps = gameModeConfiguration.getFps();
|
||||||
|
sb.append(TextUtils.formatSimple("fps=%d", fps));
|
||||||
|
sb.append("\t");
|
||||||
|
}
|
||||||
|
sb.append("\n");
|
||||||
|
}
|
||||||
|
bufferedWriter.append(sb);
|
||||||
|
bufferedWriter.flush();
|
||||||
|
FileUtils.sync(fileOutputStream);
|
||||||
|
mGameModeInterventionListFile.finishWrite(fileOutputStream);
|
||||||
|
} catch (Exception e) {
|
||||||
|
mGameModeInterventionListFile.failWrite(fileOutputStream);
|
||||||
|
Slog.wtf(TAG, "Failed to write game_mode_intervention.list, exception " + e);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] getAllUserIds(@UserIdInt int currentUserId) {
|
||||||
|
final List<UserInfo> users = mUserManager.getUsers();
|
||||||
|
int[] userIds = new int[users.size()];
|
||||||
|
for (int i = 0; i < userIds.length; ++i) {
|
||||||
|
userIds[i] = users.get(i).id;
|
||||||
|
}
|
||||||
|
if (currentUserId != -1) {
|
||||||
|
userIds = ArrayUtils.appendInt(userIds, currentUserId);
|
||||||
|
}
|
||||||
|
return userIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] getInstalledGamePackageNames(@UserIdInt int userId) {
|
||||||
final List<PackageInfo> packages =
|
final List<PackageInfo> packages =
|
||||||
mPackageManager.getInstalledPackagesAsUser(0, userId);
|
mPackageManager.getInstalledPackagesAsUser(0, userId);
|
||||||
return packages.stream().filter(e -> e.applicationInfo != null && e.applicationInfo.category
|
return packages.stream().filter(e -> e.applicationInfo != null && e.applicationInfo.category
|
||||||
@@ -1537,6 +1706,17 @@ public final class GameManagerService extends IGameManagerService.Stub {
|
|||||||
.toArray(String[]::new);
|
.toArray(String[]::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> getInstalledGamePackageNamesByAllUsers(@UserIdInt int currentUserId) {
|
||||||
|
HashSet<String> packageSet = new HashSet<>();
|
||||||
|
|
||||||
|
final int[] userIds = getAllUserIds(currentUserId);
|
||||||
|
for (int userId : userIds) {
|
||||||
|
packageSet.addAll(Arrays.asList(getInstalledGamePackageNames(userId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ArrayList<>(packageSet);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -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.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;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@@ -49,6 +50,7 @@ import android.content.res.XmlResourceParser;
|
|||||||
import android.hardware.power.Mode;
|
import android.hardware.power.Mode;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.PowerManagerInternal;
|
import android.os.PowerManagerInternal;
|
||||||
|
import android.os.UserManager;
|
||||||
import android.os.test.TestLooper;
|
import android.os.test.TestLooper;
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
@@ -69,6 +71,8 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.MockitoSession;
|
import org.mockito.MockitoSession;
|
||||||
import org.mockito.quality.Strictness;
|
import org.mockito.quality.Strictness;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -79,7 +83,7 @@ import java.util.function.Supplier;
|
|||||||
@Presubmit
|
@Presubmit
|
||||||
public class GameManagerServiceTests {
|
public class GameManagerServiceTests {
|
||||||
@Mock MockContext mMockContext;
|
@Mock MockContext mMockContext;
|
||||||
private static final String TAG = "GameServiceTests";
|
private static final String TAG = "GameManagerServiceTests";
|
||||||
private static final String PACKAGE_NAME_INVALID = "com.android.app";
|
private static final String PACKAGE_NAME_INVALID = "com.android.app";
|
||||||
private static final int USER_ID_1 = 1001;
|
private static final int USER_ID_1 = 1001;
|
||||||
private static final int USER_ID_2 = 1002;
|
private static final int USER_ID_2 = 1002;
|
||||||
@@ -91,6 +95,8 @@ public class GameManagerServiceTests {
|
|||||||
private PackageManager mMockPackageManager;
|
private PackageManager mMockPackageManager;
|
||||||
@Mock
|
@Mock
|
||||||
private PowerManagerInternal mMockPowerManager;
|
private PowerManagerInternal mMockPowerManager;
|
||||||
|
@Mock
|
||||||
|
private UserManager mMockUserManager;
|
||||||
|
|
||||||
// Stolen from ConnectivityServiceTest.MockContext
|
// Stolen from ConnectivityServiceTest.MockContext
|
||||||
class MockContext extends ContextWrapper {
|
class MockContext extends ContextWrapper {
|
||||||
@@ -150,6 +156,15 @@ public class GameManagerServiceTests {
|
|||||||
public PackageManager getPackageManager() {
|
public PackageManager getPackageManager() {
|
||||||
return mMockPackageManager;
|
return mMockPackageManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getSystemService(String name) {
|
||||||
|
switch (name) {
|
||||||
|
case Context.USER_SERVICE:
|
||||||
|
return mMockUserManager;
|
||||||
|
}
|
||||||
|
throw new UnsupportedOperationException("Couldn't find system service: " + name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -198,6 +213,19 @@ public class GameManagerServiceTests {
|
|||||||
mTestLooper.dispatchAll();
|
mTestLooper.dispatchAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void switchUser(GameManagerService gameManagerService, int from, int to) {
|
||||||
|
UserInfo userInfoFrom = new UserInfo(from, "name", 0);
|
||||||
|
UserInfo userInfoTo = new UserInfo(to, "name", 0);
|
||||||
|
gameManagerService.onUserSwitching(/* from */ new SystemService.TargetUser(userInfoFrom),
|
||||||
|
/* to */ new SystemService.TargetUser(userInfoTo));
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mockManageUsersGranted() {
|
||||||
|
mMockContext.setPermission(Manifest.permission.MANAGE_USERS,
|
||||||
|
PackageManager.PERMISSION_GRANTED);
|
||||||
|
}
|
||||||
|
|
||||||
private void mockModifyGameModeGranted() {
|
private void mockModifyGameModeGranted() {
|
||||||
mMockContext.setPermission(Manifest.permission.MANAGE_GAME_MODE,
|
mMockContext.setPermission(Manifest.permission.MANAGE_GAME_MODE,
|
||||||
PackageManager.PERMISSION_GRANTED);
|
PackageManager.PERMISSION_GRANTED);
|
||||||
@@ -819,6 +847,7 @@ public class GameManagerServiceTests {
|
|||||||
GameManagerService gameManagerService = new GameManagerService(
|
GameManagerService gameManagerService = new GameManagerService(
|
||||||
mMockContext, mTestLooper.getLooper());
|
mMockContext, mTestLooper.getLooper());
|
||||||
startUser(gameManagerService, USER_ID_1);
|
startUser(gameManagerService, USER_ID_1);
|
||||||
|
|
||||||
gameManagerService.setGameModeConfigOverride(mPackageName, USER_ID_1,
|
gameManagerService.setGameModeConfigOverride(mPackageName, USER_ID_1,
|
||||||
GameManager.GAME_MODE_PERFORMANCE, "120", "0.3");
|
GameManager.GAME_MODE_PERFORMANCE, "120", "0.3");
|
||||||
gameManagerService.setGameModeConfigOverride(mPackageName, USER_ID_1,
|
gameManagerService.setGameModeConfigOverride(mPackageName, USER_ID_1,
|
||||||
@@ -1246,4 +1275,133 @@ public class GameManagerServiceTests {
|
|||||||
public void testSetGameStateNotLoading() {
|
public void testSetGameStateNotLoading() {
|
||||||
setGameState(false);
|
setGameState(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> readGameModeInterventionList() throws Exception {
|
||||||
|
final File interventionFile = new File(InstrumentationRegistry.getContext().getFilesDir(),
|
||||||
|
"system/game_mode_intervention.list");
|
||||||
|
assertNotNull(interventionFile);
|
||||||
|
List<String> output = Files.readAllLines(interventionFile.toPath());
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mockInterventionListForMultipleUsers() {
|
||||||
|
final String[] packageNames = new String[] {"com.android.app0",
|
||||||
|
"com.android.app1", "com.android.app2"};
|
||||||
|
|
||||||
|
final ApplicationInfo[] applicationInfos = new ApplicationInfo[3];
|
||||||
|
final PackageInfo[] pis = new PackageInfo[3];
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
applicationInfos[i] = new ApplicationInfo();
|
||||||
|
applicationInfos[i].category = ApplicationInfo.CATEGORY_GAME;
|
||||||
|
applicationInfos[i].packageName = packageNames[i];
|
||||||
|
|
||||||
|
pis[i] = new PackageInfo();
|
||||||
|
pis[i].packageName = packageNames[i];
|
||||||
|
pis[i].applicationInfo = applicationInfos[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<PackageInfo> userOnePackages = new ArrayList<>();
|
||||||
|
final List<PackageInfo> userTwoPackages = new ArrayList<>();
|
||||||
|
userOnePackages.add(pis[1]);
|
||||||
|
userTwoPackages.add(pis[0]);
|
||||||
|
userTwoPackages.add(pis[2]);
|
||||||
|
|
||||||
|
final List<UserInfo> userInfos = new ArrayList<>(2);
|
||||||
|
userInfos.add(new UserInfo());
|
||||||
|
userInfos.add(new UserInfo());
|
||||||
|
userInfos.get(0).id = USER_ID_1;
|
||||||
|
userInfos.get(1).id = USER_ID_2;
|
||||||
|
|
||||||
|
when(mMockPackageManager.getInstalledPackagesAsUser(anyInt(), eq(USER_ID_1)))
|
||||||
|
.thenReturn(userOnePackages);
|
||||||
|
when(mMockPackageManager.getInstalledPackagesAsUser(anyInt(), eq(USER_ID_2)))
|
||||||
|
.thenReturn(userTwoPackages);
|
||||||
|
when(mMockUserManager.getUsers()).thenReturn(userInfos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVerifyInterventionList() throws Exception {
|
||||||
|
mockDeviceConfigAll();
|
||||||
|
mockInterventionListForMultipleUsers();
|
||||||
|
mockManageUsersGranted();
|
||||||
|
mockModifyGameModeGranted();
|
||||||
|
final Context context = InstrumentationRegistry.getContext();
|
||||||
|
GameManagerService gameManagerService =
|
||||||
|
new GameManagerService(mMockContext,
|
||||||
|
mTestLooper.getLooper(),
|
||||||
|
context.getFilesDir());
|
||||||
|
startUser(gameManagerService, USER_ID_1);
|
||||||
|
startUser(gameManagerService, USER_ID_2);
|
||||||
|
|
||||||
|
gameManagerService.setGameModeConfigOverride("com.android.app0", USER_ID_2,
|
||||||
|
GameManager.GAME_MODE_PERFORMANCE, "120", "0.6");
|
||||||
|
gameManagerService.setGameModeConfigOverride("com.android.app2", USER_ID_2,
|
||||||
|
GameManager.GAME_MODE_BATTERY, "60", "0.5");
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
|
||||||
|
/* Expected fileOutput (order may vary)
|
||||||
|
com.android.app2 <UID> 0 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.5,fps=60
|
||||||
|
com.android.app1 <UID> 1 2 angle=0,scaling=0.5,fps=90 3 angle=0,scaling=0.7,fps=30
|
||||||
|
com.android.app0 <UID> 0 2 angle=0,scaling=0.6,fps=120 3 angle=0,scaling=0.7,fps=30
|
||||||
|
|
||||||
|
The current game mode would only be set to non-zero if the current user have that game
|
||||||
|
installed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
List<String> fileOutput = readGameModeInterventionList();
|
||||||
|
assertEquals(fileOutput.size(), 3);
|
||||||
|
|
||||||
|
String[] splitLine = fileOutput.get(0).split("\\s+");
|
||||||
|
assertEquals(splitLine[0], "com.android.app2");
|
||||||
|
assertEquals(splitLine[2], "3");
|
||||||
|
assertEquals(splitLine[3], "2");
|
||||||
|
assertEquals(splitLine[4], "angle=0,scaling=0.5,fps=90");
|
||||||
|
assertEquals(splitLine[5], "3");
|
||||||
|
assertEquals(splitLine[6], "angle=0,scaling=0.5,fps=60");
|
||||||
|
splitLine = fileOutput.get(1).split("\\s+");
|
||||||
|
assertEquals(splitLine[0], "com.android.app1");
|
||||||
|
assertEquals(splitLine[2], "0");
|
||||||
|
assertEquals(splitLine[3], "2");
|
||||||
|
assertEquals(splitLine[4], "angle=0,scaling=0.5,fps=90");
|
||||||
|
assertEquals(splitLine[5], "3");
|
||||||
|
assertEquals(splitLine[6], "angle=0,scaling=0.7,fps=30");
|
||||||
|
splitLine = fileOutput.get(2).split("\\s+");
|
||||||
|
assertEquals(splitLine[0], "com.android.app0");
|
||||||
|
assertEquals(splitLine[2], "2");
|
||||||
|
assertEquals(splitLine[3], "2");
|
||||||
|
assertEquals(splitLine[4], "angle=0,scaling=0.6,fps=120");
|
||||||
|
assertEquals(splitLine[5], "3");
|
||||||
|
assertEquals(splitLine[6], "angle=0,scaling=0.7,fps=30");
|
||||||
|
|
||||||
|
switchUser(gameManagerService, USER_ID_2, USER_ID_1);
|
||||||
|
gameManagerService.setGameMode("com.android.app1",
|
||||||
|
GameManager.GAME_MODE_BATTERY, USER_ID_1);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
|
||||||
|
fileOutput = readGameModeInterventionList();
|
||||||
|
assertEquals(fileOutput.size(), 3);
|
||||||
|
|
||||||
|
splitLine = fileOutput.get(0).split("\\s+");
|
||||||
|
assertEquals(splitLine[0], "com.android.app2");
|
||||||
|
assertEquals(splitLine[2], "0");
|
||||||
|
assertEquals(splitLine[3], "2");
|
||||||
|
assertEquals(splitLine[4], "angle=0,scaling=0.5,fps=90");
|
||||||
|
assertEquals(splitLine[5], "3");
|
||||||
|
assertEquals(splitLine[6], "angle=0,scaling=0.5,fps=60");
|
||||||
|
splitLine = fileOutput.get(1).split("\\s+");
|
||||||
|
assertEquals(splitLine[0], "com.android.app1");
|
||||||
|
assertEquals(splitLine[2], "3");
|
||||||
|
assertEquals(splitLine[3], "2");
|
||||||
|
assertEquals(splitLine[4], "angle=0,scaling=0.5,fps=90");
|
||||||
|
assertEquals(splitLine[5], "3");
|
||||||
|
assertEquals(splitLine[6], "angle=0,scaling=0.7,fps=30");
|
||||||
|
splitLine = fileOutput.get(2).split("\\s+");
|
||||||
|
assertEquals(splitLine[0], "com.android.app0");
|
||||||
|
assertEquals(splitLine[2], "0");
|
||||||
|
assertEquals(splitLine[3], "2");
|
||||||
|
assertEquals(splitLine[4], "angle=0,scaling=0.6,fps=120");
|
||||||
|
assertEquals(splitLine[5], "3");
|
||||||
|
assertEquals(splitLine[6], "angle=0,scaling=0.7,fps=30");
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user