diff options
| author | 2022-06-24 20:27:05 +0000 | |
|---|---|---|
| committer | 2022-06-24 20:27:05 +0000 | |
| commit | b0c536ee88b19fcdb222dffca6f6f87d188ae9c2 (patch) | |
| tree | 8ceefd3ff5da4e8c24fdeb491421ae2981b0d1dc | |
| parent | 4a02e46b605756e6af42971118be59da64641d48 (diff) | |
| parent | c5f1c156ba428c1635487bf0c5995cf093a8deeb (diff) | |
Merge "Brightnessthrottler updateable through DeviceConfig" into tm-qpr-dev am: c5f1c156ba
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18740932
Change-Id: I28ff59074b53bf8c5c06e7054a4d9831ac61bbbb
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
6 files changed, 438 insertions, 24 deletions
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index b505395a091a..8bc11cbc61de 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -1448,5 +1448,15 @@ public final class DisplayManager { * @hide */ String KEY_HIGH_REFRESH_RATE_BLACKLIST = "high_refresh_rate_blacklist"; + + /** + * Key for the brightness throttling data as a String formatted: + * <displayId>,<no of throttling levels>,[<severity as string>,<brightness cap>] + * Where the latter part is repeated for each throttling level, and the entirety is repeated + * for each display, separated by a semicolon. + * For example: + * 123,1,critical,0.8;456,2,moderate,0.9,critical,0.7 + */ + String KEY_BRIGHTNESS_THROTTLING_DATA = "brightness_throttling_data"; } } diff --git a/services/core/java/com/android/server/display/BrightnessThrottler.java b/services/core/java/com/android/server/display/BrightnessThrottler.java index 767b2d18a69a..eccee52f37aa 100644 --- a/services/core/java/com/android/server/display/BrightnessThrottler.java +++ b/services/core/java/com/android/server/display/BrightnessThrottler.java @@ -16,21 +16,31 @@ package com.android.server.display; +import android.annotation.NonNull; import android.content.Context; import android.hardware.display.BrightnessInfo; +import android.hardware.display.DisplayManager; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.IThermalEventListener; import android.os.IThermalService; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; import android.os.Temperature; +import android.provider.DeviceConfig; +import android.provider.DeviceConfigInterface; import android.util.Slog; -import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel; +import com.android.internal.annotations.VisibleForTesting; import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData; +import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.Executor; /** * This class monitors various conditions, such as skin temperature throttling status, and limits @@ -44,28 +54,54 @@ class BrightnessThrottler { private final Injector mInjector; private final Handler mHandler; - private BrightnessThrottlingData mThrottlingData; + // We need a separate handler for unit testing. These two handlers are the same throughout the + // non-test code. + private final Handler mDeviceConfigHandler; private final Runnable mThrottlingChangeCallback; private final SkinThermalStatusObserver mSkinThermalStatusObserver; + private final DeviceConfigListener mDeviceConfigListener; + private final DeviceConfigInterface mDeviceConfig; + private int mThrottlingStatus; + private BrightnessThrottlingData mThrottlingData; + private BrightnessThrottlingData mDdcThrottlingData; private float mBrightnessCap = PowerManager.BRIGHTNESS_MAX; private @BrightnessInfo.BrightnessMaxReason int mBrightnessMaxReason = BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE; + private String mUniqueDisplayId; + + // The most recent string that has been set from DeviceConfig + private String mBrightnessThrottlingDataString; + + // This is a collection of brightness throttling data that has been written as overrides from + // the DeviceConfig. This will always take priority over the display device config data. + private HashMap<String, BrightnessThrottlingData> mBrightnessThrottlingDataOverride = + new HashMap<>(1); BrightnessThrottler(Handler handler, BrightnessThrottlingData throttlingData, - Runnable throttlingChangeCallback) { - this(new Injector(), handler, throttlingData, throttlingChangeCallback); + Runnable throttlingChangeCallback, String uniqueDisplayId) { + this(new Injector(), handler, handler, throttlingData, throttlingChangeCallback, + uniqueDisplayId); } - BrightnessThrottler(Injector injector, Handler handler, BrightnessThrottlingData throttlingData, - Runnable throttlingChangeCallback) { + @VisibleForTesting + BrightnessThrottler(Injector injector, Handler handler, Handler deviceConfigHandler, + BrightnessThrottlingData throttlingData, Runnable throttlingChangeCallback, + String uniqueDisplayId) { mInjector = injector; + mHandler = handler; + mDeviceConfigHandler = deviceConfigHandler; mThrottlingData = throttlingData; + mDdcThrottlingData = throttlingData; mThrottlingChangeCallback = throttlingChangeCallback; mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler); - resetThrottlingData(mThrottlingData); + mUniqueDisplayId = uniqueDisplayId; + mDeviceConfig = injector.getDeviceConfig(); + mDeviceConfigListener = new DeviceConfigListener(); + + resetThrottlingData(mThrottlingData, mUniqueDisplayId); } boolean deviceSupportsThrottling() { @@ -86,7 +122,7 @@ class BrightnessThrottler { void stop() { mSkinThermalStatusObserver.stopObserving(); - + mDeviceConfig.removeOnPropertiesChangedListener(mDeviceConfigListener); // We're asked to stop throttling, so reset brightness restrictions. mBrightnessCap = PowerManager.BRIGHTNESS_MAX; mBrightnessMaxReason = BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE; @@ -97,9 +133,19 @@ class BrightnessThrottler { mThrottlingStatus = THROTTLING_INVALID; } - void resetThrottlingData(BrightnessThrottlingData throttlingData) { + private void resetThrottlingData() { + resetThrottlingData(mDdcThrottlingData, mUniqueDisplayId); + } + + void resetThrottlingData(BrightnessThrottlingData throttlingData, String displayId) { stop(); - mThrottlingData = throttlingData; + + mUniqueDisplayId = displayId; + mDdcThrottlingData = throttlingData; + mDeviceConfigListener.startListening(); + reloadBrightnessThrottlingDataOverride(); + mThrottlingData = mBrightnessThrottlingDataOverride.getOrDefault(mUniqueDisplayId, + throttlingData); if (deviceSupportsThrottling()) { mSkinThermalStatusObserver.startObserving(); @@ -173,14 +219,148 @@ class BrightnessThrottler { private void dumpLocal(PrintWriter pw) { pw.println("BrightnessThrottler:"); pw.println(" mThrottlingData=" + mThrottlingData); + pw.println(" mDdcThrottlingData=" + mDdcThrottlingData); + pw.println(" mUniqueDisplayId=" + mUniqueDisplayId); pw.println(" mThrottlingStatus=" + mThrottlingStatus); pw.println(" mBrightnessCap=" + mBrightnessCap); pw.println(" mBrightnessMaxReason=" + BrightnessInfo.briMaxReasonToString(mBrightnessMaxReason)); + pw.println(" mBrightnessThrottlingDataOverride=" + mBrightnessThrottlingDataOverride); + pw.println(" mBrightnessThrottlingDataString=" + mBrightnessThrottlingDataString); mSkinThermalStatusObserver.dump(pw); } + private String getBrightnessThrottlingDataString() { + return mDeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.DeviceConfig.KEY_BRIGHTNESS_THROTTLING_DATA, + /* defaultValue= */ null); + } + + private boolean parseAndSaveData(@NonNull String strArray, + @NonNull HashMap<String, BrightnessThrottlingData> tempBrightnessThrottlingData) { + boolean validConfig = true; + String[] items = strArray.split(","); + int i = 0; + + try { + String uniqueDisplayId = items[i++]; + + // number of throttling points + int noOfThrottlingPoints = Integer.parseInt(items[i++]); + List<ThrottlingLevel> throttlingLevels = new ArrayList<>(noOfThrottlingPoints); + + // throttling level and point + for (int j = 0; j < noOfThrottlingPoints; j++) { + String severity = items[i++]; + int status = parseThermalStatus(severity); + + float brightnessPoint = parseBrightness(items[i++]); + + throttlingLevels.add(new ThrottlingLevel(status, brightnessPoint)); + } + BrightnessThrottlingData toSave = + DisplayDeviceConfig.BrightnessThrottlingData.create(throttlingLevels); + tempBrightnessThrottlingData.put(uniqueDisplayId, toSave); + } catch (NumberFormatException | IndexOutOfBoundsException + | UnknownThermalStatusException e) { + validConfig = false; + Slog.e(TAG, "Throttling data is invalid array: '" + strArray + "'", e); + } + + if (i != items.length) { + validConfig = false; + } + + return validConfig; + } + + public void reloadBrightnessThrottlingDataOverride() { + HashMap<String, BrightnessThrottlingData> tempBrightnessThrottlingData = + new HashMap<>(1); + mBrightnessThrottlingDataString = getBrightnessThrottlingDataString(); + boolean validConfig = true; + mBrightnessThrottlingDataOverride.clear(); + if (mBrightnessThrottlingDataString != null) { + String[] throttlingDataSplits = mBrightnessThrottlingDataString.split(";"); + for (String s : throttlingDataSplits) { + if (!parseAndSaveData(s, tempBrightnessThrottlingData)) { + validConfig = false; + break; + } + } + + if (validConfig) { + mBrightnessThrottlingDataOverride.putAll(tempBrightnessThrottlingData); + tempBrightnessThrottlingData.clear(); + } + + } else { + Slog.w(TAG, "DeviceConfig BrightnessThrottlingData is null"); + } + } + + /** + * Listens to config data change and updates the brightness throttling data using + * DisplayManager#KEY_BRIGHTNESS_THROTTLING_DATA. + * The format should be a string similar to: "local:4619827677550801152,2,moderate,0.5,severe, + * 0.379518072;local:4619827677550801151,1,moderate,0.75" + * In this order: + * <displayId>,<no of throttling levels>,[<severity as string>,<brightness cap>] + * Where the latter part is repeated for each throttling level, and the entirety is repeated + * for each display, separated by a semicolon. + */ + public class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener { + public Executor mExecutor = new HandlerExecutor(mDeviceConfigHandler); + + public void startListening() { + mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + mExecutor, this); + } + + @Override + public void onPropertiesChanged(DeviceConfig.Properties properties) { + reloadBrightnessThrottlingDataOverride(); + resetThrottlingData(); + } + } + + private float parseBrightness(String intVal) throws NumberFormatException { + float value = Float.parseFloat(intVal); + if (value < PowerManager.BRIGHTNESS_MIN || value > PowerManager.BRIGHTNESS_MAX) { + throw new NumberFormatException("Brightness constraint value out of bounds."); + } + return value; + } + + @PowerManager.ThermalStatus private int parseThermalStatus(@NonNull String value) + throws UnknownThermalStatusException { + switch (value) { + case "none": + return PowerManager.THERMAL_STATUS_NONE; + case "light": + return PowerManager.THERMAL_STATUS_LIGHT; + case "moderate": + return PowerManager.THERMAL_STATUS_MODERATE; + case "severe": + return PowerManager.THERMAL_STATUS_SEVERE; + case "critical": + return PowerManager.THERMAL_STATUS_CRITICAL; + case "emergency": + return PowerManager.THERMAL_STATUS_EMERGENCY; + case "shutdown": + return PowerManager.THERMAL_STATUS_SHUTDOWN; + default: + throw new UnknownThermalStatusException("Invalid Thermal Status: " + value); + } + } + + private static class UnknownThermalStatusException extends Exception { + UnknownThermalStatusException(String message) { + super(message); + } + } + private final class SkinThermalStatusObserver extends IThermalEventListener.Stub { private final Injector mInjector; private final Handler mHandler; @@ -258,5 +438,10 @@ class BrightnessThrottler { return IThermalService.Stub.asInterface( ServiceManager.getService(Context.THERMAL_SERVICE)); } + + @NonNull + public DeviceConfigInterface getDeviceConfig() { + return DeviceConfigInterface.REAL; + } } } diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index a25ac210f9c8..2322280d8a9b 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -279,9 +279,13 @@ public class DisplayDeviceConfig { private HighBrightnessModeData mHbmData; private DensityMapping mDensityMapping; private String mLoadedFrom = null; + private Spline mSdrToHdrRatioSpline; + // Brightness Throttling data may be updated via the DeviceConfig. Here we store the original + // data, which comes from the ddc, and the current one, which may be the DeviceConfig + // overwritten value. private BrightnessThrottlingData mBrightnessThrottlingData; - private Spline mSdrToHdrRatioSpline; + private BrightnessThrottlingData mOriginalBrightnessThrottlingData; private DisplayDeviceConfig(Context context) { mContext = context; @@ -422,6 +426,10 @@ public class DisplayDeviceConfig { return config; } + void setBrightnessThrottlingData(BrightnessThrottlingData brightnessThrottlingData) { + mBrightnessThrottlingData = brightnessThrottlingData; + } + /** * Return the brightness mapping nits array. * @@ -637,6 +645,7 @@ public class DisplayDeviceConfig { + ", mHbmData=" + mHbmData + ", mSdrToHdrRatioSpline=" + mSdrToHdrRatioSpline + ", mBrightnessThrottlingData=" + mBrightnessThrottlingData + + ", mOriginalBrightnessThrottlingData=" + mOriginalBrightnessThrottlingData + ", mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease + ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease + ", mBrightnessRampSlowDecrease=" + mBrightnessRampSlowDecrease @@ -932,6 +941,7 @@ public class DisplayDeviceConfig { if (!badConfig) { mBrightnessThrottlingData = BrightnessThrottlingData.create(throttlingLevels); + mOriginalBrightnessThrottlingData = mBrightnessThrottlingData; } } @@ -1407,7 +1417,9 @@ public class DisplayDeviceConfig { /** * Container for brightness throttling data. */ - static class BrightnessThrottlingData { + public static class BrightnessThrottlingData { + public List<ThrottlingLevel> throttlingLevels; + static class ThrottlingLevel { public @PowerManager.ThermalStatus int thermalStatus; public float brightness; @@ -1421,9 +1433,25 @@ public class DisplayDeviceConfig { public String toString() { return "[" + thermalStatus + "," + brightness + "]"; } - } - public List<ThrottlingLevel> throttlingLevels; + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ThrottlingLevel)) { + return false; + } + ThrottlingLevel otherThrottlingLevel = (ThrottlingLevel) obj; + + return otherThrottlingLevel.thermalStatus == this.thermalStatus + && otherThrottlingLevel.brightness == this.brightness; + } + @Override + public int hashCode() { + int result = 1; + result = 31 * result + thermalStatus; + result = 31 * result + Float.hashCode(brightness); + return result; + } + } static public BrightnessThrottlingData create(List<ThrottlingLevel> throttlingLevels) { @@ -1482,12 +1510,30 @@ public class DisplayDeviceConfig { + "} "; } + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (!(obj instanceof BrightnessThrottlingData)) { + return false; + } + + BrightnessThrottlingData otherBrightnessThrottlingData = (BrightnessThrottlingData) obj; + return throttlingLevels.equals(otherBrightnessThrottlingData.throttlingLevels); + } + + @Override + public int hashCode() { + return throttlingLevels.hashCode(); + } + private BrightnessThrottlingData(List<ThrottlingLevel> inLevels) { throttlingLevels = new ArrayList<>(inLevels.size()); for (ThrottlingLevel level : inLevels) { throttlingLevels.add(new ThrottlingLevel(level.thermalStatus, level.brightness)); } } - } } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index d05a902c6593..f9ee7f7f87a7 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -861,7 +861,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } }); mBrightnessThrottler.resetThrottlingData( - mDisplayDeviceConfig.getBrightnessThrottlingData()); + mDisplayDeviceConfig.getBrightnessThrottlingData(), mUniqueDisplayId); } private void sendUpdatePowerState() { @@ -1816,7 +1816,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call () -> { sendUpdatePowerStateLocked(); postBrightnessChangeRunnable(); - }); + }, mUniqueDisplayId); } private void blockScreenOn() { diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java index 0ed90d27db99..6a6cd6c914a2 100644 --- a/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java +++ b/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java @@ -16,13 +16,11 @@ package com.android.server.display; -import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -34,17 +32,18 @@ import android.os.IThermalEventListener; import android.os.IThermalService; import android.os.Message; import android.os.PowerManager; -import android.os.Temperature.ThrottlingStatus; import android.os.Temperature; +import android.os.Temperature.ThrottlingStatus; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.os.BackgroundThread; import com.android.server.display.BrightnessThrottler.Injector; -import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel; import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData; +import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel; import org.junit.Before; import org.junit.Test; @@ -55,7 +54,6 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; @SmallTest @@ -70,6 +68,8 @@ public class BrightnessThrottlerTest { @Mock IThermalService mThermalServiceMock; @Mock Injector mInjectorMock; + DisplayModeDirectorTest.FakeDeviceConfig mDeviceConfigFake; + @Captor ArgumentCaptor<IThermalEventListener> mThermalEventListenerCaptor; @Before @@ -83,6 +83,8 @@ public class BrightnessThrottlerTest { return true; } }); + mDeviceConfigFake = new DisplayModeDirectorTest.FakeDeviceConfig(); + when(mInjectorMock.getDeviceConfig()).thenReturn(mDeviceConfigFake); } @@ -292,6 +294,170 @@ public class BrightnessThrottlerTest { assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE, throttler.getBrightnessMaxReason()); } + @Test public void testUpdateThrottlingData() throws Exception { + // Initialise brightness throttling levels + // Ensure that they are overridden by setting the data through device config. + final ThrottlingLevel level = new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, + 0.25f); + List<ThrottlingLevel> levels = new ArrayList<>(); + levels.add(level); + final BrightnessThrottlingData data = BrightnessThrottlingData.create(levels); + mDeviceConfigFake.setBrightnessThrottlingData("123,1,critical,0.4"); + final BrightnessThrottler throttler = createThrottlerSupported(data); + + verify(mThermalServiceMock).registerThermalEventListenerWithType( + mThermalEventListenerCaptor.capture(), eq(Temperature.TYPE_SKIN)); + final IThermalEventListener listener = mThermalEventListenerCaptor.getValue(); + + // Set status too low to trigger throttling + listener.notifyThrottling(getSkinTemp(level.thermalStatus - 1)); + mTestLooper.dispatchAll(); + assertEquals(PowerManager.BRIGHTNESS_MAX, throttler.getBrightnessCap(), 0f); + assertFalse(throttler.isThrottled()); + + // Set status high enough to trigger throttling + listener.notifyThrottling(getSkinTemp(level.thermalStatus)); + mTestLooper.dispatchAll(); + assertEquals(0.4f, throttler.getBrightnessCap(), 0f); + assertTrue(throttler.isThrottled()); + + // Update thresholds + // This data is equivalent to the string "123,1,critical,0.8", passed below + final ThrottlingLevel newLevel = new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, + 0.8f); + // Set new (valid) data from device config + mDeviceConfigFake.setBrightnessThrottlingData("123,1,critical,0.8"); + + // Set status too low to trigger throttling + listener.notifyThrottling(getSkinTemp(newLevel.thermalStatus - 1)); + mTestLooper.dispatchAll(); + assertEquals(PowerManager.BRIGHTNESS_MAX, throttler.getBrightnessCap(), 0f); + assertFalse(throttler.isThrottled()); + + // Set status high enough to trigger throttling + listener.notifyThrottling(getSkinTemp(newLevel.thermalStatus)); + mTestLooper.dispatchAll(); + assertEquals(newLevel.brightness, throttler.getBrightnessCap(), 0f); + assertTrue(throttler.isThrottled()); + } + + @Test public void testInvalidThrottlingStrings() throws Exception { + // Initialise brightness throttling levels + // Ensure that they are not overridden by invalid data through device config. + final ThrottlingLevel level = new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, + 0.25f); + List<ThrottlingLevel> levels = new ArrayList<>(); + levels.add(level); + final BrightnessThrottlingData data = BrightnessThrottlingData.create(levels); + final BrightnessThrottler throttler = createThrottlerSupported(data); + verify(mThermalServiceMock).registerThermalEventListenerWithType( + mThermalEventListenerCaptor.capture(), eq(Temperature.TYPE_SKIN)); + final IThermalEventListener listener = mThermalEventListenerCaptor.getValue(); + + // None of these are valid so shouldn't override the original data + mDeviceConfigFake.setBrightnessThrottlingData("321,1,critical,0.4"); // Not the current id + testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + mDeviceConfigFake.setBrightnessThrottlingData("123,0,critical,0.4"); // Incorrect number + testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + mDeviceConfigFake.setBrightnessThrottlingData("123,2,critical,0.4"); // Incorrect number + testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + mDeviceConfigFake.setBrightnessThrottlingData("123,1,invalid,0.4"); // Invalid level + testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + mDeviceConfigFake.setBrightnessThrottlingData("123,1,critical,none"); // Invalid brightness + testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + mDeviceConfigFake.setBrightnessThrottlingData("123,1,critical,-3"); // Invalid brightness + testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + mDeviceConfigFake.setBrightnessThrottlingData("invalid string"); // Invalid format + testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + mDeviceConfigFake.setBrightnessThrottlingData(""); // Invalid format + testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + } + + private void testThrottling(BrightnessThrottler throttler, IThermalEventListener listener, + float tooLowCap, float tooHighCap) throws Exception { + final ThrottlingLevel level = new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, + tooHighCap); + + // Set status too low to trigger throttling + listener.notifyThrottling(getSkinTemp(level.thermalStatus - 1)); + mTestLooper.dispatchAll(); + assertEquals(tooLowCap, throttler.getBrightnessCap(), 0f); + assertFalse(throttler.isThrottled()); + + // Set status high enough to trigger throttling + listener.notifyThrottling(getSkinTemp(level.thermalStatus)); + mTestLooper.dispatchAll(); + assertEquals(tooHighCap, throttler.getBrightnessCap(), 0f); + assertTrue(throttler.isThrottled()); + } + + @Test public void testMultipleConfigPoints() throws Exception { + // Initialise brightness throttling levels + final ThrottlingLevel level = new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, + 0.25f); + List<ThrottlingLevel> levels = new ArrayList<>(); + levels.add(level); + final BrightnessThrottlingData data = BrightnessThrottlingData.create(levels); + + // These are identical to the string set below + final ThrottlingLevel levelSevere = new ThrottlingLevel(PowerManager.THERMAL_STATUS_SEVERE, + 0.9f); + final ThrottlingLevel levelCritical = new ThrottlingLevel( + PowerManager.THERMAL_STATUS_CRITICAL, 0.5f); + final ThrottlingLevel levelEmergency = new ThrottlingLevel( + PowerManager.THERMAL_STATUS_EMERGENCY, 0.1f); + + mDeviceConfigFake.setBrightnessThrottlingData( + "123,3,severe,0.9,critical,0.5,emergency,0.1"); + final BrightnessThrottler throttler = createThrottlerSupported(data); + + verify(mThermalServiceMock).registerThermalEventListenerWithType( + mThermalEventListenerCaptor.capture(), eq(Temperature.TYPE_SKIN)); + final IThermalEventListener listener = mThermalEventListenerCaptor.getValue(); + + // Ensure that the multiple levels set via the string through the device config correctly + // override the original display device config ones. + + // levelSevere + // Set status too low to trigger throttling + listener.notifyThrottling(getSkinTemp(levelSevere.thermalStatus - 1)); + mTestLooper.dispatchAll(); + assertEquals(PowerManager.BRIGHTNESS_MAX, throttler.getBrightnessCap(), 0f); + assertFalse(throttler.isThrottled()); + + // Set status high enough to trigger throttling + listener.notifyThrottling(getSkinTemp(levelSevere.thermalStatus)); + mTestLooper.dispatchAll(); + assertEquals(0.9f, throttler.getBrightnessCap(), 0f); + assertTrue(throttler.isThrottled()); + + // levelCritical + // Set status too low to trigger throttling + listener.notifyThrottling(getSkinTemp(levelCritical.thermalStatus - 1)); + mTestLooper.dispatchAll(); + assertEquals(0.9f, throttler.getBrightnessCap(), 0f); + assertTrue(throttler.isThrottled()); + + // Set status high enough to trigger throttling + listener.notifyThrottling(getSkinTemp(levelCritical.thermalStatus)); + mTestLooper.dispatchAll(); + assertEquals(0.5f, throttler.getBrightnessCap(), 0f); + assertTrue(throttler.isThrottled()); + + //levelEmergency + // Set status too low to trigger throttling + listener.notifyThrottling(getSkinTemp(levelEmergency.thermalStatus - 1)); + mTestLooper.dispatchAll(); + assertEquals(0.5f, throttler.getBrightnessCap(), 0f); + assertTrue(throttler.isThrottled()); + + // Set status high enough to trigger throttling + listener.notifyThrottling(getSkinTemp(levelEmergency.thermalStatus)); + mTestLooper.dispatchAll(); + assertEquals(0.1f, throttler.getBrightnessCap(), 0f); + assertTrue(throttler.isThrottled()); + } + private void assertThrottlingLevelsEquals( List<ThrottlingLevel> expected, List<ThrottlingLevel> actual) { @@ -307,12 +473,13 @@ public class BrightnessThrottlerTest { } private BrightnessThrottler createThrottlerUnsupported() { - return new BrightnessThrottler(mInjectorMock, mHandler, null, () -> {}); + return new BrightnessThrottler(mInjectorMock, mHandler, mHandler, null, () -> {}, null); } private BrightnessThrottler createThrottlerSupported(BrightnessThrottlingData data) { assertNotNull(data); - return new BrightnessThrottler(mInjectorMock, mHandler, data, () -> {}); + return new BrightnessThrottler(mInjectorMock, mHandler, BackgroundThread.getHandler(), + data, () -> {}, "123"); } private Temperature getSkinTemp(@ThrottlingStatus int status) { diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java index 864f31552ae3..968e1d8c546b 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java @@ -16,6 +16,7 @@ package com.android.server.display; +import static android.hardware.display.DisplayManager.DeviceConfig.KEY_BRIGHTNESS_THROTTLING_DATA; import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS; 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; @@ -1902,6 +1903,11 @@ public class DisplayModeDirectorTest { KEY_REFRESH_RATE_IN_HBM_HDR, String.valueOf(fps)); } + void setBrightnessThrottlingData(String brightnessThrottlingData) { + putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + KEY_BRIGHTNESS_THROTTLING_DATA, brightnessThrottlingData); + } + void setLowDisplayBrightnessThresholds(int[] brightnessThresholds) { String thresholds = toPropertyValue(brightnessThresholds); |