summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2022-01-31 17:47:07 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2022-01-31 17:47:07 +0000
commit1825f7724315e8c47d479d9fe3be3b57113c8d91 (patch)
treeb3a38aa31fb053cf8f7934493b371e537cff38ad
parent30288f9eeb63843e1a5883c035e23bb27bc687dd (diff)
parente7b9879b4bb6610f0c36b6af4c5149b22a4f18c5 (diff)
Merge "Add MANAGE_GAME_ACTIVITY permission"
-rw-r--r--core/api/system-current.txt3
-rw-r--r--core/java/android/service/games/GameSession.java2
-rw-r--r--core/res/AndroidManifest.xml6
-rw-r--r--services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java9
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java64
5 files changed, 70 insertions, 14 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index c47c37b0bc7e..ec39e9f4df2d 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -166,6 +166,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";
@@ -11060,7 +11061,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);
}
diff --git a/core/java/android/service/games/GameSession.java b/core/java/android/service/games/GameSession.java
index f4baedc18acf..9590933cf2da 100644
--- a/core/java/android/service/games/GameSession.java
+++ b/core/java/android/service/games/GameSession.java
@@ -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);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 92f7f2921bee..7df9ca73b0d5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -6174,6 +6174,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 -->
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index 913621913e95..ec37134acd01 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -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,
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
index d5e4710095f2..b0ffcf34ac07 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
@@ -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() {