Loading services/core/java/com/android/server/display/DisplayManagerService.java +30 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static android.Manifest.permission.MODIFY_HDR_CONVERSION_MODE; import static android.Manifest.permission.RESTRICT_DISPLAY_MODES; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; import static android.hardware.display.DisplayManagerGlobal.InternalEventFlag; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; Loading Loading @@ -380,6 +381,8 @@ public final class DisplayManagerService extends SystemService { private final SparseArray<DisplayPowerController> mDisplayPowerControllers = new SparseArray<>(); private int mMaxImportanceForRRCallbacks = IMPORTANCE_VISIBLE; /** {@link DisplayBlanker} used by all {@link DisplayPowerController}s. */ private final DisplayBlanker mDisplayBlanker = new DisplayBlanker() { // Synchronized to avoid race conditions when updating multiple display states. Loading Loading @@ -3636,6 +3639,7 @@ public final class DisplayManagerService extends SystemService { pw.println(" mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount); pw.println(" mStableDisplaySize=" + mStableDisplaySize); pw.println(" mMinimumBrightnessCurve=" + mMinimumBrightnessCurve); pw.println(" mMaxImportanceForRRCallbacks=" + mMaxImportanceForRRCallbacks); if (mUserPreferredMode != null) { pw.println(" mUserPreferredMode=" + mUserPreferredMode); Loading Loading @@ -3764,6 +3768,10 @@ public final class DisplayManagerService extends SystemService { } } void overrideMaxImportanceForRRCallbacks(int importance) { mMaxImportanceForRRCallbacks = importance; } boolean requestDisplayPower(int displayId, int requestedState) { synchronized (mSyncRoot) { final var display = mLogicalDisplayMapper.getDisplayLocked(displayId); Loading Loading @@ -4147,6 +4155,18 @@ public final class DisplayManagerService extends SystemService { mPackageName = packageNames == null ? null : packageNames[0]; } public boolean shouldReceiveRefreshRateWithChangeUpdate(int event) { if (mFlags.isRefreshRateEventForForegroundAppsEnabled() && event == DisplayManagerGlobal.EVENT_DISPLAY_REFRESH_RATE_CHANGED) { int procState = mActivityManagerInternal.getUidProcessState(mUid); int importance = ActivityManager.RunningAppProcessInfo .procStateToImportance(procState); return importance <= mMaxImportanceForRRCallbacks || mUid <= Process.SYSTEM_UID; } return true; } public void updateEventFlagsMask(@InternalEventFlag long internalEventFlag) { mInternalEventFlagsMask.set(internalEventFlag); } Loading Loading @@ -4254,6 +4274,11 @@ public final class DisplayManagerService extends SystemService { } } if (!shouldReceiveRefreshRateWithChangeUpdate(event)) { // The client is not visible to the user and is not a system service, so do nothing. return true; } try { transmitDisplayEvent(displayId, event); return true; Loading Loading @@ -4405,6 +4430,11 @@ public final class DisplayManagerService extends SystemService { + displayEvent.displayId + "/" + displayEvent.event + " to " + mUid + "/" + mPid); } if (!shouldReceiveRefreshRateWithChangeUpdate(displayEvent.event)) { continue; } transmitDisplayEvent(displayEvent.displayId, displayEvent.event); } return true; Loading services/core/java/com/android/server/display/DisplayManagerShellCommand.java +19 −0 Original line number Diff line number Diff line Loading @@ -112,6 +112,8 @@ class DisplayManagerShellCommand extends ShellCommand { return requestDisplayPower(Display.STATE_UNKNOWN); case "power-off": return requestDisplayPower(Display.STATE_OFF); case "override-max-importance-rr-callbacks": return overrideMaxImportanceForRRCallbacks(); default: return handleDefaultCommands(cmd); } Loading Loading @@ -631,4 +633,21 @@ class DisplayManagerShellCommand extends ShellCommand { mService.requestDisplayPower(displayId, state); return 0; } private int overrideMaxImportanceForRRCallbacks() { final String importanceString = getNextArg(); if (importanceString == null) { getErrPrintWriter().println("Error: no importance specified"); return 1; } final int importance; try { importance = Integer.parseInt(importanceString); } catch (NumberFormatException e) { getErrPrintWriter().println("Error: invalid importance: '" + importanceString + "'"); return 1; } mService.overrideMaxImportanceForRRCallbacks(importance); return 0; } } services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +14 −1 Original line number Diff line number Diff line Loading @@ -268,6 +268,11 @@ public class DisplayManagerFlags { Flags::framerateOverrideTriggersRrCallbacks ); private final FlagState mRefreshRateEventForForegroundApps = new FlagState( Flags.FLAG_REFRESH_RATE_EVENT_FOR_FOREGROUND_APPS, Flags::refreshRateEventForForegroundApps ); /** * @return {@code true} if 'port' is allowed in display layout configuration file. */ Loading Loading @@ -578,6 +583,14 @@ public class DisplayManagerFlags { } /** * @return {@code true} if the flag for sending refresh rate events only for the apps in * foreground is enabled */ public boolean isRefreshRateEventForForegroundAppsEnabled() { return mRefreshRateEventForForegroundApps.isEnabled(); } /** * dumps all flagstates * @param pw printWriter Loading Loading @@ -634,7 +647,7 @@ public class DisplayManagerFlags { pw.println(" " + mEnableDisplayContentModeManagementFlagState); pw.println(" " + mBaseDensityForExternalDisplays); pw.println(" " + mFramerateOverrideTriggersRrCallbacks); pw.println(" " + mRefreshRateEventForForegroundApps); } private static class FlagState { Loading services/core/java/com/android/server/display/feature/display_flags.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -490,3 +490,14 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "refresh_rate_event_for_foreground_apps" namespace: "display_manager" description: "Send Refresh Rate events only for the apps in foreground." bug: "390107600" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } } services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +24 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT; import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS; import static android.Manifest.permission.MANAGE_DISPLAYS; import static android.Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE; import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND; import static android.hardware.display.DisplayManager.SWITCHING_TYPE_NONE; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; Loading Loading @@ -2344,6 +2345,29 @@ public class DisplayManagerServiceTest { callback.clear(); } @Test public void test_doesNotNotifyRefreshRateChanged_whenAppInBackground() { when(mMockFlags.isRefreshRateEventForForegroundAppsEnabled()).thenReturn(true); DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerService.BinderService displayManagerBinderService = displayManager.new BinderService(); displayManager.windowManagerAndInputReady(); registerDefaultDisplays(displayManager); displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY); FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, new float[]{60f}); FakeDisplayManagerCallback callback = registerDisplayListenerCallback(displayManager, displayManagerBinderService, displayDevice); when(mMockActivityManagerInternal.getUidProcessState(Process.myUid())) .thenReturn(PROCESS_STATE_TRANSIENT_BACKGROUND); updateRenderFrameRate(displayManager, displayDevice, 30f); waitForIdleHandler(displayManager.getDisplayHandler()); assertEquals(0, callback.receivedEvents().size()); callback.clear(); } /** * Tests that the DisplayInfo is updated correctly with a render frame rate */ Loading Loading
services/core/java/com/android/server/display/DisplayManagerService.java +30 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static android.Manifest.permission.MODIFY_HDR_CONVERSION_MODE; import static android.Manifest.permission.RESTRICT_DISPLAY_MODES; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; import static android.hardware.display.DisplayManagerGlobal.InternalEventFlag; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; Loading Loading @@ -380,6 +381,8 @@ public final class DisplayManagerService extends SystemService { private final SparseArray<DisplayPowerController> mDisplayPowerControllers = new SparseArray<>(); private int mMaxImportanceForRRCallbacks = IMPORTANCE_VISIBLE; /** {@link DisplayBlanker} used by all {@link DisplayPowerController}s. */ private final DisplayBlanker mDisplayBlanker = new DisplayBlanker() { // Synchronized to avoid race conditions when updating multiple display states. Loading Loading @@ -3636,6 +3639,7 @@ public final class DisplayManagerService extends SystemService { pw.println(" mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount); pw.println(" mStableDisplaySize=" + mStableDisplaySize); pw.println(" mMinimumBrightnessCurve=" + mMinimumBrightnessCurve); pw.println(" mMaxImportanceForRRCallbacks=" + mMaxImportanceForRRCallbacks); if (mUserPreferredMode != null) { pw.println(" mUserPreferredMode=" + mUserPreferredMode); Loading Loading @@ -3764,6 +3768,10 @@ public final class DisplayManagerService extends SystemService { } } void overrideMaxImportanceForRRCallbacks(int importance) { mMaxImportanceForRRCallbacks = importance; } boolean requestDisplayPower(int displayId, int requestedState) { synchronized (mSyncRoot) { final var display = mLogicalDisplayMapper.getDisplayLocked(displayId); Loading Loading @@ -4147,6 +4155,18 @@ public final class DisplayManagerService extends SystemService { mPackageName = packageNames == null ? null : packageNames[0]; } public boolean shouldReceiveRefreshRateWithChangeUpdate(int event) { if (mFlags.isRefreshRateEventForForegroundAppsEnabled() && event == DisplayManagerGlobal.EVENT_DISPLAY_REFRESH_RATE_CHANGED) { int procState = mActivityManagerInternal.getUidProcessState(mUid); int importance = ActivityManager.RunningAppProcessInfo .procStateToImportance(procState); return importance <= mMaxImportanceForRRCallbacks || mUid <= Process.SYSTEM_UID; } return true; } public void updateEventFlagsMask(@InternalEventFlag long internalEventFlag) { mInternalEventFlagsMask.set(internalEventFlag); } Loading Loading @@ -4254,6 +4274,11 @@ public final class DisplayManagerService extends SystemService { } } if (!shouldReceiveRefreshRateWithChangeUpdate(event)) { // The client is not visible to the user and is not a system service, so do nothing. return true; } try { transmitDisplayEvent(displayId, event); return true; Loading Loading @@ -4405,6 +4430,11 @@ public final class DisplayManagerService extends SystemService { + displayEvent.displayId + "/" + displayEvent.event + " to " + mUid + "/" + mPid); } if (!shouldReceiveRefreshRateWithChangeUpdate(displayEvent.event)) { continue; } transmitDisplayEvent(displayEvent.displayId, displayEvent.event); } return true; Loading
services/core/java/com/android/server/display/DisplayManagerShellCommand.java +19 −0 Original line number Diff line number Diff line Loading @@ -112,6 +112,8 @@ class DisplayManagerShellCommand extends ShellCommand { return requestDisplayPower(Display.STATE_UNKNOWN); case "power-off": return requestDisplayPower(Display.STATE_OFF); case "override-max-importance-rr-callbacks": return overrideMaxImportanceForRRCallbacks(); default: return handleDefaultCommands(cmd); } Loading Loading @@ -631,4 +633,21 @@ class DisplayManagerShellCommand extends ShellCommand { mService.requestDisplayPower(displayId, state); return 0; } private int overrideMaxImportanceForRRCallbacks() { final String importanceString = getNextArg(); if (importanceString == null) { getErrPrintWriter().println("Error: no importance specified"); return 1; } final int importance; try { importance = Integer.parseInt(importanceString); } catch (NumberFormatException e) { getErrPrintWriter().println("Error: invalid importance: '" + importanceString + "'"); return 1; } mService.overrideMaxImportanceForRRCallbacks(importance); return 0; } }
services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +14 −1 Original line number Diff line number Diff line Loading @@ -268,6 +268,11 @@ public class DisplayManagerFlags { Flags::framerateOverrideTriggersRrCallbacks ); private final FlagState mRefreshRateEventForForegroundApps = new FlagState( Flags.FLAG_REFRESH_RATE_EVENT_FOR_FOREGROUND_APPS, Flags::refreshRateEventForForegroundApps ); /** * @return {@code true} if 'port' is allowed in display layout configuration file. */ Loading Loading @@ -578,6 +583,14 @@ public class DisplayManagerFlags { } /** * @return {@code true} if the flag for sending refresh rate events only for the apps in * foreground is enabled */ public boolean isRefreshRateEventForForegroundAppsEnabled() { return mRefreshRateEventForForegroundApps.isEnabled(); } /** * dumps all flagstates * @param pw printWriter Loading Loading @@ -634,7 +647,7 @@ public class DisplayManagerFlags { pw.println(" " + mEnableDisplayContentModeManagementFlagState); pw.println(" " + mBaseDensityForExternalDisplays); pw.println(" " + mFramerateOverrideTriggersRrCallbacks); pw.println(" " + mRefreshRateEventForForegroundApps); } private static class FlagState { Loading
services/core/java/com/android/server/display/feature/display_flags.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -490,3 +490,14 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "refresh_rate_event_for_foreground_apps" namespace: "display_manager" description: "Send Refresh Rate events only for the apps in foreground." bug: "390107600" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } }
services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +24 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT; import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS; import static android.Manifest.permission.MANAGE_DISPLAYS; import static android.Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE; import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND; import static android.hardware.display.DisplayManager.SWITCHING_TYPE_NONE; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; Loading Loading @@ -2344,6 +2345,29 @@ public class DisplayManagerServiceTest { callback.clear(); } @Test public void test_doesNotNotifyRefreshRateChanged_whenAppInBackground() { when(mMockFlags.isRefreshRateEventForForegroundAppsEnabled()).thenReturn(true); DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerService.BinderService displayManagerBinderService = displayManager.new BinderService(); displayManager.windowManagerAndInputReady(); registerDefaultDisplays(displayManager); displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY); FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, new float[]{60f}); FakeDisplayManagerCallback callback = registerDisplayListenerCallback(displayManager, displayManagerBinderService, displayDevice); when(mMockActivityManagerInternal.getUidProcessState(Process.myUid())) .thenReturn(PROCESS_STATE_TRANSIENT_BACKGROUND); updateRenderFrameRate(displayManager, displayDevice, 30f); waitForIdleHandler(displayManager.getDisplayHandler()); assertEquals(0, callback.receivedEvents().size()); callback.clear(); } /** * Tests that the DisplayInfo is updated correctly with a render frame rate */ Loading