Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 14a8feaa authored by Rupesh Bansal's avatar Rupesh Bansal
Browse files

Dont send RR events if not in foreground

Do not send refresh rate change callbacks to an app which is not in the
foreground. This will help in reducing the number of display change
callbacks.

Bug: 390107600
Test: Manually verified app in background is not getting any RR change callback
Test: atest DisplayManagerServiceTest
Flag: com.android.server.display.feature.flags.refresh_rate_event_for_foreground_apps
Change-Id: I5dba115a282e7d85f52a1b9870af058921ca44b4
parent 672207ab
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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.
@@ -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);
@@ -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);
@@ -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);
        }
@@ -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;
@@ -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;
+19 −0
Original line number Diff line number Diff line
@@ -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);
        }
@@ -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;
    }
}
+14 −1
Original line number Diff line number Diff line
@@ -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.
     */
@@ -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
@@ -634,7 +647,7 @@ public class DisplayManagerFlags {
        pw.println(" " + mEnableDisplayContentModeManagementFlagState);
        pw.println(" " + mBaseDensityForExternalDisplays);
        pw.println(" " + mFramerateOverrideTriggersRrCallbacks);

        pw.println(" " + mRefreshRateEventForForegroundApps);
    }

    private static class FlagState {
+11 −0
Original line number Diff line number Diff line
@@ -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
    }
}
+24 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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
     */