Loading core/java/android/app/IGameManagerService.aidl +14 −0 Original line number Original line Diff line number Diff line Loading @@ -19,20 +19,34 @@ package android.app; import android.app.GameModeConfiguration; import android.app.GameModeConfiguration; import android.app.GameModeInfo; import android.app.GameModeInfo; import android.app.GameState; import android.app.GameState; import android.app.IGameModeListener; /** /** * @hide * @hide */ */ interface IGameManagerService { interface IGameManagerService { int getGameMode(String packageName, int userId); int getGameMode(String packageName, int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") void setGameMode(String packageName, int gameMode, int userId); void setGameMode(String packageName, int gameMode, int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") int[] getAvailableGameModes(String packageName); int[] getAvailableGameModes(String packageName); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") boolean isAngleEnabled(String packageName, int userId); boolean isAngleEnabled(String packageName, int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") void notifyGraphicsEnvironmentSetup(String packageName, int userId); void notifyGraphicsEnvironmentSetup(String packageName, int userId); void setGameState(String packageName, in GameState gameState, int userId); void setGameState(String packageName, in GameState gameState, int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") GameModeInfo getGameModeInfo(String packageName, int userId); GameModeInfo getGameModeInfo(String packageName, int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.SET_GAME_SERVICE)") void setGameServiceProvider(String packageName); void setGameServiceProvider(String packageName); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") void updateResolutionScalingFactor(String packageName, int gameMode, float scalingFactor, int userId); void updateResolutionScalingFactor(String packageName, int gameMode, float scalingFactor, int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") float getResolutionScalingFactor(String packageName, int gameMode, int userId); float getResolutionScalingFactor(String packageName, int gameMode, int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") void updateCustomGameModeConfiguration(String packageName, in GameModeConfiguration gameModeConfig, int userId); void updateCustomGameModeConfiguration(String packageName, in GameModeConfiguration gameModeConfig, int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") void addGameModeListener(IGameModeListener gameModeListener); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") void removeGameModeListener(IGameModeListener gameModeListener); } } core/java/android/app/IGameModeListener.aidl 0 → 100644 +25 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.app; /** @hide */ interface IGameModeListener { /** * Called when the game mode of the user has changed. */ void onGameModeChanged(String packageName, int gameModeFrom, int gameModeTo, int userId); } services/core/java/com/android/server/app/GameManagerService.java +71 −1 Original line number Original line Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.app.GameModeConfiguration; import android.app.GameModeInfo; import android.app.GameModeInfo; import android.app.GameState; import android.app.GameState; import android.app.IGameManagerService; import android.app.IGameManagerService; import android.app.IGameModeListener; import android.content.BroadcastReceiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Context; import android.content.Intent; import android.content.Intent; Loading @@ -58,10 +59,12 @@ import android.os.Bundle; import android.os.Environment; import android.os.Environment; import android.os.FileUtils; import android.os.FileUtils; import android.os.Handler; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Looper; import android.os.Message; import android.os.Message; import android.os.PowerManagerInternal; import android.os.PowerManagerInternal; import android.os.Process; import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.ShellCallback; import android.os.UserManager; import android.os.UserManager; Loading Loading @@ -132,6 +135,7 @@ public final class GameManagerService extends IGameManagerService.Stub { private final Context mContext; private final Context mContext; private final Object mLock = new Object(); private final Object mLock = new Object(); private final Object mDeviceConfigLock = new Object(); private final Object mDeviceConfigLock = new Object(); private final Object mGameModeListenerLock = new Object(); @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) final Handler mHandler; final Handler mHandler; private final PackageManager mPackageManager; private final PackageManager mPackageManager; Loading @@ -145,6 +149,9 @@ public final class GameManagerService extends IGameManagerService.Stub { private final ArrayMap<Integer, GameManagerSettings> mSettings = new ArrayMap<>(); private final ArrayMap<Integer, GameManagerSettings> mSettings = new ArrayMap<>(); @GuardedBy("mDeviceConfigLock") @GuardedBy("mDeviceConfigLock") private final ArrayMap<String, GamePackageConfiguration> mConfigs = new ArrayMap<>(); private final ArrayMap<String, GamePackageConfiguration> mConfigs = new ArrayMap<>(); // listener to caller uid map @GuardedBy("mGameModeListenerLock") private final ArrayMap<IGameModeListener, Integer> mGameModeListeners = new ArrayMap<>(); @Nullable @Nullable private final GameServiceController mGameServiceController; private final GameServiceController mGameServiceController; Loading Loading @@ -1102,7 +1109,7 @@ public final class GameManagerService extends IGameManagerService.Stub { // Restrict to games and valid game modes only. // Restrict to games and valid game modes only. return; return; } } int fromGameMode; synchronized (mLock) { synchronized (mLock) { userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, true, "setGameMode", Binder.getCallingUid(), userId, false, true, "setGameMode", Loading @@ -1114,9 +1121,21 @@ public final class GameManagerService extends IGameManagerService.Stub { return; return; } } GameManagerSettings userSettings = mSettings.get(userId); GameManagerSettings userSettings = mSettings.get(userId); fromGameMode = userSettings.getGameModeLocked(packageName); userSettings.setGameModeLocked(packageName, gameMode); userSettings.setGameModeLocked(packageName, gameMode); } } updateInterventions(packageName, gameMode, userId); updateInterventions(packageName, gameMode, userId); synchronized (mGameModeListenerLock) { for (IGameModeListener listener : mGameModeListeners.keySet()) { Binder.allowBlocking(listener.asBinder()); try { listener.onGameModeChanged(packageName, fromGameMode, gameMode, userId); } catch (RemoteException ex) { Slog.w(TAG, "Cannot notify game mode change for listener added by " + mGameModeListeners.get(listener)); } } } sendUserMessage(userId, WRITE_SETTINGS, "SET_GAME_MODE", WRITE_DELAY_MILLIS); sendUserMessage(userId, WRITE_SETTINGS, "SET_GAME_MODE", WRITE_DELAY_MILLIS); sendUserMessage(userId, WRITE_GAME_MODE_INTERVENTION_LIST_FILE, sendUserMessage(userId, WRITE_GAME_MODE_INTERVENTION_LIST_FILE, "SET_GAME_MODE", 0 /*delayMillis*/); "SET_GAME_MODE", 0 /*delayMillis*/); Loading Loading @@ -1341,6 +1360,57 @@ public final class GameManagerService extends IGameManagerService.Stub { + internalConfig.getScaling()); + internalConfig.getScaling()); } } /** * Adds a game mode listener. * * @throws SecurityException if caller doesn't have * {@link android.Manifest.permission#MANAGE_GAME_MODE} * permission. */ @Override @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public void addGameModeListener(@NonNull IGameModeListener listener) { checkPermission(Manifest.permission.MANAGE_GAME_MODE); try { final IBinder listenerBinder = listener.asBinder(); listenerBinder.linkToDeath(new DeathRecipient() { @Override public void binderDied() { // TODO(b/258851194): add traces on binder death based listener removal removeGameModeListenerUnchecked(listener); listenerBinder.unlinkToDeath(this, 0 /*flags*/); } }, 0 /*flags*/); synchronized (mGameModeListenerLock) { mGameModeListeners.put(listener, Binder.getCallingUid()); } } catch (RemoteException ex) { Slog.e(TAG, "Failed to link death recipient for IGameModeListener from caller " + Binder.getCallingUid() + ", abandoned its listener registration", ex); } } /** * Removes a game mode listener. * * @throws SecurityException if caller doesn't have * {@link android.Manifest.permission#MANAGE_GAME_MODE} * permission. */ @Override @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public void removeGameModeListener(@NonNull IGameModeListener listener) { // TODO(b/258851194): add traces on manual listener removal checkPermission(Manifest.permission.MANAGE_GAME_MODE); removeGameModeListenerUnchecked(listener); } private void removeGameModeListenerUnchecked(IGameModeListener listener) { synchronized (mGameModeListenerLock) { mGameModeListeners.remove(listener); } } /** /** * Notified when boot is completed. * Notified when boot is completed. */ */ Loading services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java +56 −0 Original line number Original line Diff line number Diff line Loading @@ -33,6 +33,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.any; import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.when; Loading @@ -43,6 +44,7 @@ import android.app.GameManager; import android.app.GameModeConfiguration; import android.app.GameModeConfiguration; import android.app.GameModeInfo; import android.app.GameModeInfo; import android.app.GameState; import android.app.GameState; import android.app.IGameModeListener; import android.content.BroadcastReceiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Context; import android.content.ContextWrapper; import android.content.ContextWrapper; Loading @@ -57,7 +59,9 @@ import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.content.res.XmlResourceParser; import android.hardware.power.Mode; import android.hardware.power.Mode; import android.os.Bundle; import android.os.Bundle; import android.os.IBinder; import android.os.PowerManagerInternal; import android.os.PowerManagerInternal; import android.os.RemoteException; import android.os.UserManager; import android.os.UserManager; import android.os.test.TestLooper; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.Presubmit; Loading @@ -74,7 +78,9 @@ import org.junit.After; import org.junit.Before; import org.junit.Before; import org.junit.Test; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatchers; import org.mockito.ArgumentMatchers; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.Mockito; import org.mockito.MockitoSession; import org.mockito.MockitoSession; Loading Loading @@ -110,6 +116,9 @@ public class GameManagerServiceTests { private UserManager mMockUserManager; private UserManager mMockUserManager; private BroadcastReceiver mShutDownActionReceiver; private BroadcastReceiver mShutDownActionReceiver; @Captor ArgumentCaptor<IBinder.DeathRecipient> mDeathRecipientCaptor; // Stolen from ConnectivityServiceTest.MockContext // Stolen from ConnectivityServiceTest.MockContext class MockContext extends ContextWrapper { class MockContext extends ContextWrapper { private static final String TAG = "MockContext"; private static final String TAG = "MockContext"; Loading Loading @@ -1874,6 +1883,53 @@ public class GameManagerServiceTests { ArgumentMatchers.eq(0.0f)); ArgumentMatchers.eq(0.0f)); } } @Test public void testAddGameModeListener() throws RemoteException { GameManagerService gameManagerService = new GameManagerService(mMockContext, mTestLooper.getLooper()); mockDeviceConfigAll(); startUser(gameManagerService, USER_ID_1); mockModifyGameModeGranted(); IGameModeListener mockListener = Mockito.mock(IGameModeListener.class); IBinder binder = Mockito.mock(IBinder.class); when(mockListener.asBinder()).thenReturn(binder); gameManagerService.addGameModeListener(mockListener); verify(binder).linkToDeath(mDeathRecipientCaptor.capture(), anyInt()); gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1); verify(mockListener).onGameModeChanged(mPackageName, GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1); reset(mockListener); gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1); verify(mockListener).onGameModeChanged(mPackageName, GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_BATTERY, USER_ID_1); reset(mockListener); mDeathRecipientCaptor.getValue().binderDied(); verify(binder).unlinkToDeath(eq(mDeathRecipientCaptor.getValue()), anyInt()); gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_CUSTOM, USER_ID_1); verify(mockListener, never()).onGameModeChanged(anyString(), anyInt(), anyInt(), anyInt()); } @Test public void testRemoveGameModeListener() throws RemoteException { GameManagerService gameManagerService = new GameManagerService(mMockContext, mTestLooper.getLooper()); mockDeviceConfigAll(); startUser(gameManagerService, USER_ID_1); mockModifyGameModeGranted(); IGameModeListener mockListener = Mockito.mock(IGameModeListener.class); IBinder binder = Mockito.mock(IBinder.class); when(mockListener.asBinder()).thenReturn(binder); gameManagerService.addGameModeListener(mockListener); gameManagerService.removeGameModeListener(mockListener); gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1); verify(mockListener, never()).onGameModeChanged(anyString(), anyInt(), anyInt(), anyInt()); } private static void deleteFolder(File folder) { private static void deleteFolder(File folder) { File[] files = folder.listFiles(); File[] files = folder.listFiles(); if (files != null) { if (files != null) { Loading Loading
core/java/android/app/IGameManagerService.aidl +14 −0 Original line number Original line Diff line number Diff line Loading @@ -19,20 +19,34 @@ package android.app; import android.app.GameModeConfiguration; import android.app.GameModeConfiguration; import android.app.GameModeInfo; import android.app.GameModeInfo; import android.app.GameState; import android.app.GameState; import android.app.IGameModeListener; /** /** * @hide * @hide */ */ interface IGameManagerService { interface IGameManagerService { int getGameMode(String packageName, int userId); int getGameMode(String packageName, int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") void setGameMode(String packageName, int gameMode, int userId); void setGameMode(String packageName, int gameMode, int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") int[] getAvailableGameModes(String packageName); int[] getAvailableGameModes(String packageName); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") boolean isAngleEnabled(String packageName, int userId); boolean isAngleEnabled(String packageName, int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") void notifyGraphicsEnvironmentSetup(String packageName, int userId); void notifyGraphicsEnvironmentSetup(String packageName, int userId); void setGameState(String packageName, in GameState gameState, int userId); void setGameState(String packageName, in GameState gameState, int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") GameModeInfo getGameModeInfo(String packageName, int userId); GameModeInfo getGameModeInfo(String packageName, int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.SET_GAME_SERVICE)") void setGameServiceProvider(String packageName); void setGameServiceProvider(String packageName); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") void updateResolutionScalingFactor(String packageName, int gameMode, float scalingFactor, int userId); void updateResolutionScalingFactor(String packageName, int gameMode, float scalingFactor, int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") float getResolutionScalingFactor(String packageName, int gameMode, int userId); float getResolutionScalingFactor(String packageName, int gameMode, int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") void updateCustomGameModeConfiguration(String packageName, in GameModeConfiguration gameModeConfig, int userId); void updateCustomGameModeConfiguration(String packageName, in GameModeConfiguration gameModeConfig, int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") void addGameModeListener(IGameModeListener gameModeListener); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)") void removeGameModeListener(IGameModeListener gameModeListener); } }
core/java/android/app/IGameModeListener.aidl 0 → 100644 +25 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.app; /** @hide */ interface IGameModeListener { /** * Called when the game mode of the user has changed. */ void onGameModeChanged(String packageName, int gameModeFrom, int gameModeTo, int userId); }
services/core/java/com/android/server/app/GameManagerService.java +71 −1 Original line number Original line Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.app.GameModeConfiguration; import android.app.GameModeInfo; import android.app.GameModeInfo; import android.app.GameState; import android.app.GameState; import android.app.IGameManagerService; import android.app.IGameManagerService; import android.app.IGameModeListener; import android.content.BroadcastReceiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Context; import android.content.Intent; import android.content.Intent; Loading @@ -58,10 +59,12 @@ import android.os.Bundle; import android.os.Environment; import android.os.Environment; import android.os.FileUtils; import android.os.FileUtils; import android.os.Handler; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Looper; import android.os.Message; import android.os.Message; import android.os.PowerManagerInternal; import android.os.PowerManagerInternal; import android.os.Process; import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.ShellCallback; import android.os.UserManager; import android.os.UserManager; Loading Loading @@ -132,6 +135,7 @@ public final class GameManagerService extends IGameManagerService.Stub { private final Context mContext; private final Context mContext; private final Object mLock = new Object(); private final Object mLock = new Object(); private final Object mDeviceConfigLock = new Object(); private final Object mDeviceConfigLock = new Object(); private final Object mGameModeListenerLock = new Object(); @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) final Handler mHandler; final Handler mHandler; private final PackageManager mPackageManager; private final PackageManager mPackageManager; Loading @@ -145,6 +149,9 @@ public final class GameManagerService extends IGameManagerService.Stub { private final ArrayMap<Integer, GameManagerSettings> mSettings = new ArrayMap<>(); private final ArrayMap<Integer, GameManagerSettings> mSettings = new ArrayMap<>(); @GuardedBy("mDeviceConfigLock") @GuardedBy("mDeviceConfigLock") private final ArrayMap<String, GamePackageConfiguration> mConfigs = new ArrayMap<>(); private final ArrayMap<String, GamePackageConfiguration> mConfigs = new ArrayMap<>(); // listener to caller uid map @GuardedBy("mGameModeListenerLock") private final ArrayMap<IGameModeListener, Integer> mGameModeListeners = new ArrayMap<>(); @Nullable @Nullable private final GameServiceController mGameServiceController; private final GameServiceController mGameServiceController; Loading Loading @@ -1102,7 +1109,7 @@ public final class GameManagerService extends IGameManagerService.Stub { // Restrict to games and valid game modes only. // Restrict to games and valid game modes only. return; return; } } int fromGameMode; synchronized (mLock) { synchronized (mLock) { userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, true, "setGameMode", Binder.getCallingUid(), userId, false, true, "setGameMode", Loading @@ -1114,9 +1121,21 @@ public final class GameManagerService extends IGameManagerService.Stub { return; return; } } GameManagerSettings userSettings = mSettings.get(userId); GameManagerSettings userSettings = mSettings.get(userId); fromGameMode = userSettings.getGameModeLocked(packageName); userSettings.setGameModeLocked(packageName, gameMode); userSettings.setGameModeLocked(packageName, gameMode); } } updateInterventions(packageName, gameMode, userId); updateInterventions(packageName, gameMode, userId); synchronized (mGameModeListenerLock) { for (IGameModeListener listener : mGameModeListeners.keySet()) { Binder.allowBlocking(listener.asBinder()); try { listener.onGameModeChanged(packageName, fromGameMode, gameMode, userId); } catch (RemoteException ex) { Slog.w(TAG, "Cannot notify game mode change for listener added by " + mGameModeListeners.get(listener)); } } } sendUserMessage(userId, WRITE_SETTINGS, "SET_GAME_MODE", WRITE_DELAY_MILLIS); sendUserMessage(userId, WRITE_SETTINGS, "SET_GAME_MODE", WRITE_DELAY_MILLIS); sendUserMessage(userId, WRITE_GAME_MODE_INTERVENTION_LIST_FILE, sendUserMessage(userId, WRITE_GAME_MODE_INTERVENTION_LIST_FILE, "SET_GAME_MODE", 0 /*delayMillis*/); "SET_GAME_MODE", 0 /*delayMillis*/); Loading Loading @@ -1341,6 +1360,57 @@ public final class GameManagerService extends IGameManagerService.Stub { + internalConfig.getScaling()); + internalConfig.getScaling()); } } /** * Adds a game mode listener. * * @throws SecurityException if caller doesn't have * {@link android.Manifest.permission#MANAGE_GAME_MODE} * permission. */ @Override @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public void addGameModeListener(@NonNull IGameModeListener listener) { checkPermission(Manifest.permission.MANAGE_GAME_MODE); try { final IBinder listenerBinder = listener.asBinder(); listenerBinder.linkToDeath(new DeathRecipient() { @Override public void binderDied() { // TODO(b/258851194): add traces on binder death based listener removal removeGameModeListenerUnchecked(listener); listenerBinder.unlinkToDeath(this, 0 /*flags*/); } }, 0 /*flags*/); synchronized (mGameModeListenerLock) { mGameModeListeners.put(listener, Binder.getCallingUid()); } } catch (RemoteException ex) { Slog.e(TAG, "Failed to link death recipient for IGameModeListener from caller " + Binder.getCallingUid() + ", abandoned its listener registration", ex); } } /** * Removes a game mode listener. * * @throws SecurityException if caller doesn't have * {@link android.Manifest.permission#MANAGE_GAME_MODE} * permission. */ @Override @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public void removeGameModeListener(@NonNull IGameModeListener listener) { // TODO(b/258851194): add traces on manual listener removal checkPermission(Manifest.permission.MANAGE_GAME_MODE); removeGameModeListenerUnchecked(listener); } private void removeGameModeListenerUnchecked(IGameModeListener listener) { synchronized (mGameModeListenerLock) { mGameModeListeners.remove(listener); } } /** /** * Notified when boot is completed. * Notified when boot is completed. */ */ Loading
services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java +56 −0 Original line number Original line Diff line number Diff line Loading @@ -33,6 +33,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.any; import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.when; Loading @@ -43,6 +44,7 @@ import android.app.GameManager; import android.app.GameModeConfiguration; import android.app.GameModeConfiguration; import android.app.GameModeInfo; import android.app.GameModeInfo; import android.app.GameState; import android.app.GameState; import android.app.IGameModeListener; import android.content.BroadcastReceiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Context; import android.content.ContextWrapper; import android.content.ContextWrapper; Loading @@ -57,7 +59,9 @@ import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.content.res.XmlResourceParser; import android.hardware.power.Mode; import android.hardware.power.Mode; import android.os.Bundle; import android.os.Bundle; import android.os.IBinder; import android.os.PowerManagerInternal; import android.os.PowerManagerInternal; import android.os.RemoteException; import android.os.UserManager; import android.os.UserManager; import android.os.test.TestLooper; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.Presubmit; Loading @@ -74,7 +78,9 @@ import org.junit.After; import org.junit.Before; import org.junit.Before; import org.junit.Test; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatchers; import org.mockito.ArgumentMatchers; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.Mockito; import org.mockito.MockitoSession; import org.mockito.MockitoSession; Loading Loading @@ -110,6 +116,9 @@ public class GameManagerServiceTests { private UserManager mMockUserManager; private UserManager mMockUserManager; private BroadcastReceiver mShutDownActionReceiver; private BroadcastReceiver mShutDownActionReceiver; @Captor ArgumentCaptor<IBinder.DeathRecipient> mDeathRecipientCaptor; // Stolen from ConnectivityServiceTest.MockContext // Stolen from ConnectivityServiceTest.MockContext class MockContext extends ContextWrapper { class MockContext extends ContextWrapper { private static final String TAG = "MockContext"; private static final String TAG = "MockContext"; Loading Loading @@ -1874,6 +1883,53 @@ public class GameManagerServiceTests { ArgumentMatchers.eq(0.0f)); ArgumentMatchers.eq(0.0f)); } } @Test public void testAddGameModeListener() throws RemoteException { GameManagerService gameManagerService = new GameManagerService(mMockContext, mTestLooper.getLooper()); mockDeviceConfigAll(); startUser(gameManagerService, USER_ID_1); mockModifyGameModeGranted(); IGameModeListener mockListener = Mockito.mock(IGameModeListener.class); IBinder binder = Mockito.mock(IBinder.class); when(mockListener.asBinder()).thenReturn(binder); gameManagerService.addGameModeListener(mockListener); verify(binder).linkToDeath(mDeathRecipientCaptor.capture(), anyInt()); gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1); verify(mockListener).onGameModeChanged(mPackageName, GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1); reset(mockListener); gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1); verify(mockListener).onGameModeChanged(mPackageName, GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_BATTERY, USER_ID_1); reset(mockListener); mDeathRecipientCaptor.getValue().binderDied(); verify(binder).unlinkToDeath(eq(mDeathRecipientCaptor.getValue()), anyInt()); gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_CUSTOM, USER_ID_1); verify(mockListener, never()).onGameModeChanged(anyString(), anyInt(), anyInt(), anyInt()); } @Test public void testRemoveGameModeListener() throws RemoteException { GameManagerService gameManagerService = new GameManagerService(mMockContext, mTestLooper.getLooper()); mockDeviceConfigAll(); startUser(gameManagerService, USER_ID_1); mockModifyGameModeGranted(); IGameModeListener mockListener = Mockito.mock(IGameModeListener.class); IBinder binder = Mockito.mock(IBinder.class); when(mockListener.asBinder()).thenReturn(binder); gameManagerService.addGameModeListener(mockListener); gameManagerService.removeGameModeListener(mockListener); gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1); verify(mockListener, never()).onGameModeChanged(anyString(), anyInt(), anyInt(), anyInt()); } private static void deleteFolder(File folder) { private static void deleteFolder(File folder) { File[] files = folder.listFiles(); File[] files = folder.listFiles(); if (files != null) { if (files != null) { Loading