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); + } + } + +}