Loading core/java/android/app/GameManager.java +23 −7 Original line number Diff line number Diff line Loading @@ -29,16 +29,24 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Build; import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * The GameManager allows system apps to modify and query the game mode of apps. * * <p><b>Note:</b> After {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}, some devices * that do not support the GameManager features <i>may</i> not publish a GameManager instance. * These device types include: * <ul> * <li> Wear devices ({@link PackageManager#FEATURE_WATCH}) * </ul> * * <p>Therefore, you should always do a {@code null} check on the return value of * {@link Context#getSystemService(Class)} and {@link Context#getSystemService(String)} when trying * to obtain an instance of GameManager on the aforementioned device types. */ @SystemService(Context.GAME_SERVICE) public final class GameManager { Loading @@ -46,7 +54,7 @@ public final class GameManager { private static final String TAG = "GameManager"; private final @Nullable Context mContext; private final IGameManagerService mService; private final @Nullable IGameManagerService mService; /** @hide */ @IntDef(flag = false, prefix = {"GAME_MODE_"}, value = { Loading Loading @@ -92,10 +100,9 @@ public final class GameManager { */ public static final int GAME_MODE_CUSTOM = 4; GameManager(Context context, Handler handler) throws ServiceNotFoundException { GameManager(Context context, @Nullable IGameManagerService service) { mContext = context; mService = IGameManagerService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.GAME_SERVICE)); mService = service; } /** Loading Loading @@ -145,6 +152,7 @@ public final class GameManager { // we don't want a binder call each time to check on behalf of an app using CompatChange. @SuppressWarnings("AndroidFrameworkCompatChange") private @GameMode int getGameModeImpl(@NonNull String packageName, int targetSdkVersion) { if (mService == null) return GAME_MODE_UNSUPPORTED; final int gameMode; try { gameMode = mService.getGameMode(packageName, Loading Loading @@ -176,6 +184,7 @@ public final class GameManager { @UserHandleAware @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public @Nullable GameModeInfo getGameModeInfo(@NonNull String packageName) { if (mService == null) return null; try { return mService.getGameModeInfo(packageName, mContext.getUserId()); } catch (RemoteException e) { Loading @@ -196,6 +205,7 @@ public final class GameManager { @UserHandleAware @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public void setGameMode(@NonNull String packageName, @GameMode int gameMode) { if (mService == null) return; try { mService.setGameMode(packageName, gameMode, mContext.getUserId()); } catch (RemoteException e) { Loading @@ -212,6 +222,7 @@ public final class GameManager { */ @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public @GameMode int[] getAvailableGameModes(@NonNull String packageName) { if (mService == null) return new int[0]; try { return mService.getAvailableGameModes(packageName, mContext.getUserId()); } catch (RemoteException e) { Loading @@ -232,6 +243,7 @@ public final class GameManager { @TestApi @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public boolean isAngleEnabled(@NonNull String packageName) { if (mService == null) return false; try { return mService.isAngleEnabled(packageName, mContext.getUserId()); } catch (RemoteException e) { Loading @@ -246,6 +258,7 @@ public final class GameManager { */ @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public void notifyGraphicsEnvironmentSetup() { if (mService == null) return; try { mService.notifyGraphicsEnvironmentSetup( mContext.getPackageName(), mContext.getUserId()); Loading @@ -259,6 +272,7 @@ public final class GameManager { * @param gameState An object set to the current state. */ public void setGameState(@NonNull GameState gameState) { if (mService == null) return; try { mService.setGameState(mContext.getPackageName(), gameState, mContext.getUserId()); } catch (RemoteException e) { Loading @@ -275,6 +289,7 @@ public final class GameManager { */ @TestApi public void setGameServiceProvider(@Nullable String packageName) { if (mService == null) return; try { mService.setGameServiceProvider(packageName); } catch (RemoteException e) { Loading @@ -296,6 +311,7 @@ public final class GameManager { @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public void updateCustomGameModeConfiguration(@NonNull String packageName, @NonNull GameModeConfiguration gameModeConfig) { if (mService == null) return; try { mService.updateCustomGameModeConfiguration(packageName, gameModeConfig, mContext.getUserId()); Loading core/java/android/app/SystemServiceRegistry.java +30 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.app; import static android.app.appfunctions.flags.Flags.enableAppFunctionManager; import static android.server.Flags.removeGameManagerServiceFromWear; import android.accounts.AccountManager; import android.accounts.IAccountManager; Loading Loading @@ -74,6 +75,7 @@ import android.companion.virtual.IVirtualDeviceManager; import android.companion.virtual.VirtualDeviceManager; import android.compat.Compatibility; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.compat.annotation.EnabledSince; import android.content.ClipboardManager; import android.content.ContentCaptureOptions; Loading Loading @@ -308,6 +310,16 @@ public final class SystemServiceRegistry { @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) static final long ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN = 330902016; /** * After {@link Build.VERSION_CODES.VANILLA_ICE_CREAM}, Wear devices will be allowed to publish * no {@link GameManager} instance. This is because the respective system service is no longer * started for Wear devices given that the applications of the service do not currently apply to * Wear. */ @ChangeId @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) static final long NULL_GAME_MANAGER_IN_WEAR = 340929737; /** * The corresponding vendor API for Android V * Loading Loading @@ -1624,8 +1636,24 @@ public final class SystemServiceRegistry { @Override public GameManager createService(ContextImpl ctx) throws ServiceNotFoundException { return new GameManager(ctx.getOuterContext(), ctx.mMainThread.getHandler()); final PackageManager pm = ctx.getPackageManager(); final boolean isWatch = pm.hasSystemFeature(PackageManager.FEATURE_WATCH); final IBinder binder = // Allow a potentially absent GameManagerService only for // Wear devices. For non-Wear devices, throw a // ServiceNotFoundException when the service is missing. (removeGameManagerServiceFromWear() && isWatch) ? ServiceManager.getService(Context.GAME_SERVICE) : ServiceManager.getServiceOrThrow(Context.GAME_SERVICE); if (binder == null && Compatibility.isChangeEnabled(NULL_GAME_MANAGER_IN_WEAR)) { return null; } return new GameManager( ctx.getOuterContext(), IGameManagerService.Stub.asInterface(binder)); } }); Loading core/tests/GameManagerTests/src/android/app/GameManagerTests.java +6 −0 Original line number Diff line number Diff line Loading @@ -22,7 +22,10 @@ import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; import static org.junit.Assume.assumeNotNull; import android.content.Context; import android.content.pm.PackageManager; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; Loading @@ -47,6 +50,9 @@ public final class GameManagerTests { public void setUp() { mContext = getInstrumentation().getContext(); mGameManager = mContext.getSystemService(GameManager.class); if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) { assumeNotNull(mGameManager); } mPackageName = mContext.getPackageName(); // Reset the Game Mode for the test app, since it persists across invocations. Loading services/java/com/android/server/SystemServer.java +7 −3 Original line number Diff line number Diff line Loading @@ -3009,9 +3009,13 @@ public final class SystemServer implements Dumpable { } t.traceEnd(); if (!isWatch || !android.server.Flags.removeGameManagerServiceFromWear()) { t.traceBegin("GameManagerService"); mSystemServiceManager.startService(GameManagerService.Lifecycle.class); t.traceEnd(); } else { Slog.d(TAG, "Not starting GameManagerService"); } if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)) { t.traceBegin("UwbService"); Loading services/java/com/android/server/flags.aconfig +8 −0 Original line number Diff line number Diff line Loading @@ -36,3 +36,11 @@ flag { description: "Allow NetworkTimeUpdateService on Wear" bug: "327508176" } flag { name: "remove_game_manager_service_from_wear" namespace: "wear_frameworks" description: "Remove GameManagerService from Wear" bug: "340929737" is_fixed_read_only: true } No newline at end of file Loading
core/java/android/app/GameManager.java +23 −7 Original line number Diff line number Diff line Loading @@ -29,16 +29,24 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Build; import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * The GameManager allows system apps to modify and query the game mode of apps. * * <p><b>Note:</b> After {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}, some devices * that do not support the GameManager features <i>may</i> not publish a GameManager instance. * These device types include: * <ul> * <li> Wear devices ({@link PackageManager#FEATURE_WATCH}) * </ul> * * <p>Therefore, you should always do a {@code null} check on the return value of * {@link Context#getSystemService(Class)} and {@link Context#getSystemService(String)} when trying * to obtain an instance of GameManager on the aforementioned device types. */ @SystemService(Context.GAME_SERVICE) public final class GameManager { Loading @@ -46,7 +54,7 @@ public final class GameManager { private static final String TAG = "GameManager"; private final @Nullable Context mContext; private final IGameManagerService mService; private final @Nullable IGameManagerService mService; /** @hide */ @IntDef(flag = false, prefix = {"GAME_MODE_"}, value = { Loading Loading @@ -92,10 +100,9 @@ public final class GameManager { */ public static final int GAME_MODE_CUSTOM = 4; GameManager(Context context, Handler handler) throws ServiceNotFoundException { GameManager(Context context, @Nullable IGameManagerService service) { mContext = context; mService = IGameManagerService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.GAME_SERVICE)); mService = service; } /** Loading Loading @@ -145,6 +152,7 @@ public final class GameManager { // we don't want a binder call each time to check on behalf of an app using CompatChange. @SuppressWarnings("AndroidFrameworkCompatChange") private @GameMode int getGameModeImpl(@NonNull String packageName, int targetSdkVersion) { if (mService == null) return GAME_MODE_UNSUPPORTED; final int gameMode; try { gameMode = mService.getGameMode(packageName, Loading Loading @@ -176,6 +184,7 @@ public final class GameManager { @UserHandleAware @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public @Nullable GameModeInfo getGameModeInfo(@NonNull String packageName) { if (mService == null) return null; try { return mService.getGameModeInfo(packageName, mContext.getUserId()); } catch (RemoteException e) { Loading @@ -196,6 +205,7 @@ public final class GameManager { @UserHandleAware @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public void setGameMode(@NonNull String packageName, @GameMode int gameMode) { if (mService == null) return; try { mService.setGameMode(packageName, gameMode, mContext.getUserId()); } catch (RemoteException e) { Loading @@ -212,6 +222,7 @@ public final class GameManager { */ @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public @GameMode int[] getAvailableGameModes(@NonNull String packageName) { if (mService == null) return new int[0]; try { return mService.getAvailableGameModes(packageName, mContext.getUserId()); } catch (RemoteException e) { Loading @@ -232,6 +243,7 @@ public final class GameManager { @TestApi @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public boolean isAngleEnabled(@NonNull String packageName) { if (mService == null) return false; try { return mService.isAngleEnabled(packageName, mContext.getUserId()); } catch (RemoteException e) { Loading @@ -246,6 +258,7 @@ public final class GameManager { */ @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public void notifyGraphicsEnvironmentSetup() { if (mService == null) return; try { mService.notifyGraphicsEnvironmentSetup( mContext.getPackageName(), mContext.getUserId()); Loading @@ -259,6 +272,7 @@ public final class GameManager { * @param gameState An object set to the current state. */ public void setGameState(@NonNull GameState gameState) { if (mService == null) return; try { mService.setGameState(mContext.getPackageName(), gameState, mContext.getUserId()); } catch (RemoteException e) { Loading @@ -275,6 +289,7 @@ public final class GameManager { */ @TestApi public void setGameServiceProvider(@Nullable String packageName) { if (mService == null) return; try { mService.setGameServiceProvider(packageName); } catch (RemoteException e) { Loading @@ -296,6 +311,7 @@ public final class GameManager { @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public void updateCustomGameModeConfiguration(@NonNull String packageName, @NonNull GameModeConfiguration gameModeConfig) { if (mService == null) return; try { mService.updateCustomGameModeConfiguration(packageName, gameModeConfig, mContext.getUserId()); Loading
core/java/android/app/SystemServiceRegistry.java +30 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.app; import static android.app.appfunctions.flags.Flags.enableAppFunctionManager; import static android.server.Flags.removeGameManagerServiceFromWear; import android.accounts.AccountManager; import android.accounts.IAccountManager; Loading Loading @@ -74,6 +75,7 @@ import android.companion.virtual.IVirtualDeviceManager; import android.companion.virtual.VirtualDeviceManager; import android.compat.Compatibility; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.compat.annotation.EnabledSince; import android.content.ClipboardManager; import android.content.ContentCaptureOptions; Loading Loading @@ -308,6 +310,16 @@ public final class SystemServiceRegistry { @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) static final long ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN = 330902016; /** * After {@link Build.VERSION_CODES.VANILLA_ICE_CREAM}, Wear devices will be allowed to publish * no {@link GameManager} instance. This is because the respective system service is no longer * started for Wear devices given that the applications of the service do not currently apply to * Wear. */ @ChangeId @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) static final long NULL_GAME_MANAGER_IN_WEAR = 340929737; /** * The corresponding vendor API for Android V * Loading Loading @@ -1624,8 +1636,24 @@ public final class SystemServiceRegistry { @Override public GameManager createService(ContextImpl ctx) throws ServiceNotFoundException { return new GameManager(ctx.getOuterContext(), ctx.mMainThread.getHandler()); final PackageManager pm = ctx.getPackageManager(); final boolean isWatch = pm.hasSystemFeature(PackageManager.FEATURE_WATCH); final IBinder binder = // Allow a potentially absent GameManagerService only for // Wear devices. For non-Wear devices, throw a // ServiceNotFoundException when the service is missing. (removeGameManagerServiceFromWear() && isWatch) ? ServiceManager.getService(Context.GAME_SERVICE) : ServiceManager.getServiceOrThrow(Context.GAME_SERVICE); if (binder == null && Compatibility.isChangeEnabled(NULL_GAME_MANAGER_IN_WEAR)) { return null; } return new GameManager( ctx.getOuterContext(), IGameManagerService.Stub.asInterface(binder)); } }); Loading
core/tests/GameManagerTests/src/android/app/GameManagerTests.java +6 −0 Original line number Diff line number Diff line Loading @@ -22,7 +22,10 @@ import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; import static org.junit.Assume.assumeNotNull; import android.content.Context; import android.content.pm.PackageManager; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; Loading @@ -47,6 +50,9 @@ public final class GameManagerTests { public void setUp() { mContext = getInstrumentation().getContext(); mGameManager = mContext.getSystemService(GameManager.class); if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) { assumeNotNull(mGameManager); } mPackageName = mContext.getPackageName(); // Reset the Game Mode for the test app, since it persists across invocations. Loading
services/java/com/android/server/SystemServer.java +7 −3 Original line number Diff line number Diff line Loading @@ -3009,9 +3009,13 @@ public final class SystemServer implements Dumpable { } t.traceEnd(); if (!isWatch || !android.server.Flags.removeGameManagerServiceFromWear()) { t.traceBegin("GameManagerService"); mSystemServiceManager.startService(GameManagerService.Lifecycle.class); t.traceEnd(); } else { Slog.d(TAG, "Not starting GameManagerService"); } if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)) { t.traceBegin("UwbService"); Loading
services/java/com/android/server/flags.aconfig +8 −0 Original line number Diff line number Diff line Loading @@ -36,3 +36,11 @@ flag { description: "Allow NetworkTimeUpdateService on Wear" bug: "327508176" } flag { name: "remove_game_manager_service_from_wear" namespace: "wear_frameworks" description: "Remove GameManagerService from Wear" bug: "340929737" is_fixed_read_only: true } No newline at end of file