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
This commit is contained in:
Rupesh Bansal
2022-10-30 10:16:03 +00:00
parent 6e16fac514
commit de3be8915d
2 changed files with 161 additions and 34 deletions

View File

@@ -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,19 +1144,25 @@ 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)
: (float) displayDeviceConfig.getDefaultRefreshRate();
R.integer.config_defaultRefreshRate)
: (float) displayDeviceConfig.getDefaultRefreshRate();
}
public void observe() {
@@ -1215,13 +1223,27 @@ 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;
try {
defaultPeakRefreshRate =
if (attemptLoadingFromDeviceConfig) {
try {
defaultPeakRefreshRate =
mDeviceConfigDisplaySettings.getDefaultPeakRefreshRate();
} catch (Exception exception) {
// Do nothing
} catch (Exception exception) {
// Do nothing
}
}
if (defaultPeakRefreshRate == null) {
defaultPeakRefreshRate =
@@ -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);
}
private void loadLowBrightnessThresholds(DisplayDeviceConfig displayDeviceConfig) {
@VisibleForTesting
int[] getLowDisplayBrightnessThreshold() {
return mLowDisplayBrightnessThresholds;
}
@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,13 +1651,16 @@ public class DisplayModeDirector {
Callable<int[]> loadFromDeviceConfigDisplaySettingsCallable,
Callable<int[]> loadFromDisplayDeviceConfigCallable,
int brightnessThresholdOfFixedRefreshRateKey,
DisplayDeviceConfig displayDeviceConfig) {
DisplayDeviceConfig displayDeviceConfig, boolean attemptLoadingFromDeviceConfig) {
int[] brightnessThresholds = null;
try {
brightnessThresholds =
if (attemptLoadingFromDeviceConfig) {
try {
brightnessThresholds =
loadFromDeviceConfigDisplaySettingsCallable.call();
} catch (Exception exception) {
// Do nothing
} catch (Exception exception) {
// Do nothing
}
}
if (brightnessThresholds == null) {
try {

View File

@@ -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);
verify(displayDeviceConfig).getDefaultRefreshRate();
verify(displayDeviceConfig).getDefaultPeakRefreshRate();
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);
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);