Add MANAGE_GAME_ACTIVITY permission
Add permission enforcement to GameSessionController#takeScreenshot Bug: 216344350 Test: atest GameServiceProviderInstanceImplTest Change-Id: Ibf0a267f96b02a98d77887766d8bd0867c25eb53
This commit is contained in:
@@ -165,6 +165,7 @@ package android {
|
||||
field public static final String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING";
|
||||
field public static final String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
|
||||
field public static final String MANAGE_FACTORY_RESET_PROTECTION = "android.permission.MANAGE_FACTORY_RESET_PROTECTION";
|
||||
field public static final String MANAGE_GAME_ACTIVITY = "android.permission.MANAGE_GAME_ACTIVITY";
|
||||
field public static final String MANAGE_GAME_MODE = "android.permission.MANAGE_GAME_MODE";
|
||||
field public static final String MANAGE_HOTWORD_DETECTION = "android.permission.MANAGE_HOTWORD_DETECTION";
|
||||
field public static final String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
|
||||
@@ -10855,7 +10856,7 @@ package android.service.games {
|
||||
method public void onCreate();
|
||||
method public void onDestroy();
|
||||
method public void onGameTaskFocusChanged(boolean);
|
||||
method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public final boolean restartGame();
|
||||
method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY) public final boolean restartGame();
|
||||
method public void setTaskOverlayView(@NonNull android.view.View, @NonNull android.view.ViewGroup.LayoutParams);
|
||||
method public void takeScreenshot(@NonNull java.util.concurrent.Executor, @NonNull android.service.games.GameSession.ScreenshotCallback);
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@ public abstract class GameSession {
|
||||
*
|
||||
* @return {@code true} if the game was successfully restarted; otherwise, {@code false}.
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
|
||||
@RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY)
|
||||
public final boolean restartGame() {
|
||||
try {
|
||||
mGameSessionController.restartGame(mTaskId);
|
||||
|
||||
@@ -6150,6 +6150,12 @@
|
||||
<permission android:name="android.permission.ACCESS_FPS_COUNTER"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- @SystemApi Allows the GameService provider to create GameSession and call GameSession
|
||||
APIs and overlay a view on top of the game's Activity.
|
||||
@hide -->
|
||||
<permission android:name="android.permission.MANAGE_GAME_ACTIVITY"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- @SystemApi Allows the holder to register callbacks to inform the RebootReadinessManager
|
||||
when they are performing reboot-blocking work.
|
||||
@hide -->
|
||||
|
||||
@@ -116,9 +116,10 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
||||
});
|
||||
}
|
||||
|
||||
@RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
|
||||
@Override
|
||||
@RequiresPermission(Manifest.permission.MANAGE_GAME_ACTIVITY)
|
||||
public void restartGame(int taskId) {
|
||||
mContext.enforceCallingPermission(Manifest.permission.FORCE_STOP_PACKAGES,
|
||||
mContext.enforceCallingPermission(Manifest.permission.MANAGE_GAME_ACTIVITY,
|
||||
"restartGame()");
|
||||
mBackgroundExecutor.execute(() -> {
|
||||
GameServiceProviderInstanceImpl.this.restartGame(taskId);
|
||||
@@ -372,12 +373,12 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
||||
}, mBackgroundExecutor);
|
||||
|
||||
AndroidFuture<Void> unusedPostCreateGameSessionFuture =
|
||||
mGameSessionServiceConnector.post(gameService -> {
|
||||
mGameSessionServiceConnector.post(gameSessionService -> {
|
||||
CreateGameSessionRequest createGameSessionRequest =
|
||||
new CreateGameSessionRequest(
|
||||
taskId,
|
||||
existingGameSessionRecord.getComponentName().getPackageName());
|
||||
gameService.create(
|
||||
gameSessionService.create(
|
||||
mGameSessionController,
|
||||
createGameSessionRequest,
|
||||
gameSessionViewHostConfiguration,
|
||||
|
||||
@@ -26,6 +26,7 @@ import static com.google.common.collect.Iterables.getOnlyElement;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
@@ -33,6 +34,7 @@ import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.app.ActivityTaskManager;
|
||||
@@ -83,6 +85,7 @@ import org.mockito.quality.Strictness;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
@@ -121,7 +124,7 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
private WindowManagerInternal mMockWindowManagerInternal;
|
||||
@Mock
|
||||
private IActivityManager mMockActivityManager;
|
||||
private FakeContext mFakeContext;
|
||||
private MockContext mMockContext;
|
||||
private FakeGameClassifier mFakeGameClassifier;
|
||||
private FakeGameService mFakeGameService;
|
||||
private FakeServiceConnector<IGameService> mFakeGameServiceConnector;
|
||||
@@ -140,7 +143,7 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
.strictness(Strictness.LENIENT)
|
||||
.startMocking();
|
||||
|
||||
mFakeContext = new FakeContext(InstrumentationRegistry.getInstrumentation().getContext());
|
||||
mMockContext = new MockContext(InstrumentationRegistry.getInstrumentation().getContext());
|
||||
|
||||
mFakeGameClassifier = new FakeGameClassifier();
|
||||
mFakeGameClassifier.recordGamePackage(GAME_A_PACKAGE);
|
||||
@@ -169,7 +172,7 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
mGameServiceProviderInstance = new GameServiceProviderInstanceImpl(
|
||||
new UserHandle(USER_ID),
|
||||
ConcurrentUtils.DIRECT_EXECUTOR,
|
||||
mFakeContext,
|
||||
mMockContext,
|
||||
mFakeGameClassifier,
|
||||
mMockActivityManager,
|
||||
mMockActivityTaskManager,
|
||||
@@ -683,6 +686,7 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
|
||||
@Test
|
||||
public void restartGame_taskIdAssociatedWithGame_restartsTargetGame() throws Exception {
|
||||
mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
|
||||
Intent launchIntent = new Intent("com.test.ACTION_LAUNCH_GAME_PACKAGE")
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
when(mMockPackageManager.getLaunchIntentForPackage(GAME_A_PACKAGE))
|
||||
@@ -710,11 +714,12 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
.mGameSessionController.restartGame(10);
|
||||
|
||||
verify(mMockActivityManager).forceStopPackage(GAME_A_PACKAGE, UserHandle.USER_CURRENT);
|
||||
assertThat(mFakeContext.getLastStartedIntent()).isEqualTo(launchIntent);
|
||||
assertThat(mMockContext.getLastStartedIntent()).isEqualTo(launchIntent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restartGame_taskIdNotAssociatedWithGame_noOp() throws Exception {
|
||||
mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
|
||||
mGameServiceProviderInstance.start();
|
||||
|
||||
startTask(10, GAME_A_MAIN_ACTIVITY);
|
||||
@@ -730,7 +735,19 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
.mGameSessionController.restartGame(11);
|
||||
|
||||
verifyZeroInteractions(mMockActivityManager);
|
||||
assertThat(mFakeContext.getLastStartedIntent()).isNull();
|
||||
assertThat(mMockContext.getLastStartedIntent()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restartGame_failurePermissionDenied() throws Exception {
|
||||
mGameServiceProviderInstance.start();
|
||||
startTask(10, GAME_A_MAIN_ACTIVITY);
|
||||
mFakeGameService.requestCreateGameSession(10);
|
||||
|
||||
IGameSessionController gameSessionController = Objects.requireNonNull(getOnlyElement(
|
||||
mFakeGameSessionService.getCapturedCreateInvocations())).mGameSessionController;
|
||||
assertThrows(SecurityException.class,
|
||||
() -> gameSessionController.restartGame(10));
|
||||
}
|
||||
|
||||
private void startTask(int taskId, ComponentName componentName) {
|
||||
@@ -774,6 +791,14 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
}
|
||||
}
|
||||
|
||||
private void mockPermissionGranted(String permission) {
|
||||
mMockContext.setPermission(permission, PackageManager.PERMISSION_GRANTED);
|
||||
}
|
||||
|
||||
private void mockPermissionDenied(String permission) {
|
||||
mMockContext.setPermission(permission, PackageManager.PERMISSION_DENIED);
|
||||
}
|
||||
|
||||
static final class FakeGameService extends IGameService.Stub {
|
||||
private IGameServiceController mGameServiceController;
|
||||
|
||||
@@ -900,13 +925,28 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
}
|
||||
}
|
||||
|
||||
private final class FakeContext extends ContextWrapper {
|
||||
private final class MockContext extends ContextWrapper {
|
||||
private Intent mLastStartedIntent;
|
||||
// Map of permission name -> PermissionManager.Permission_{GRANTED|DENIED} constant
|
||||
private final HashMap<String, Integer> mMockedPermissions = new HashMap<>();
|
||||
|
||||
FakeContext(Context base) {
|
||||
MockContext(Context base) {
|
||||
super(base);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock checks for the specified permission, and have them behave as per {@code granted}.
|
||||
*
|
||||
* <p>Passing null reverts to default behavior, which does a real permission check on the
|
||||
* test package.
|
||||
*
|
||||
* @param granted One of {@link PackageManager#PERMISSION_GRANTED} or
|
||||
* {@link PackageManager#PERMISSION_DENIED}.
|
||||
*/
|
||||
public void setPermission(String permission, Integer granted) {
|
||||
mMockedPermissions.put(permission, granted);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PackageManager getPackageManager() {
|
||||
return mMockPackageManager;
|
||||
@@ -919,7 +959,15 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
|
||||
@Override
|
||||
public void enforceCallingPermission(String permission, @Nullable String message) {
|
||||
// Do nothing.
|
||||
final Integer granted = mMockedPermissions.get(permission);
|
||||
if (granted == null) {
|
||||
super.enforceCallingOrSelfPermission(permission, message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!granted.equals(PackageManager.PERMISSION_GRANTED)) {
|
||||
throw new SecurityException("[Test] permission denied: " + permission);
|
||||
}
|
||||
}
|
||||
|
||||
Intent getLastStartedIntent() {
|
||||
|
||||
Reference in New Issue
Block a user