Merge "GameManagerService: Restrict get/set Game Mode to Games" into sc-dev

This commit is contained in:
Tim Van Patten
2021-03-23 19:33:07 +00:00
committed by Android (Google) Code Review
5 changed files with 1193 additions and 21 deletions

View File

@@ -19,7 +19,7 @@
package="com.android.app.gamemanagertests"
android:sharedUserId="android.uid.system" >
<application>
<application android:appCategory="game">
<uses-library android:name="android.test.runner" />
</application>

View File

@@ -37,9 +37,6 @@ import org.junit.runner.RunWith;
@SmallTest
@Presubmit
public final class GameManagerTests {
private static final String PACKAGE_NAME_0 = "com.android.app0";
private static final String PACKAGE_NAME_1 = "com.android.app1";
protected Context mContext;
private GameManager mGameManager;
private String mPackageName;
@@ -52,8 +49,6 @@ public final class GameManagerTests {
// Reset the Game Mode for the test app, since it persists across invocations.
mGameManager.setGameMode(mPackageName, GameManager.GAME_MODE_UNSUPPORTED);
mGameManager.setGameMode(PACKAGE_NAME_0, GameManager.GAME_MODE_UNSUPPORTED);
mGameManager.setGameMode(PACKAGE_NAME_1, GameManager.GAME_MODE_UNSUPPORTED);
}
@Test
@@ -73,14 +68,14 @@ public final class GameManagerTests {
@Test
public void testPrivilegedGameModeGetterSetter() {
assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
mGameManager.getGameMode(PACKAGE_NAME_0));
mGameManager.getGameMode(mPackageName));
mGameManager.setGameMode(PACKAGE_NAME_1, GameManager.GAME_MODE_STANDARD);
mGameManager.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD);
assertEquals(GameManager.GAME_MODE_STANDARD,
mGameManager.getGameMode(PACKAGE_NAME_1));
mGameManager.getGameMode(mPackageName));
mGameManager.setGameMode(PACKAGE_NAME_1, GameManager.GAME_MODE_PERFORMANCE);
mGameManager.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE);
assertEquals(GameManager.GAME_MODE_PERFORMANCE,
mGameManager.getGameMode(PACKAGE_NAME_1));
mGameManager.getGameMode(mPackageName));
}
}

View File

@@ -24,6 +24,7 @@ import android.app.GameManager;
import android.app.GameManager.GameMode;
import android.app.IGameManagerService;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Environment;
@@ -58,6 +59,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
static final int WRITE_SETTINGS_DELAY = 10 * 1000; // 10 seconds
private final Context mContext;
private final PackageManager mPackageManager;
private final Object mLock = new Object();
private final Handler mHandler;
@GuardedBy("mLock")
@@ -70,6 +72,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
GameManagerService(Context context, Looper looper) {
mContext = context;
mHandler = new SettingsHandler(looper);
mPackageManager = context.getPackageManager();
}
class SettingsHandler extends Handler {
@@ -171,9 +174,8 @@ public final class GameManagerService extends IGameManagerService.Stub {
}
private boolean isValidPackageName(String packageName) {
final PackageManager pm = mContext.getPackageManager();
try {
return pm.getPackageUid(packageName, 0) == Binder.getCallingUid();
return mPackageManager.getPackageUid(packageName, 0) == Binder.getCallingUid();
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return false;
@@ -208,16 +210,36 @@ public final class GameManagerService extends IGameManagerService.Stub {
@Override
public @GameMode int getGameMode(String packageName, int userId)
throws SecurityException {
// TODO(b/178860939): Restrict to games only.
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, true, "getGameMode",
"com.android.server.app.GameManagerService");
// Restrict to games only.
try {
final ApplicationInfo applicationInfo = mPackageManager
.getApplicationInfoAsUser(packageName, PackageManager.MATCH_ALL, userId);
if (applicationInfo.category != ApplicationInfo.CATEGORY_GAME) {
Log.e(TAG, "Ignoring attempt to get the Game Mode for '" + packageName
+ "' which is not categorized as a game: applicationInfo.flags = "
+ applicationInfo.flags + ", category = " + applicationInfo.category);
return GameManager.GAME_MODE_UNSUPPORTED;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return GameManager.GAME_MODE_UNSUPPORTED;
}
// This function handles two types of queries:
// 1.) A normal, non-privileged app querying its own Game Mode.
// 2.) A privileged system service querying the Game Mode of another package.
// The least privileged case is a normal app performing a query, so check that first and
// return a value if the package name is valid. Next, check if the caller has the necessary
// permission and return a value. Do this check last, since it can throw an exception.
if (isValidPackageName(packageName)) {
return getGameModeFromSettings(packageName, userId);
}
// Since the package name doesn't match, check the caller has the necessary permission.
checkPermission(Manifest.permission.MANAGE_GAME_MODE);
return getGameModeFromSettings(packageName, userId);
}
@@ -230,15 +252,28 @@ public final class GameManagerService extends IGameManagerService.Stub {
@RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
public void setGameMode(String packageName, @GameMode int gameMode, int userId)
throws SecurityException {
// TODO(b/178860939): Restrict to games only.
checkPermission(Manifest.permission.MANAGE_GAME_MODE);
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, true, "setGameMode",
"com.android.server.app.GameManagerService");
// Restrict to games only.
try {
final ApplicationInfo applicationInfo = mPackageManager
.getApplicationInfoAsUser(packageName, PackageManager.MATCH_ALL, userId);
if (applicationInfo.category != ApplicationInfo.CATEGORY_GAME) {
Log.e(TAG, "Ignoring attempt to set the Game Mode for '" + packageName
+ "' which is not categorized as a game: applicationInfo.flags = "
+ applicationInfo.flags + ", category = " + applicationInfo.category);
return;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return;
}
synchronized (mLock) {
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, true, "setGameMode",
"com.android.server.app.GameManagerService");
if (!mSettings.containsKey(userId)) {
return;
}

View File

@@ -49,14 +49,18 @@ public class GameManagerServiceTests {
private static final int USER_ID_2 = 1002;
// Stolen from ConnectivityServiceTest.MockContext
class MockContext extends ContextWrapper {
static 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();
}
/**
@@ -101,6 +105,11 @@ public class GameManagerServiceTests {
throw new SecurityException("[Test] permission denied: " + permission);
}
}
@Override
public PackageManager getPackageManager() {
return mMockPackageManager;
}
}
@Mock

File diff suppressed because it is too large Load Diff