summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Andy Yu <chingtangyu@google.com> 2023-11-13 14:39:21 -0800
committer Andy Yu <chingtangyu@google.com> 2023-12-11 10:25:45 -0800
commit6e4cd761e8ec4302e30550bf7615f1d49cf987db (patch)
treed4706efda312fd3b563a2f54432c7f4f7ec24708
parentfce39f1443b1348c5c36951d165f56f99ca1fee4 (diff)
Add Game Default Frame Rate calls
Update Game mode intervention frame rate override and add game default frame rate override JNI calls to SurfaceFlinger. Game default frame rate depends on two sysprops: To determine if it's enabled: 1) persist.graphics.game_default_frame_rate.enabled To determine the default frame rate value: 2) ro.surface_flinger.game_default_frame_rate_override This change adds setGameDefaultFrameRateOverride to call into SurfaceFlinger. Meanwhile it also changes the original override call to setGameModeFrameRateOverride to differenitate between those two calls. Bug: 286084594 Test: atest GameManagerServiceTests Change-Id: I68f93e79fda5457303b49d0bd8f0edbb14e01b3f
-rw-r--r--AconfigFlags.bp14
-rw-r--r--core/java/android/app/IGameManagerService.aidl2
-rw-r--r--services/core/java/com/android/server/app/GameManagerService.java120
-rw-r--r--services/core/java/com/android/server/app/GameManagerServiceSystemPropertiesWrapper.java67
-rw-r--r--services/core/java/com/android/server/app/flags.aconfig9
-rw-r--r--services/core/jni/com_android_server_app_GameManagerService.cpp18
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java173
7 files changed, 374 insertions, 29 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 904109b569b8..2e086b39d950 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -26,6 +26,7 @@ aconfig_srcjars = [
":android.os.flags-aconfig-java{.generated_srcjars}",
":android.os.vibrator.flags-aconfig-java{.generated_srcjars}",
":android.security.flags-aconfig-java{.generated_srcjars}",
+ ":android.server.app.flags-aconfig-java{.generated_srcjars}",
":android.service.chooser.flags-aconfig-java{.generated_srcjars}",
":android.service.notification.flags-aconfig-java{.generated_srcjars}",
":android.view.flags-aconfig-java{.generated_srcjars}",
@@ -834,6 +835,19 @@ java_aconfig_library {
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+// App
+aconfig_declarations {
+ name: "android.server.app.flags-aconfig",
+ package: "android.server.app",
+ srcs: ["services/core/java/com/android/server/app/flags.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.server.app.flags-aconfig-java",
+ aconfig_declarations: "android.server.app.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
// WebView
aconfig_declarations {
name: "android.webkit.flags-aconfig",
diff --git a/core/java/android/app/IGameManagerService.aidl b/core/java/android/app/IGameManagerService.aidl
index 9a818e49ae4a..bfec9430fd58 100644
--- a/core/java/android/app/IGameManagerService.aidl
+++ b/core/java/android/app/IGameManagerService.aidl
@@ -52,4 +52,6 @@ interface IGameManagerService {
void removeGameModeListener(IGameModeListener gameModeListener);
void addGameStateListener(IGameStateListener gameStateListener);
void removeGameStateListener(IGameStateListener gameStateListener);
+ @EnforcePermission("MANAGE_GAME_MODE")
+ void toggleGameDefaultFrameRate(boolean isEnabled);
}
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 824bdd4ccb79..b1825380bbdc 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -19,6 +19,7 @@ package com.android.server.app;
import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static android.content.Intent.EXTRA_REPLACING;
+import static android.server.app.Flags.gameDefaultFrameRate;
import static com.android.internal.R.styleable.GameModeConfig_allowGameAngleDriver;
import static com.android.internal.R.styleable.GameModeConfig_allowGameDownscaling;
@@ -28,6 +29,7 @@ import static com.android.internal.R.styleable.GameModeConfig_supportsPerformanc
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import android.Manifest;
+import android.annotation.EnforcePermission;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -66,11 +68,13 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.PermissionEnforcer;
import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
+import android.os.SystemProperties;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
@@ -138,12 +142,17 @@ public final class GameManagerService extends IGameManagerService.Stub {
static final int WRITE_GAME_MODE_INTERVENTION_LIST_FILE = 6;
static final int WRITE_DELAY_MILLIS = 10 * 1000; // 10 seconds
static final int LOADING_BOOST_MAX_DURATION = 5 * 1000; // 5 seconds
+ static final String PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED =
+ "persist.graphics.game_default_frame_rate.enabled";
+ static final String PROPERTY_RO_SURFACEFLINGER_GAME_DEFAULT_FRAME_RATE =
+ "ro.surface_flinger.game_default_frame_rate_override";
private static final String PACKAGE_NAME_MSG_KEY = "packageName";
private static final String USER_ID_MSG_KEY = "userId";
private static final String GAME_MODE_INTERVENTION_LIST_FILE_NAME =
"game_mode_intervention.list";
+
private final Context mContext;
private final Object mLock = new Object();
private final Object mDeviceConfigLock = new Object();
@@ -154,7 +163,6 @@ public final class GameManagerService extends IGameManagerService.Stub {
private final PackageManager mPackageManager;
private final UserManager mUserManager;
private final PowerManagerInternal mPowerManagerInternal;
- private final File mSystemDir;
@VisibleForTesting
final AtomicFile mGameModeInterventionListFile;
private DeviceConfigListener mDeviceConfigListener;
@@ -175,28 +183,56 @@ public final class GameManagerService extends IGameManagerService.Stub {
final MyUidObserver mUidObserver;
@GuardedBy("mUidObserverLock")
private final Set<Integer> mForegroundGameUids = new HashSet<>();
+ private final GameManagerServiceSystemPropertiesWrapper mSysProps;
+
+ @VisibleForTesting
+ static class Injector {
+ public GameManagerServiceSystemPropertiesWrapper createSystemPropertiesWrapper() {
+ return new GameManagerServiceSystemPropertiesWrapper() {
+ @Override
+ public String get(String key, String def) {
+ return SystemProperties.get(key, def);
+ }
+ @Override
+ public boolean getBoolean(String key, boolean def) {
+ return SystemProperties.getBoolean(key, def);
+ }
+
+ @Override
+ public int getInt(String key, int def) {
+ return SystemProperties.getInt(key, def);
+ }
+
+ @Override
+ public void set(String key, String val) {
+ SystemProperties.set(key, val);
+ }
+ };
+ }
+ }
public GameManagerService(Context context) {
this(context, createServiceThread().getLooper());
}
GameManagerService(Context context, Looper looper) {
- this(context, looper, Environment.getDataDirectory());
+ this(context, looper, Environment.getDataDirectory(), new Injector());
}
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- GameManagerService(Context context, Looper looper, File dataDir) {
+ GameManagerService(Context context, Looper looper, File dataDir, Injector injector) {
+ super(PermissionEnforcer.fromContext(context));
mContext = context;
mHandler = new SettingsHandler(looper);
mPackageManager = mContext.getPackageManager();
mUserManager = mContext.getSystemService(UserManager.class);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
- mSystemDir = new File(dataDir, "system");
- mSystemDir.mkdirs();
- FileUtils.setPermissions(mSystemDir.toString(),
+ File systemDir = new File(dataDir, "system");
+ systemDir.mkdirs();
+ FileUtils.setPermissions(systemDir.toString(),
FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH,
-1, -1);
- mGameModeInterventionListFile = new AtomicFile(new File(mSystemDir,
+ mGameModeInterventionListFile = new AtomicFile(new File(systemDir,
GAME_MODE_INTERVENTION_LIST_FILE_NAME));
FileUtils.setPermissions(mGameModeInterventionListFile.getBaseFile().getAbsolutePath(),
FileUtils.S_IRUSR | FileUtils.S_IWUSR
@@ -220,6 +256,8 @@ public final class GameManagerService extends IGameManagerService.Stub {
} catch (RemoteException e) {
Slog.w(TAG, "Could not register UidObserver");
}
+
+ mSysProps = injector.createSystemPropertiesWrapper();
}
@Override
@@ -1588,7 +1626,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
try {
final float fps = 0.0f;
final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
- setOverrideFrameRate(uid, fps);
+ setGameModeFrameRateOverride(uid, fps);
} catch (PackageManager.NameNotFoundException e) {
return;
}
@@ -1620,7 +1658,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
try {
final float fps = modeConfig.getFps();
final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
- setOverrideFrameRate(uid, fps);
+ setGameModeFrameRateOverride(uid, fps);
} catch (PackageManager.NameNotFoundException e) {
return;
}
@@ -2159,14 +2197,70 @@ public final class GameManagerService extends IGameManagerService.Stub {
}
@VisibleForTesting
- void setOverrideFrameRate(int uid, float frameRate) {
- nativeSetOverrideFrameRate(uid, frameRate);
+ void setGameModeFrameRateOverride(int uid, float frameRate) {
+ nativeSetGameModeFrameRateOverride(uid, frameRate);
+ }
+
+ @VisibleForTesting
+ void setGameDefaultFrameRateOverride(int uid, float frameRate) {
+ Slog.v(TAG, "setDefaultFrameRateOverride : " + uid + " , " + frameRate);
+ nativeSetGameDefaultFrameRateOverride(uid, frameRate);
+ }
+
+ private float getGameDefaultFrameRate() {
+ final boolean isGameDefaultFrameRateEnabled;
+ float gameDefaultFrameRate = 0.0f;
+ synchronized (mLock) {
+ isGameDefaultFrameRateEnabled =
+ mSysProps.getBoolean(
+ PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED, true);
+ }
+ if (gameDefaultFrameRate()) {
+ gameDefaultFrameRate = isGameDefaultFrameRateEnabled
+ ? (float) mSysProps.getInt(
+ PROPERTY_RO_SURFACEFLINGER_GAME_DEFAULT_FRAME_RATE, 0) : 0.0f;
+ }
+ return gameDefaultFrameRate;
+ }
+
+ @Override
+ @EnforcePermission(Manifest.permission.MANAGE_GAME_MODE)
+ public void toggleGameDefaultFrameRate(boolean isEnabled) {
+ toggleGameDefaultFrameRate_enforcePermission();
+ if (gameDefaultFrameRate()) {
+ Slog.v(TAG, "toggleGameDefaultFrameRate : " + isEnabled);
+ this.toggleGameDefaultFrameRateUnchecked(isEnabled);
+ }
+ }
+
+ private void toggleGameDefaultFrameRateUnchecked(boolean isEnabled) {
+ // Update system properties.
+ // Here we only need to immediately update games that are in the foreground.
+ // We will update game default frame rate when a game comes into foreground in
+ // MyUidObserver.
+ synchronized (mLock) {
+ if (isEnabled) {
+ mSysProps.set(
+ PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED, "true");
+ } else {
+ mSysProps.set(
+ PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED, "false");
+ }
+ }
+
+ // Update all foreground games' frame rate.
+ synchronized (mUidObserverLock) {
+ for (int uid : mForegroundGameUids) {
+ setGameDefaultFrameRateOverride(uid, getGameDefaultFrameRate());
+ }
+ }
}
/**
* load dynamic library for frame rate overriding JNI calls
*/
- private static native void nativeSetOverrideFrameRate(int uid, float frameRate);
+ private static native void nativeSetGameModeFrameRateOverride(int uid, float frameRate);
+ private static native void nativeSetGameDefaultFrameRateOverride(int uid, float frameRate);
final class MyUidObserver extends UidObserver {
@Override
@@ -2179,6 +2273,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
@Override
public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
synchronized (mUidObserverLock) {
+
if (procState != ActivityManager.PROCESS_STATE_TOP) {
disableGameMode(uid);
return;
@@ -2198,6 +2293,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
Slog.v(TAG, "Game power mode ON (process state was changed to foreground)");
mPowerManagerInternal.setPowerMode(Mode.GAME, true);
}
+ setGameDefaultFrameRateOverride(uid, getGameDefaultFrameRate());
mForegroundGameUids.add(uid);
}
}
diff --git a/services/core/java/com/android/server/app/GameManagerServiceSystemPropertiesWrapper.java b/services/core/java/com/android/server/app/GameManagerServiceSystemPropertiesWrapper.java
new file mode 100644
index 000000000000..afacedaac11b
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameManagerServiceSystemPropertiesWrapper.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 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 com.android.server.app;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.SystemProperties;
+/**
+ * Wrapper interface to access {@link SystemProperties}.
+ *
+ * @hide
+ */
+interface GameManagerServiceSystemPropertiesWrapper {
+ /**
+ * Get the String value for the given {@code key}.
+ *
+ * @param key the key to lookup
+ * @param def the default value in case the property is not set or empty
+ * @return if the {@code key} isn't found, return {@code def} if it isn't null, or an empty
+ * string otherwise
+ */
+ @NonNull
+ String get(@NonNull String key, @Nullable String def);
+ /**
+ * Get the Boolean value for the given {@code key}.
+ *
+ * @param key the key to lookup
+ * @param def the default value in case the property is not set or empty
+ * @return if the {@code key} isn't found, return {@code def} if it isn't null, not parsable
+ * or an empty string otherwise
+ */
+ @NonNull
+ boolean getBoolean(@NonNull String key, boolean def);
+
+ /**
+ * Get the Integer value for the given {@code key}.
+ *
+ * @param key the key to lookup
+ * @param def the default value in case the property is not set or empty
+ * @return if the {@code key} isn't found, return {@code def} if it isn't null, not parsable
+ * or an empty string otherwise
+ */
+ @NonNull
+ int getInt(@NonNull String key, int def);
+ /**
+ * Set the value for the given {@code key} to {@code val}.
+ *
+ * @throws IllegalArgumentException if the {@code val} exceeds 91 characters
+ * @throws RuntimeException if the property cannot be set, for example, if it was blocked by
+ * SELinux. libc will log the underlying reason.
+ */
+ void set(@NonNull String key, @Nullable String val);
+}
diff --git a/services/core/java/com/android/server/app/flags.aconfig b/services/core/java/com/android/server/app/flags.aconfig
new file mode 100644
index 000000000000..f2e4783bd9eb
--- /dev/null
+++ b/services/core/java/com/android/server/app/flags.aconfig
@@ -0,0 +1,9 @@
+package: "android.server.app"
+
+flag {
+ name: "game_default_frame_rate"
+ namespace: "game"
+ description: "This flag guards the new behavior with the addition of Game Default Frame Rate feature."
+ bug: "286084594"
+ is_fixed_read_only: true
+} \ No newline at end of file
diff --git a/services/core/jni/com_android_server_app_GameManagerService.cpp b/services/core/jni/com_android_server_app_GameManagerService.cpp
index 3028813d0d5a..f593f4077365 100644
--- a/services/core/jni/com_android_server_app_GameManagerService.cpp
+++ b/services/core/jni/com_android_server_app_GameManagerService.cpp
@@ -25,15 +25,21 @@
namespace android {
-static void android_server_app_GameManagerService_nativeSetOverrideFrameRate(JNIEnv* env,
- jclass clazz, jint uid,
- jfloat frameRate) {
- SurfaceComposerClient::setOverrideFrameRate(uid, frameRate);
+static void android_server_app_GameManagerService_nativeSetGameModeFrameRateOverride(
+ JNIEnv* env, jclass clazz, jint uid, jfloat frameRate) {
+ SurfaceComposerClient::setGameModeFrameRateOverride(uid, frameRate);
+}
+
+static void android_server_app_GameManagerService_nativeSetGameDefaultFrameRateOverride(
+ JNIEnv* env, jclass clazz, jint uid, jfloat frameRate) {
+ SurfaceComposerClient::setGameDefaultFrameRateOverride(uid, frameRate);
}
static const JNINativeMethod gMethods[] = {
- {"nativeSetOverrideFrameRate", "(IF)V",
- (void*)android_server_app_GameManagerService_nativeSetOverrideFrameRate},
+ {"nativeSetGameModeFrameRateOverride", "(IF)V",
+ (void*)android_server_app_GameManagerService_nativeSetGameModeFrameRateOverride},
+ {"nativeSetGameDefaultFrameRateOverride", "(IF)V",
+ (void*)android_server_app_GameManagerService_nativeSetGameDefaultFrameRateOverride},
};
int register_android_server_app_GameManagerService(JNIEnv* env) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index 6906decec9a2..76d4d55f4d5d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -18,7 +18,10 @@ package com.android.server.app;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.server.app.GameManagerService.CANCEL_GAME_LOADING_MODE;
+import static com.android.server.app.GameManagerService.Injector;
import static com.android.server.app.GameManagerService.LOADING_BOOST_MAX_DURATION;
+import static com.android.server.app.GameManagerService.PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED;
+import static com.android.server.app.GameManagerService.PROPERTY_RO_SURFACEFLINGER_GAME_DEFAULT_FRAME_RATE;
import static com.android.server.app.GameManagerService.SET_GAME_STATE;
import static com.android.server.app.GameManagerService.WRITE_DELAY_MILLIS;
import static com.android.server.app.GameManagerService.WRITE_GAME_MODE_INTERVENTION_LIST_FILE;
@@ -33,6 +36,7 @@ import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.any;
@@ -72,9 +76,12 @@ import android.os.IBinder;
import android.os.PowerManagerInternal;
import android.os.RemoteException;
import android.os.UserManager;
+import android.os.test.FakePermissionEnforcer;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.DeviceConfig;
+import android.server.app.Flags;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -85,6 +92,7 @@ import com.android.server.SystemService;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -108,6 +116,7 @@ import java.util.function.Supplier;
@Presubmit
public class GameManagerServiceTests {
@Mock MockContext mMockContext;
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final String TAG = "GameManagerServiceTests";
private static final String PACKAGE_NAME_INVALID = "com.android.app";
private static final int USER_ID_1 = 1001;
@@ -126,6 +135,11 @@ public class GameManagerServiceTests {
private UserManager mMockUserManager;
private BroadcastReceiver mShutDownActionReceiver;
+ private FakePermissionEnforcer mFakePermissionEnforcer = new FakePermissionEnforcer();
+
+ @Mock
+ private GameManagerServiceSystemPropertiesWrapper mSysPropsMock;
+
@Captor
ArgumentCaptor<IBinder.DeathRecipient> mDeathRecipientCaptor;
@@ -193,6 +207,8 @@ public class GameManagerServiceTests {
switch (name) {
case Context.USER_SERVICE:
return mMockUserManager;
+ case Context.PERMISSION_ENFORCER_SERVICE:
+ return mFakePermissionEnforcer;
}
throw new UnsupportedOperationException("Couldn't find system service: " + name);
}
@@ -222,6 +238,8 @@ public class GameManagerServiceTests {
when(mMockPackageManager.getPackageUidAsUser(mPackageName, USER_ID_1)).thenReturn(
DEFAULT_PACKAGE_UID);
LocalServices.addService(PowerManagerInternal.class, mMockPowerManager);
+
+ mSetFlagsRule.enableFlags(Flags.FLAG_GAME_DEFAULT_FRAME_RATE);
}
private void mockAppCategory(String packageName, @ApplicationInfo.Category int category)
@@ -1695,9 +1713,8 @@ public class GameManagerServiceTests {
mockModifyGameModeGranted();
final Context context = InstrumentationRegistry.getContext();
GameManagerService gameManagerService =
- new GameManagerService(mMockContext,
- mTestLooper.getLooper(),
- context.getFilesDir());
+ new GameManagerService(mMockContext, mTestLooper.getLooper(), context.getFilesDir(),
+ new Injector());
startUser(gameManagerService, USER_ID_1);
startUser(gameManagerService, USER_ID_2);
@@ -1786,7 +1803,7 @@ public class GameManagerServiceTests {
mockDeviceConfigBattery();
final Context context = InstrumentationRegistry.getContext();
GameManagerService gameManagerService = new GameManagerService(mMockContext,
- mTestLooper.getLooper(), context.getFilesDir());
+ mTestLooper.getLooper(), context.getFilesDir(), new Injector());
startUser(gameManagerService, USER_ID_1);
startUser(gameManagerService, USER_ID_2);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1);
@@ -1962,7 +1979,7 @@ public class GameManagerServiceTests {
assertTrue(
gameManagerService.mHandler.hasEqualMessages(WRITE_GAME_MODE_INTERVENTION_LIST_FILE,
USER_ID_1));
- Mockito.verify(gameManagerService).setOverrideFrameRate(
+ Mockito.verify(gameManagerService).setGameModeFrameRateOverride(
ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
ArgumentMatchers.eq(60.0f));
checkFps(gameManagerService, GameManager.GAME_MODE_CUSTOM, 60);
@@ -2035,7 +2052,7 @@ public class GameManagerServiceTests {
mTestLooper.getLooper()));
startUser(gameManagerService, USER_ID_1);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
- Mockito.verify(gameManagerService).setOverrideFrameRate(
+ Mockito.verify(gameManagerService).setGameModeFrameRateOverride(
ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
ArgumentMatchers.eq(90.0f));
checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90);
@@ -2044,7 +2061,7 @@ public class GameManagerServiceTests {
when(DeviceConfig.getProperty(anyString(), anyString()))
.thenReturn(configStringAfter);
gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName);
- Mockito.verify(gameManagerService).setOverrideFrameRate(
+ Mockito.verify(gameManagerService).setGameModeFrameRateOverride(
ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
ArgumentMatchers.eq(0.0f));
}
@@ -2061,14 +2078,14 @@ public class GameManagerServiceTests {
mTestLooper.getLooper()));
startUser(gameManagerService, USER_ID_1);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
- Mockito.verify(gameManagerService).setOverrideFrameRate(
+ Mockito.verify(gameManagerService).setGameModeFrameRateOverride(
ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
ArgumentMatchers.eq(90.0f));
checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90);
mockInterventionsDisabledNoOptInFromXml();
gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName);
- Mockito.verify(gameManagerService).setOverrideFrameRate(
+ Mockito.verify(gameManagerService).setGameModeFrameRateOverride(
ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
ArgumentMatchers.eq(0.0f));
checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0);
@@ -2087,14 +2104,14 @@ public class GameManagerServiceTests {
startUser(gameManagerService, USER_ID_1);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
- Mockito.verify(gameManagerService).setOverrideFrameRate(
+ Mockito.verify(gameManagerService).setGameModeFrameRateOverride(
ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
ArgumentMatchers.eq(90.0f));
checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90);
mockInterventionsEnabledAllOptInFromXml();
gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName);
- Mockito.verify(gameManagerService).setOverrideFrameRate(
+ Mockito.verify(gameManagerService).setGameModeFrameRateOverride(
ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
ArgumentMatchers.eq(0.0f));
}
@@ -2390,4 +2407,138 @@ public class GameManagerServiceTests {
DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
verify(mMockPowerManager, times(0)).setPowerMode(Mode.GAME, false);
}
+
+ @Test
+ public void testGameDefaultFrameRate_FlagOn() throws Exception {
+ mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_GAME_MODE);
+
+ GameManagerService gameManagerService = Mockito.spy(
+ new GameManagerService(mMockContext, mTestLooper.getLooper(),
+ InstrumentationRegistry.getContext().getFilesDir(),
+ new Injector(){
+ @Override
+ public GameManagerServiceSystemPropertiesWrapper
+ createSystemPropertiesWrapper() {
+ return mSysPropsMock;
+ }
+ }));
+
+ // Set up a game in the foreground.
+ String[] packages = {mPackageName};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TOP, 0, 0);
+
+ // Toggle game default frame rate on.
+ when(mSysPropsMock.getInt(
+ ArgumentMatchers.eq(PROPERTY_RO_SURFACEFLINGER_GAME_DEFAULT_FRAME_RATE),
+ anyInt())).thenReturn(60);
+ when(mSysPropsMock.getBoolean(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ ArgumentMatchers.eq(true))).thenReturn(true);
+ gameManagerService.toggleGameDefaultFrameRate(true);
+
+ // Verify that:
+ // 1) The system property is set correctly
+ // 2) setDefaultFrameRateOverride is called with correct arguments
+ Mockito.verify(mSysPropsMock).set(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ ArgumentMatchers.eq("true"));
+ Mockito.verify(gameManagerService, times(1))
+ .setGameDefaultFrameRateOverride(ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
+ ArgumentMatchers.eq(60.0f));
+
+ // Adding another game to the foreground.
+ String anotherGamePkg = "another.game";
+ String[] packages2 = {anotherGamePkg};
+ mockAppCategory(anotherGamePkg, ApplicationInfo.CATEGORY_GAME);
+ int somePackageId = DEFAULT_PACKAGE_UID + 1;
+ when(mMockPackageManager.getPackagesForUid(somePackageId)).thenReturn(packages2);
+
+ gameManagerService.mUidObserver.onUidStateChanged(
+ somePackageId, ActivityManager.PROCESS_STATE_TOP, 0, 0);
+
+ // Toggle game default frame rate off.
+ when(mSysPropsMock.getBoolean(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ ArgumentMatchers.eq(true))).thenReturn(false);
+ gameManagerService.toggleGameDefaultFrameRate(false);
+
+ // Verify that:
+ // 1) The system property is set correctly
+ // 2) setDefaultFrameRateOverride is called with correct arguments
+ Mockito.verify(mSysPropsMock).set(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ ArgumentMatchers.eq("false"));
+ Mockito.verify(gameManagerService).setGameDefaultFrameRateOverride(
+ ArgumentMatchers.eq(DEFAULT_PACKAGE_UID), ArgumentMatchers.eq(0.0f));
+ Mockito.verify(gameManagerService).setGameDefaultFrameRateOverride(
+ ArgumentMatchers.eq(somePackageId), ArgumentMatchers.eq(0.0f));
+ }
+
+ @Test
+ public void testGameDefaultFrameRate_FlagOff() throws Exception {
+ mSetFlagsRule.disableFlags(Flags.FLAG_GAME_DEFAULT_FRAME_RATE);
+ mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_GAME_MODE);
+
+ GameManagerService gameManagerService = Mockito.spy(
+ new GameManagerService(mMockContext, mTestLooper.getLooper(),
+ InstrumentationRegistry.getContext().getFilesDir(),
+ new Injector(){
+ @Override
+ public GameManagerServiceSystemPropertiesWrapper
+ createSystemPropertiesWrapper() {
+ return mSysPropsMock;
+ }
+ }));
+
+ // Set up a game in the foreground.
+ String[] packages = {mPackageName};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TOP, 0, 0);
+
+ // Toggle game default frame rate on.
+ when(mSysPropsMock.getInt(
+ ArgumentMatchers.eq(PROPERTY_RO_SURFACEFLINGER_GAME_DEFAULT_FRAME_RATE),
+ anyInt())).thenReturn(60);
+ when(mSysPropsMock.getBoolean(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ ArgumentMatchers.eq(true))).thenReturn(true);
+
+ gameManagerService.toggleGameDefaultFrameRate(true);
+
+ // Verify that:
+ // 1) System property is never set
+ // 2) setGameDefaultFrameRateOverride() should never be called if the flag is disabled.
+ Mockito.verify(mSysPropsMock, never()).set(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ anyString());
+ Mockito.verify(gameManagerService, never())
+ .setGameDefaultFrameRateOverride(anyInt(), anyFloat());
+
+ // Toggle game default frame rate off.
+ String anotherGamePkg = "another.game";
+ String[] packages2 = {anotherGamePkg};
+ mockAppCategory(anotherGamePkg, ApplicationInfo.CATEGORY_GAME);
+ int somePackageId = DEFAULT_PACKAGE_UID + 1;
+ when(mMockPackageManager.getPackagesForUid(somePackageId)).thenReturn(packages2);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ somePackageId, ActivityManager.PROCESS_STATE_TOP, 0, 0);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ somePackageId, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ when(mSysPropsMock.getBoolean(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ ArgumentMatchers.eq(true))).thenReturn(false);
+
+ gameManagerService.toggleGameDefaultFrameRate(false);
+ // Verify that:
+ // 1) System property is never set
+ // 2) setGameDefaultFrameRateOverride() should never be called if the flag is disabled.
+ Mockito.verify(mSysPropsMock, never()).set(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ anyString());
+ Mockito.verify(gameManagerService, never())
+ .setGameDefaultFrameRateOverride(anyInt(), anyFloat());
+ }
}