From 221ed8b5bd147048145b4039a0a29696633efd1f Mon Sep 17 00:00:00 2001 From: Daniel Solomon Date: Mon, 10 Jan 2022 20:11:53 -0800 Subject: [PATCH] Add BrightnessThrottler data to display device config Brightness throttler, which will be added in a future change, will be responsible for limiting the usable range of display brightness based on various events, such as thermal throttling. This change adds the necessary data containers in display device config. Bug: 206857086 Bug: 212634465 Test: atest BrightnessThrottlerTest Change-Id: Iadff7e4c16127ccddff34a1660d13c3e00584c9a --- .../server/display/DisplayDeviceConfig.java | 155 ++++++++++++++++++ .../display-device-config.xsd | 35 ++++ .../display-device-config/schema/current.txt | 21 +++ .../display/BrightnessThrottlerTest.java | 118 +++++++++++++ 4 files changed, 329 insertions(+) create mode 100644 services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index f3969b19e11f5..a4a6eb4312cca 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -33,6 +33,8 @@ import android.view.DisplayAddress; import com.android.internal.R; import com.android.internal.display.BrightnessSynchronizer; import com.android.server.display.config.BrightnessThresholds; +import com.android.server.display.config.BrightnessThrottlingMap; +import com.android.server.display.config.BrightnessThrottlingPoint; import com.android.server.display.config.Density; import com.android.server.display.config.DisplayConfiguration; import com.android.server.display.config.DisplayQuirks; @@ -43,6 +45,7 @@ import com.android.server.display.config.Point; import com.android.server.display.config.RefreshRateRange; import com.android.server.display.config.SensorDetails; import com.android.server.display.config.ThermalStatus; +import com.android.server.display.config.ThermalThrottling; import com.android.server.display.config.Thresholds; import com.android.server.display.config.XmlParser; @@ -145,6 +148,8 @@ public class DisplayDeviceConfig { private DensityMap mDensityMap; private String mLoadedFrom = null; + private BrightnessThrottlingData mBrightnessThrottlingData; + private DisplayDeviceConfig(Context context) { mContext = context; } @@ -424,6 +429,13 @@ public class DisplayDeviceConfig { return mDensityMap; } + /** + * @return brightness throttling data configuration data for the display. + */ + public BrightnessThrottlingData getBrightnessThrottlingData() { + return BrightnessThrottlingData.create(mBrightnessThrottlingData); + } + @Override public String toString() { return "DisplayDeviceConfig{" @@ -441,6 +453,7 @@ public class DisplayDeviceConfig { + ", mQuirks=" + mQuirks + ", isHbmEnabled=" + mIsHighBrightnessModeEnabled + ", mHbmData=" + mHbmData + + ", mBrightnessThrottlingData=" + mBrightnessThrottlingData + ", mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease + ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease + ", mBrightnessRampSlowDecrease=" + mBrightnessRampSlowDecrease @@ -502,6 +515,7 @@ public class DisplayDeviceConfig { loadBrightnessDefaultFromDdcXml(config); loadBrightnessConstraintsFromConfigXml(); loadBrightnessMap(config); + loadBrightnessThrottlingMap(config); loadHighBrightnessModeData(config); loadQuirks(config); loadBrightnessRamps(config); @@ -664,6 +678,41 @@ public class DisplayDeviceConfig { constrainNitsAndBacklightArrays(); } + private void loadBrightnessThrottlingMap(DisplayConfiguration config) { + final ThermalThrottling throttlingConfig = config.getThermalThrottling(); + if (throttlingConfig == null) { + Slog.i(TAG, "no thermal throttling config found"); + return; + } + + final BrightnessThrottlingMap map = throttlingConfig.getBrightnessThrottlingMap(); + if (map == null) { + Slog.i(TAG, "no brightness throttling map found"); + return; + } + + final List points = map.getBrightnessThrottlingPoint(); + // At least 1 point is guaranteed by the display device config schema + List throttlingLevels = + new ArrayList<>(points.size()); + + boolean badConfig = false; + for (BrightnessThrottlingPoint point : points) { + ThermalStatus status = point.getThermalStatus(); + if (!thermalStatusIsValid(status)) { + badConfig = true; + break; + } + + throttlingLevels.add(new BrightnessThrottlingData.ThrottlingLevel( + convertThermalStatus(status), point.getBrightness().floatValue())); + } + + if (!badConfig) { + mBrightnessThrottlingData = BrightnessThrottlingData.create(throttlingLevels); + } + } + private void loadBrightnessMapFromConfigXml() { // Use the config.xml mapping final Resources res = mContext.getResources(); @@ -931,6 +980,25 @@ public class DisplayDeviceConfig { } } + private boolean thermalStatusIsValid(ThermalStatus value) { + if (value == null) { + return false; + } + + switch (value) { + case none: + case light: + case moderate: + case severe: + case critical: + case emergency: + case shutdown: + return true; + default: + return false; + } + } + private @PowerManager.ThermalStatus int convertThermalStatus(ThermalStatus value) { if (value == null) { return PowerManager.THERMAL_STATUS_NONE; @@ -1061,4 +1129,91 @@ public class DisplayDeviceConfig { + "} "; } } + + /** + * Container for brightness throttling data. + */ + static class BrightnessThrottlingData { + static class ThrottlingLevel { + public @PowerManager.ThermalStatus int thermalStatus; + public float brightness; + + ThrottlingLevel(@PowerManager.ThermalStatus int thermalStatus, float brightness) { + this.thermalStatus = thermalStatus; + this.brightness = brightness; + } + + @Override + public String toString() { + return "[" + thermalStatus + "," + brightness + "]"; + } + } + + public List throttlingLevels; + + static public BrightnessThrottlingData create(List throttlingLevels) + { + if (throttlingLevels == null || throttlingLevels.size() == 0) { + Slog.e(TAG, "BrightnessThrottlingData received null or empty throttling levels"); + return null; + } + + ThrottlingLevel prevLevel = throttlingLevels.get(0); + final int numLevels = throttlingLevels.size(); + for (int i = 1; i < numLevels; i++) { + ThrottlingLevel thisLevel = throttlingLevels.get(i); + + if (thisLevel.thermalStatus <= prevLevel.thermalStatus) { + Slog.e(TAG, "brightnessThrottlingMap must be strictly increasing, ignoring " + + "configuration. ThermalStatus " + thisLevel.thermalStatus + " <= " + + prevLevel.thermalStatus); + return null; + } + + if (thisLevel.brightness >= prevLevel.brightness) { + Slog.e(TAG, "brightnessThrottlingMap must be strictly decreasing, ignoring " + + "configuration. Brightness " + thisLevel.brightness + " >= " + + thisLevel.brightness); + return null; + } + + prevLevel = thisLevel; + } + + for (ThrottlingLevel level : throttlingLevels) { + // Non-negative brightness values are enforced by device config schema + if (level.brightness > PowerManager.BRIGHTNESS_MAX) { + Slog.e(TAG, "brightnessThrottlingMap contains a brightness value exceeding " + + "system max. Brightness " + level.brightness + " > " + + PowerManager.BRIGHTNESS_MAX); + return null; + } + } + + return new BrightnessThrottlingData(throttlingLevels); + } + + static public BrightnessThrottlingData create(BrightnessThrottlingData other) { + if (other == null) + return null; + + return BrightnessThrottlingData.create(other.throttlingLevels); + } + + + @Override + public String toString() { + return "BrightnessThrottlingData{" + + "throttlingLevels:" + throttlingLevels + + "} "; + } + + private BrightnessThrottlingData(List inLevels) { + throttlingLevels = new ArrayList<>(inLevels.size()); + for (ThrottlingLevel level : inLevels) { + throttlingLevels.add(new ThrottlingLevel(level.thermalStatus, level.brightness)); + } + } + + } } diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd index 574dbfd1046dd..79d80366efd38 100644 --- a/services/core/xsd/display-device-config/display-device-config.xsd +++ b/services/core/xsd/display-device-config/display-device-config.xsd @@ -38,6 +38,10 @@ + + + + @@ -154,6 +158,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt index 04f0916dbc549..0b7df4d0bc7cf 100644 --- a/services/core/xsd/display-device-config/schema/current.txt +++ b/services/core/xsd/display-device-config/schema/current.txt @@ -7,6 +7,19 @@ package com.android.server.display.config { method public final void setMinimum(@NonNull java.math.BigDecimal); } + public class BrightnessThrottlingMap { + ctor public BrightnessThrottlingMap(); + method @NonNull public final java.util.List getBrightnessThrottlingPoint(); + } + + public class BrightnessThrottlingPoint { + ctor public BrightnessThrottlingPoint(); + method @NonNull public final java.math.BigDecimal getBrightness(); + method @NonNull public final com.android.server.display.config.ThermalStatus getThermalStatus(); + method public final void setBrightness(@NonNull java.math.BigDecimal); + method public final void setThermalStatus(@NonNull com.android.server.display.config.ThermalStatus); + } + public class Density { ctor public Density(); method @NonNull public final java.math.BigInteger getDensity(); @@ -39,6 +52,7 @@ package com.android.server.display.config { method public final java.math.BigDecimal getScreenBrightnessRampFastIncrease(); method public final java.math.BigDecimal getScreenBrightnessRampSlowDecrease(); method public final java.math.BigDecimal getScreenBrightnessRampSlowIncrease(); + method @NonNull public final com.android.server.display.config.ThermalThrottling getThermalThrottling(); method public final void setAmbientBrightnessChangeThresholds(@NonNull com.android.server.display.config.Thresholds); method public final void setAmbientLightHorizonLong(java.math.BigInteger); method public final void setAmbientLightHorizonShort(java.math.BigInteger); @@ -54,6 +68,7 @@ package com.android.server.display.config { method public final void setScreenBrightnessRampFastIncrease(java.math.BigDecimal); method public final void setScreenBrightnessRampSlowDecrease(java.math.BigDecimal); method public final void setScreenBrightnessRampSlowIncrease(java.math.BigDecimal); + method public final void setThermalThrottling(@NonNull com.android.server.display.config.ThermalThrottling); } public class DisplayQuirks { @@ -131,6 +146,12 @@ package com.android.server.display.config { enum_constant public static final com.android.server.display.config.ThermalStatus shutdown; } + public class ThermalThrottling { + ctor public ThermalThrottling(); + method @NonNull public final com.android.server.display.config.BrightnessThrottlingMap getBrightnessThrottlingMap(); + method public final void setBrightnessThrottlingMap(@NonNull com.android.server.display.config.BrightnessThrottlingMap); + } + public class Thresholds { ctor public Thresholds(); method @NonNull public final com.android.server.display.config.BrightnessThresholds getBrighteningThresholds(); diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java new file mode 100644 index 0000000000000..a65b41d68d551 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2022 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.display; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import android.os.PowerManager; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel; +import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@SmallTest +@Presubmit +@RunWith(AndroidJUnit4.class) +public class BrightnessThrottlerTest { + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + ///////////////// + // Test Methods + ///////////////// + + @Test + public void testBrightnessThrottlingData() { + List singleLevel = new ArrayList<>(); + singleLevel.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.25f)); + + List validLevels = new ArrayList<>(); + validLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.62f)); + validLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.25f)); + + List invalidThermalLevels = new ArrayList<>(); + invalidThermalLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.62f)); + invalidThermalLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.25f)); + + List invalidBrightnessLevels = new ArrayList<>(); + invalidBrightnessLevels.add( + new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.25f)); + invalidBrightnessLevels.add( + new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.62f)); + + List invalidLevels = new ArrayList<>(); + invalidLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.25f)); + invalidLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.62f)); + + // Test invalid data + BrightnessThrottlingData data; + data = BrightnessThrottlingData.create((List)null); + assertEquals(data, null); + data = BrightnessThrottlingData.create((BrightnessThrottlingData)null); + assertEquals(data, null); + data = BrightnessThrottlingData.create(new ArrayList()); + assertEquals(data, null); + data = BrightnessThrottlingData.create(invalidThermalLevels); + assertEquals(data, null); + data = BrightnessThrottlingData.create(invalidBrightnessLevels); + assertEquals(data, null); + data = BrightnessThrottlingData.create(invalidLevels); + assertEquals(data, null); + + // Test valid data + data = BrightnessThrottlingData.create(singleLevel); + assertNotEquals(data, null); + assertThrottlingLevelsEquals(singleLevel, data.throttlingLevels); + + data = BrightnessThrottlingData.create(validLevels); + assertNotEquals(data, null); + assertThrottlingLevelsEquals(validLevels, data.throttlingLevels); + } + + private void assertThrottlingLevelsEquals( + List expected, + List actual) { + assertEquals(expected.size(), actual.size()); + + for (int i = 0; i < expected.size(); i++) { + ThrottlingLevel expectedLevel = expected.get(i); + ThrottlingLevel actualLevel = actual.get(i); + + assertEquals(expectedLevel.thermalStatus, actualLevel.thermalStatus); + assertEquals(expectedLevel.brightness, actualLevel.brightness, 0.0f); + } + } + +}