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

Commit de3be891 authored by Rupesh Bansal's avatar Rupesh Bansal
Browse files

Fixed latency spike

A spike in the startup time of DisplayManagerService was observeed
because of a recent change where we are attempting read values from
DeviceConfig, which if missing fallsback to DisplayDeviceConfig. This
extra read attempt is unneeded because once the DisplayManagerService is
setup, we explicitly make a start call to DisplayModeDirector which
takes care of reloading values from DeviceConfig if present.

Bug: 254354520
Test: Manual
Change-Id: Iae7066b8c732d9b39e3fb76200ff24cb5aeb3d73
parent 6e16fac5
Loading
Loading
Loading
Loading
+76 −27
Original line number Diff line number Diff line
@@ -523,8 +523,10 @@ public class DisplayModeDirector {
     * changed
     */
    public void defaultDisplayDeviceUpdated(DisplayDeviceConfig displayDeviceConfig) {
        mSettingsObserver.setRefreshRates(displayDeviceConfig);
        mBrightnessObserver.updateBlockingZoneThresholds(displayDeviceConfig);
        mSettingsObserver.setRefreshRates(displayDeviceConfig,
            /* attemptLoadingFromDeviceConfig= */ true);
        mBrightnessObserver.updateBlockingZoneThresholds(displayDeviceConfig,
            /* attemptLoadingFromDeviceConfig= */ true);
    }

    /**
@@ -1142,15 +1144,21 @@ public class DisplayModeDirector {
        SettingsObserver(@NonNull Context context, @NonNull Handler handler) {
            super(handler);
            mContext = context;
            setRefreshRates(/* displayDeviceConfig= */ null);
            // We don't want to load from the DeviceConfig while constructing since this leads to
            // a spike in the latency of DisplayManagerService startup. This happens because
            // reading from the DeviceConfig is an intensive IO operation and having it in the
            // startup phase where we thrive to keep the latency very low has significant impact.
            setRefreshRates(/* displayDeviceConfig= */ null,
                /* attemptLoadingFromDeviceConfig= */ false);
        }

        /**
         * This is used to update the refresh rate configs from the DeviceConfig, which
         * if missing from DisplayDeviceConfig, and finally fallback to config.xml.
         */
        public void setRefreshRates(DisplayDeviceConfig displayDeviceConfig) {
            setDefaultPeakRefreshRate(displayDeviceConfig);
        public void setRefreshRates(DisplayDeviceConfig displayDeviceConfig,
                boolean attemptLoadingFromDeviceConfig) {
            setDefaultPeakRefreshRate(displayDeviceConfig, attemptLoadingFromDeviceConfig);
            mDefaultRefreshRate =
                    (displayDeviceConfig == null) ? (float) mContext.getResources().getInteger(
                        R.integer.config_defaultRefreshRate)
@@ -1215,14 +1223,28 @@ public class DisplayModeDirector {
            }
        }

        private void setDefaultPeakRefreshRate(DisplayDeviceConfig displayDeviceConfig) {
        @VisibleForTesting
        float getDefaultRefreshRate() {
            return mDefaultRefreshRate;
        }

        @VisibleForTesting
        float getDefaultPeakRefreshRate() {
            return mDefaultPeakRefreshRate;
        }

        private void setDefaultPeakRefreshRate(DisplayDeviceConfig displayDeviceConfig,
                boolean attemptLoadingFromDeviceConfig) {
            Float defaultPeakRefreshRate = null;

            if (attemptLoadingFromDeviceConfig) {
                try {
                    defaultPeakRefreshRate =
                        mDeviceConfigDisplaySettings.getDefaultPeakRefreshRate();
                } catch (Exception exception) {
                    // Do nothing
                }
            }
            if (defaultPeakRefreshRate == null) {
                defaultPeakRefreshRate =
                        (displayDeviceConfig == null) ? (float) mContext.getResources().getInteger(
@@ -1544,7 +1566,8 @@ public class DisplayModeDirector {
            mContext = context;
            mHandler = handler;
            mInjector = injector;
            updateBlockingZoneThresholds(/* displayDeviceConfig= */ null);
            updateBlockingZoneThresholds(/* displayDeviceConfig= */ null,
                /* attemptLoadingFromDeviceConfig= */ false);
            mRefreshRateInHighZone = context.getResources().getInteger(
                    R.integer.config_fixedRefreshRateInHighZone);
        }
@@ -1553,22 +1576,44 @@ public class DisplayModeDirector {
         * This is used to update the blocking zone thresholds from the DeviceConfig, which
         * if missing from DisplayDeviceConfig, and finally fallback to config.xml.
         */
        public void updateBlockingZoneThresholds(DisplayDeviceConfig displayDeviceConfig) {
            loadLowBrightnessThresholds(displayDeviceConfig);
            loadHighBrightnessThresholds(displayDeviceConfig);
        public void updateBlockingZoneThresholds(DisplayDeviceConfig displayDeviceConfig,
                boolean attemptLoadingFromDeviceConfig) {
            loadLowBrightnessThresholds(displayDeviceConfig, attemptLoadingFromDeviceConfig);
            loadHighBrightnessThresholds(displayDeviceConfig, attemptLoadingFromDeviceConfig);
        }

        @VisibleForTesting
        int[] getLowDisplayBrightnessThreshold() {
            return mLowDisplayBrightnessThresholds;
        }

        private void loadLowBrightnessThresholds(DisplayDeviceConfig displayDeviceConfig) {
        @VisibleForTesting
        int[] getLowAmbientBrightnessThreshold() {
            return mLowAmbientBrightnessThresholds;
        }

        @VisibleForTesting
        int[] getHighDisplayBrightnessThreshold() {
            return mHighDisplayBrightnessThresholds;
        }

        @VisibleForTesting
        int[] getHighAmbientBrightnessThreshold() {
            return mHighAmbientBrightnessThresholds;
        }

        private void loadLowBrightnessThresholds(DisplayDeviceConfig displayDeviceConfig,
                boolean attemptLoadingFromDeviceConfig) {
            mLowDisplayBrightnessThresholds = loadBrightnessThresholds(
                    () -> mDeviceConfigDisplaySettings.getLowDisplayBrightnessThresholds(),
                    () -> displayDeviceConfig.getLowDisplayBrightnessThresholds(),
                    R.array.config_brightnessThresholdsOfPeakRefreshRate,
                    displayDeviceConfig);
                    displayDeviceConfig, attemptLoadingFromDeviceConfig);
            mLowAmbientBrightnessThresholds = loadBrightnessThresholds(
                    () -> mDeviceConfigDisplaySettings.getLowAmbientBrightnessThresholds(),
                    () -> displayDeviceConfig.getLowAmbientBrightnessThresholds(),
                    R.array.config_ambientThresholdsOfPeakRefreshRate,
                    displayDeviceConfig);
                    displayDeviceConfig, attemptLoadingFromDeviceConfig);
            if (mLowDisplayBrightnessThresholds.length != mLowAmbientBrightnessThresholds.length) {
                throw new RuntimeException("display low brightness threshold array and ambient "
                        + "brightness threshold array have different length: "
@@ -1579,17 +1624,18 @@ public class DisplayModeDirector {
            }
        }

        private void loadHighBrightnessThresholds(DisplayDeviceConfig displayDeviceConfig) {
        private void loadHighBrightnessThresholds(DisplayDeviceConfig displayDeviceConfig,
                boolean attemptLoadingFromDeviceConfig) {
            mHighDisplayBrightnessThresholds = loadBrightnessThresholds(
                    () -> mDeviceConfigDisplaySettings.getHighDisplayBrightnessThresholds(),
                    () -> displayDeviceConfig.getHighDisplayBrightnessThresholds(),
                    R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate,
                    displayDeviceConfig);
                    displayDeviceConfig, attemptLoadingFromDeviceConfig);
            mHighAmbientBrightnessThresholds = loadBrightnessThresholds(
                    () -> mDeviceConfigDisplaySettings.getHighAmbientBrightnessThresholds(),
                    () -> displayDeviceConfig.getHighAmbientBrightnessThresholds(),
                    R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate,
                    displayDeviceConfig);
                    displayDeviceConfig, attemptLoadingFromDeviceConfig);
            if (mHighDisplayBrightnessThresholds.length
                    != mHighAmbientBrightnessThresholds.length) {
                throw new RuntimeException("display high brightness threshold array and ambient "
@@ -1605,14 +1651,17 @@ public class DisplayModeDirector {
                Callable<int[]> loadFromDeviceConfigDisplaySettingsCallable,
                Callable<int[]> loadFromDisplayDeviceConfigCallable,
                int brightnessThresholdOfFixedRefreshRateKey,
                DisplayDeviceConfig displayDeviceConfig) {
                DisplayDeviceConfig displayDeviceConfig, boolean attemptLoadingFromDeviceConfig) {
            int[] brightnessThresholds = null;

            if (attemptLoadingFromDeviceConfig) {
                try {
                    brightnessThresholds =
                        loadFromDeviceConfigDisplaySettingsCallable.call();
                } catch (Exception exception) {
                    // Do nothing
                }
            }
            if (brightnessThresholds == null) {
                try {
                    brightnessThresholds =
+85 −7
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REF
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_HDR;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_SUNLIGHT;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE;
@@ -31,6 +32,8 @@ import static com.android.server.display.HighBrightnessModeController.HBM_TRANSI

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -48,6 +51,7 @@ import android.annotation.NonNull;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.Sensor;
import android.hardware.SensorEventListener;
@@ -76,6 +80,7 @@ import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.internal.R;
import com.android.internal.display.BrightnessSynchronizer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.test.FakeSettingsProvider;
@@ -1855,16 +1860,83 @@ public class DisplayModeDirectorTest {

    @Test
    public void testNotifyDefaultDisplayDeviceUpdated() {
        DisplayDeviceConfig displayDeviceConfig = mock(DisplayDeviceConfig.class);
        when(displayDeviceConfig.getLowDisplayBrightnessThresholds()).thenReturn(new int[]{});
        when(displayDeviceConfig.getLowAmbientBrightnessThresholds()).thenReturn(new int[]{});
        when(displayDeviceConfig.getHighDisplayBrightnessThresholds()).thenReturn(new int[]{});
        when(displayDeviceConfig.getHighAmbientBrightnessThresholds()).thenReturn(new int[]{});
        Resources resources = mock(Resources.class);
        when(mContext.getResources()).thenReturn(resources);
        when(resources.getInteger(com.android.internal.R.integer.config_defaultPeakRefreshRate))
            .thenReturn(75);
        when(resources.getInteger(R.integer.config_defaultRefreshRate))
            .thenReturn(45);
        when(resources.getIntArray(R.array.config_brightnessThresholdsOfPeakRefreshRate))
            .thenReturn(new int[]{5});
        when(resources.getIntArray(R.array.config_ambientThresholdsOfPeakRefreshRate))
            .thenReturn(new int[]{10});
        when(
            resources.getIntArray(R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate))
            .thenReturn(new int[]{250});
        when(
            resources.getIntArray(R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate))
            .thenReturn(new int[]{7000});
        DisplayModeDirector director =
                createDirectorFromRefreshRateArray(new float[]{60.0f, 90.0f}, 0);
        // We don't expect any interaction with DeviceConfig when the director is initialized
        // because we explicitly avoid doing this as this can lead to a latency spike in the
        // startup of DisplayManagerService
        // Verify all the loaded values are from DisplayDeviceConfig
        assertEquals(director.getSettingsObserver().getDefaultRefreshRate(), 45, 0.0);
        assertEquals(director.getSettingsObserver().getDefaultPeakRefreshRate(), 75,
                0.0);
        assertArrayEquals(director.getBrightnessObserver().getHighDisplayBrightnessThreshold(),
                new int[]{250});
        assertArrayEquals(director.getBrightnessObserver().getHighAmbientBrightnessThreshold(),
                new int[]{7000});
        assertArrayEquals(director.getBrightnessObserver().getLowDisplayBrightnessThreshold(),
                new int[]{5});
        assertArrayEquals(director.getBrightnessObserver().getLowAmbientBrightnessThreshold(),
                new int[]{10});

        // Notify that the default display is updated, such that DisplayDeviceConfig has new values
        DisplayDeviceConfig displayDeviceConfig = mock(DisplayDeviceConfig.class);
        when(displayDeviceConfig.getDefaultRefreshRate()).thenReturn(50);
        when(displayDeviceConfig.getDefaultPeakRefreshRate()).thenReturn(55);
        when(displayDeviceConfig.getLowDisplayBrightnessThresholds()).thenReturn(new int[]{25});
        when(displayDeviceConfig.getLowAmbientBrightnessThresholds()).thenReturn(new int[]{30});
        when(displayDeviceConfig.getHighDisplayBrightnessThresholds()).thenReturn(new int[]{210});
        when(displayDeviceConfig.getHighAmbientBrightnessThresholds()).thenReturn(new int[]{2100});
        director.defaultDisplayDeviceUpdated(displayDeviceConfig);

        assertEquals(director.getSettingsObserver().getDefaultRefreshRate(), 50, 0.0);
        assertEquals(director.getSettingsObserver().getDefaultPeakRefreshRate(), 55,
                0.0);
        assertArrayEquals(director.getBrightnessObserver().getHighDisplayBrightnessThreshold(),
                new int[]{210});
        assertArrayEquals(director.getBrightnessObserver().getHighAmbientBrightnessThreshold(),
                new int[]{2100});
        assertArrayEquals(director.getBrightnessObserver().getLowDisplayBrightnessThreshold(),
                new int[]{25});
        assertArrayEquals(director.getBrightnessObserver().getLowAmbientBrightnessThreshold(),
                new int[]{30});

        // Notify that the default display is updated, such that DeviceConfig has new values
        FakeDeviceConfig config = mInjector.getDeviceConfig();
        config.setDefaultPeakRefreshRate(60);
        config.setLowAmbientBrightnessThresholds(new int[]{20});
        config.setLowDisplayBrightnessThresholds(new int[]{10});
        config.setHighDisplayBrightnessThresholds(new int[]{255});
        config.setHighAmbientBrightnessThresholds(new int[]{8000});

        director.defaultDisplayDeviceUpdated(displayDeviceConfig);
        verify(displayDeviceConfig).getDefaultRefreshRate();
        verify(displayDeviceConfig).getDefaultPeakRefreshRate();

        assertEquals(director.getSettingsObserver().getDefaultRefreshRate(), 50, 0.0);
        assertEquals(director.getSettingsObserver().getDefaultPeakRefreshRate(), 60,
                0.0);
        assertArrayEquals(director.getBrightnessObserver().getHighDisplayBrightnessThreshold(),
                new int[]{255});
        assertArrayEquals(director.getBrightnessObserver().getHighAmbientBrightnessThreshold(),
                new int[]{8000});
        assertArrayEquals(director.getBrightnessObserver().getLowDisplayBrightnessThreshold(),
                new int[]{10});
        assertArrayEquals(director.getBrightnessObserver().getLowAmbientBrightnessThreshold(),
                new int[]{20});
    }

    private Temperature getSkinTemp(@Temperature.ThrottlingStatus int status) {
@@ -1954,6 +2026,12 @@ public class DisplayModeDirectorTest {
                    String.valueOf(fps));
        }

        void setDefaultPeakRefreshRate(int fps) {
            putPropertyAndNotify(
                    DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_PEAK_REFRESH_RATE_DEFAULT,
                    String.valueOf(fps));
        }

        void setHighDisplayBrightnessThresholds(int[] brightnessThresholds) {
            String thresholds = toPropertyValue(brightnessThresholds);