Add a test API allowing overriding the GameService provider.

This is so that CTS tests can be run against a test GameService
rather than against whatever GameService a particular device
has set as its default.

Ignore-AOSP-First: GameService incomplete in AOSP
Test: atest CtsGameServiceTestCases GameServiceProviderSelectorImplTest
Bug: 202417555
Bug: 206128693
Change-Id: I5d0d1a4047949117850818c14b5df617314efcf5
This commit is contained in:
shannonchen
2022-01-21 16:08:14 +00:00
committed by Shannon Chen
parent 78f3eb7af4
commit d5846ad238
12 changed files with 168 additions and 57 deletions

View File

@@ -38,6 +38,7 @@ package android {
field public static final String RESET_APP_ERRORS = "android.permission.RESET_APP_ERRORS";
field public static final String REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL = "android.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL";
field public static final String SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS = "android.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS";
field public static final String SET_GAME_SERVICE = "android.permission.SET_GAME_SERVICE";
field public static final String SET_KEYBOARD_LAYOUT = "android.permission.SET_KEYBOARD_LAYOUT";
field public static final String START_TASKS_FROM_RECENTS = "android.permission.START_TASKS_FROM_RECENTS";
field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
@@ -274,6 +275,10 @@ package android.app {
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void stopDream();
}
public final class GameManager {
method public void setGameServiceProvider(@Nullable String);
}
public abstract class HomeVisibilityListener {
ctor public HomeVisibilityListener();
method public abstract void onHomeVisibilityChanged(boolean);

View File

@@ -23,6 +23,7 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UserHandleAware;
import android.content.Context;
import android.os.Handler;
@@ -204,4 +205,20 @@ public final class GameManager {
throw e.rethrowFromSystemServer();
}
}
/**
* Sets the game service provider to the given package name for test only.
*
* <p>Passing in {@code null} will clear a previously set value.
* @hide
*/
@TestApi
public void setGameServiceProvider(@Nullable String packageName) {
try {
mService.setGameServiceProvider(packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}

View File

@@ -29,4 +29,5 @@ interface IGameManagerService {
boolean getAngleEnabled(String packageName, int userId);
void setGameState(String packageName, in GameState gameState, int userId);
GameModeInfo getGameModeInfo(String packageName, int userId);
void setGameServiceProvider(String packageName);
}

View File

@@ -6131,6 +6131,11 @@
<permission android:name="android.permission.MANAGE_GAME_MODE"
android:protectionLevel="signature|privileged" />
<!-- @TestApi Allows setting the game service provider, meant for tests only.
@hide -->
<permission android:name="android.permission.SET_GAME_SERVICE"
android:protectionLevel="signature" />
<!-- @SystemApi Allows accessing the frame rate per second of a given application
@hide -->
<permission android:name="android.permission.ACCESS_FPS_COUNTER"

View File

@@ -557,6 +557,9 @@
<!-- Permission required for CTS test - CtsGameManagerTestCases -->
<uses-permission android:name="android.permission.MANAGE_GAME_MODE" />
<!-- Permission required for CTS test - CtsGameServiceTestCases -->
<uses-permission android:name="android.permission.SET_GAME_SERVICE" />
<!-- Permission required for CTS test - ClipboardManagerTest -->
<uses-permission android:name="android.permission.SET_CLIP_SOURCE" />

View File

@@ -83,7 +83,6 @@ import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.SystemService.TargetUser;
import com.android.server.app.GameManagerService.GamePackageConfiguration.GameModeConfiguration;
import java.io.FileDescriptor;
import java.util.List;
@@ -128,6 +127,8 @@ public final class GameManagerService extends IGameManagerService.Stub {
private final ArrayMap<String, GamePackageConfiguration> mConfigs = new ArrayMap<>();
@GuardedBy("mOverrideConfigLock")
private final ArrayMap<String, GamePackageConfiguration> mOverrideConfigs = new ArrayMap<>();
@Nullable
private final GameServiceController mGameServiceController;
public GameManagerService(Context context) {
this(context, createServiceThread().getLooper());
@@ -140,6 +141,16 @@ public final class GameManagerService extends IGameManagerService.Stub {
mPlatformCompat = IPlatformCompat.Stub.asInterface(
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_GAME_SERVICE)) {
mGameServiceController = new GameServiceController(
BackgroundThread.getExecutor(),
new GameServiceProviderSelectorImpl(
context.getResources(),
context.getPackageManager()),
new GameServiceProviderInstanceFactoryImpl(context));
} else {
mGameServiceController = null;
}
}
@Override
@@ -610,8 +621,6 @@ public final class GameManagerService extends IGameManagerService.Stub {
*/
public static class Lifecycle extends SystemService {
private GameManagerService mService;
@Nullable
private GameServiceController mGameServiceController;
public Lifecycle(Context context) {
super(context);
@@ -624,57 +633,33 @@ public final class GameManagerService extends IGameManagerService.Stub {
publishBinderService(Context.GAME_SERVICE, mService);
mService.registerDeviceConfigListener();
mService.registerPackageReceiver();
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_GAME_SERVICE)) {
mGameServiceController = new GameServiceController(
BackgroundThread.getExecutor(),
new GameServiceProviderSelectorImpl(
getContext().getResources(),
getContext().getPackageManager()),
new GameServiceProviderInstanceFactoryImpl(getContext()));
}
}
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_BOOT_COMPLETED) {
mService.onBootCompleted();
if (mGameServiceController != null) {
mGameServiceController.onBootComplete();
}
}
}
@Override
public void onUserStarting(@NonNull TargetUser user) {
mService.onUserStarting(user.getUserIdentifier());
if (mGameServiceController != null) {
mGameServiceController.notifyUserStarted(user);
}
mService.onUserStarting(user);
}
@Override
public void onUserUnlocking(@NonNull TargetUser user) {
super.onUserUnlocking(user);
if (mGameServiceController != null) {
mGameServiceController.notifyUserUnlocking(user);
}
mService.onUserUnlocking(user);
}
@Override
public void onUserStopping(@NonNull TargetUser user) {
mService.onUserStopping(user.getUserIdentifier());
if (mGameServiceController != null) {
mGameServiceController.notifyUserStopped(user);
}
mService.onUserStopping(user);
}
@Override
public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
mService.onUserSwitching(from, to.getUserIdentifier());
if (mGameServiceController != null) {
mGameServiceController.notifyNewForegroundUser(to);
}
mService.onUserSwitching(from, to);
}
}
@@ -867,15 +852,39 @@ public final class GameManagerService extends IGameManagerService.Stub {
}
}
/**
* Sets the game service provider to a given package, meant for testing.
*
* <p>This setting persists until the next call or until the next reboot.
*
* <p>Checks that the caller has {@link android.Manifest.permission#SET_GAME_SERVICE}.
*/
@Override
@RequiresPermission(Manifest.permission.SET_GAME_SERVICE)
public void setGameServiceProvider(@Nullable String packageName) throws SecurityException {
checkPermission(Manifest.permission.SET_GAME_SERVICE);
if (mGameServiceController == null) {
return;
}
mGameServiceController.setGameServiceProvider(packageName);
}
/**
* Notified when boot is completed.
*/
@VisibleForTesting
void onBootCompleted() {
Slog.d(TAG, "onBootCompleted");
if (mGameServiceController != null) {
mGameServiceController.onBootComplete();
}
}
void onUserStarting(int userId) {
void onUserStarting(@NonNull TargetUser user) {
final int userId = user.getUserIdentifier();
synchronized (mLock) {
if (!mSettings.containsKey(userId)) {
GameManagerSettings userSettings =
@@ -887,9 +896,21 @@ public final class GameManagerService extends IGameManagerService.Stub {
final Message msg = mHandler.obtainMessage(POPULATE_GAME_MODE_SETTINGS);
msg.obj = userId;
mHandler.sendMessage(msg);
if (mGameServiceController != null) {
mGameServiceController.notifyUserStarted(user);
}
}
void onUserStopping(int userId) {
void onUserUnlocking(@NonNull TargetUser user) {
if (mGameServiceController != null) {
mGameServiceController.notifyUserUnlocking(user);
}
}
void onUserStopping(TargetUser user) {
final int userId = user.getUserIdentifier();
synchronized (mLock) {
if (!mSettings.containsKey(userId)) {
return;
@@ -898,9 +919,14 @@ public final class GameManagerService extends IGameManagerService.Stub {
msg.obj = userId;
mHandler.sendMessage(msg);
}
if (mGameServiceController != null) {
mGameServiceController.notifyUserStopped(user);
}
}
void onUserSwitching(TargetUser from, int toUserId) {
void onUserSwitching(TargetUser from, TargetUser to) {
final int toUserId = to.getUserIdentifier();
if (from != null) {
synchronized (mLock) {
final int fromUserId = from.getUserIdentifier();
@@ -914,6 +940,10 @@ public final class GameManagerService extends IGameManagerService.Stub {
final Message msg = mHandler.obtainMessage(POPULATE_GAME_MODE_SETTINGS);
msg.obj = toUserId;
mHandler.sendMessage(msg);
if (mGameServiceController != null) {
mGameServiceController.notifyNewForegroundUser(to);
}
}
/**

View File

@@ -44,6 +44,8 @@ final class GameServiceController {
private volatile boolean mHasBootCompleted;
@Nullable
private volatile String mGameServiceProviderOverride;
@Nullable
private volatile SystemService.TargetUser mCurrentForegroundUser;
@GuardedBy("mLock")
@Nullable
@@ -108,6 +110,16 @@ final class GameServiceController {
setCurrentForegroundUserAndEvaluateProvider(null);
}
void setGameServiceProvider(@Nullable String packageName) {
boolean hasPackageChanged = !Objects.equals(mGameServiceProviderOverride, packageName);
if (!hasPackageChanged) {
return;
}
mGameServiceProviderOverride = packageName;
mBackgroundExecutor.execute(this::evaluateActiveGameServiceProvider);
}
private void setCurrentForegroundUserAndEvaluateProvider(
@Nullable SystemService.TargetUser user) {
boolean hasUserChanged =
@@ -128,7 +140,8 @@ final class GameServiceController {
synchronized (mLock) {
GameServiceProviderConfiguration selectedGameServiceProviderConfiguration =
mGameServiceProviderSelector.get(mCurrentForegroundUser);
mGameServiceProviderSelector.get(mCurrentForegroundUser,
mGameServiceProviderOverride);
boolean didActiveGameServiceProviderChanged =
!Objects.equals(selectedGameServiceProviderConfiguration,

View File

@@ -30,5 +30,6 @@ interface GameServiceProviderSelector {
* Service provider for the given user or {@code null} if none should be used.
*/
@Nullable
GameServiceProviderConfiguration get(@Nullable SystemService.TargetUser user);
GameServiceProviderConfiguration get(@Nullable SystemService.TargetUser user,
@Nullable String packageNameOverride);
}

View File

@@ -57,7 +57,8 @@ final class GameServiceProviderSelectorImpl implements GameServiceProviderSelect
@Override
@Nullable
public GameServiceProviderConfiguration get(@Nullable SystemService.TargetUser user) {
public GameServiceProviderConfiguration get(@Nullable SystemService.TargetUser user,
@Nullable String packageNameOverride) {
if (user == null) {
return null;
}
@@ -68,9 +69,16 @@ final class GameServiceProviderSelectorImpl implements GameServiceProviderSelect
return null;
}
String gameServicePackage =
mResources.getString(
com.android.internal.R.string.config_systemGameService);
int resolveInfoQueryFlags;
String gameServicePackage;
if (!TextUtils.isEmpty(packageNameOverride)) {
resolveInfoQueryFlags = 0;
gameServicePackage = packageNameOverride;
} else {
resolveInfoQueryFlags = PackageManager.MATCH_SYSTEM_ONLY;
gameServicePackage = mResources.getString(
com.android.internal.R.string.config_systemGameService);
}
if (TextUtils.isEmpty(gameServicePackage)) {
Slog.w(TAG, "No game service package defined");
@@ -81,7 +89,7 @@ final class GameServiceProviderSelectorImpl implements GameServiceProviderSelect
List<ResolveInfo> gameServiceResolveInfos =
mPackageManager.queryIntentServicesAsUser(
new Intent(GameService.ACTION_GAME_SERVICE).setPackage(gameServicePackage),
PackageManager.GET_META_DATA | PackageManager.MATCH_SYSTEM_ONLY,
PackageManager.GET_META_DATA | resolveInfoQueryFlags,
userId);
if (DEBUG) {
Slog.i(TAG, "Querying package: " + gameServicePackage + " and user id: " + userId);

View File

@@ -35,6 +35,7 @@ import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
@@ -45,6 +46,8 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.SystemService;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -167,7 +170,8 @@ public class GameManagerServiceTests {
}
private void startUser(GameManagerService gameManagerService, int userId) {
gameManagerService.onUserStarting(userId);
UserInfo userInfo = new UserInfo(userId, "name", 0);
gameManagerService.onUserStarting(new SystemService.TargetUser(userInfo));
mTestLooper.dispatchAll();
}
@@ -861,7 +865,7 @@ public class GameManagerServiceTests {
public void testInterventionAllowAngleFalse() throws Exception {
GameManagerService gameManagerService =
new GameManagerService(mMockContext, mTestLooper.getLooper());
gameManagerService.onUserStarting(USER_ID_1);
startUser(gameManagerService, USER_ID_1);
mockDeviceConfigPerformanceEnableAngle();
mockInterventionAllowAngleFalse();
mockModifyGameModeGranted();

View File

@@ -207,12 +207,12 @@ public final class GameServiceControllerTest {
}
private void seedNoConfigurationForUser(SystemService.TargetUser user) {
when(mMockGameServiceProviderSelector.get(user)).thenReturn(null);
when(mMockGameServiceProviderSelector.get(user, "")).thenReturn(null);
}
private FakeGameServiceProviderInstance seedConfigurationForUser(SystemService.TargetUser user,
GameServiceProviderConfiguration configuration) {
when(mMockGameServiceProviderSelector.get(user)).thenReturn(configuration);
when(mMockGameServiceProviderSelector.get(user, "")).thenReturn(configuration);
FakeGameServiceProviderInstance instanceForConfiguration =
spy(new FakeGameServiceProviderInstance());
when(mMockGameServiceProviderInstanceFactory.create(configuration))

View File

@@ -16,6 +16,7 @@
package com.android.server.app;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.google.common.truth.Truth.assertThat;
@@ -25,7 +26,6 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -138,7 +138,7 @@ public final class GameServiceProviderSelectorImplTest {
"res/xml/game_service_metadata_valid.xml");
GameServiceProviderConfiguration gameServiceProviderConfiguration =
mGameServiceProviderSelector.get(null);
mGameServiceProviderSelector.get(null, null);
assertThat(gameServiceProviderConfiguration).isNull();
}
@@ -155,7 +155,7 @@ public final class GameServiceProviderSelectorImplTest {
"res/xml/game_service_metadata_valid.xml");
GameServiceProviderConfiguration gameServiceProviderConfiguration =
mGameServiceProviderSelector.get(managedTargetUser(USER_HANDLE_10));
mGameServiceProviderSelector.get(managedTargetUser(USER_HANDLE_10), null);
assertThat(gameServiceProviderConfiguration).isNull();
}
@@ -171,7 +171,7 @@ public final class GameServiceProviderSelectorImplTest {
"res/xml/game_service_metadata_valid.xml");
GameServiceProviderConfiguration gameServiceProviderConfiguration =
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10), null);
assertThat(gameServiceProviderConfiguration).isNull();
}
@@ -187,7 +187,7 @@ public final class GameServiceProviderSelectorImplTest {
"res/xml/game_service_metadata_valid.xml");
GameServiceProviderConfiguration gameServiceProviderConfiguration =
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10), null);
assertThat(gameServiceProviderConfiguration).isNull();
}
@@ -201,7 +201,7 @@ public final class GameServiceProviderSelectorImplTest {
seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
GameServiceProviderConfiguration gameServiceProviderConfiguration =
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10), null);
assertThat(gameServiceProviderConfiguration).isNull();
}
@@ -218,7 +218,7 @@ public final class GameServiceProviderSelectorImplTest {
"res/xml/game_service_metadata_valid.xml");
GameServiceProviderConfiguration gameServiceProviderConfiguration =
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10), null);
assertThat(gameServiceProviderConfiguration).isNull();
}
@@ -234,7 +234,7 @@ public final class GameServiceProviderSelectorImplTest {
"res/xml/game_service_metadata_wrong_first_tag.xml");
GameServiceProviderConfiguration gameServiceProviderConfiguration =
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10), null);
assertThat(gameServiceProviderConfiguration).isNull();
}
@@ -251,7 +251,7 @@ public final class GameServiceProviderSelectorImplTest {
"res/xml/game_service_metadata_valid.xml");
GameServiceProviderConfiguration gameServiceProviderConfiguration =
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10), null);
GameServiceProviderConfiguration expectedGameServiceProviderConfiguration =
new GameServiceProviderConfiguration(USER_HANDLE_10,
@@ -277,7 +277,7 @@ public final class GameServiceProviderSelectorImplTest {
"res/xml/game_service_metadata_valid.xml");
GameServiceProviderConfiguration gameServiceProviderConfiguration =
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10), null);
GameServiceProviderConfiguration expectedGameServiceProviderConfiguration =
new GameServiceProviderConfiguration(USER_HANDLE_10,
@@ -300,7 +300,31 @@ public final class GameServiceProviderSelectorImplTest {
"res/xml/game_service_metadata_valid.xml");
GameServiceProviderConfiguration gameServiceProviderConfiguration =
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10), null);
GameServiceProviderConfiguration expectedGameServiceProviderConfiguration =
new GameServiceProviderConfiguration(USER_HANDLE_10,
GAME_SERVICE_COMPONENT,
GAME_SESSION_SERVICE_COMPONENT);
assertThat(gameServiceProviderConfiguration).isEqualTo(
expectedGameServiceProviderConfiguration);
}
@Test
public void get_overridePresent_returnsDeviceConfigGameServiceProvider()
throws Exception {
seedSystemGameServicePackageName("other.package");
seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
resolveInfo(GAME_SERVICE_B_SERVICE_INFO), resolveInfo(GAME_SERVICE_SERVICE_INFO));
seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
GAME_SERVICE_META_DATA_RES_ID,
"res/xml/game_service_metadata_valid.xml");
GameServiceProviderConfiguration gameServiceProviderConfiguration =
mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10),
GAME_SERVICE_PACKAGE_NAME);
GameServiceProviderConfiguration expectedGameServiceProviderConfiguration =
new GameServiceProviderConfiguration(USER_HANDLE_10,
@@ -324,7 +348,7 @@ public final class GameServiceProviderSelectorImplTest {
argThat(intent ->
intent != null
&& intent.getAction().equals(
GameService.ACTION_GAME_SERVICE)
GameService.ACTION_GAME_SERVICE)
&& intent.getPackage().equals(gameServicePackageName)
),
anyInt(),