diff options
14 files changed, 399 insertions, 78 deletions
diff --git a/services/core/java/com/android/server/display/BrightnessThrottler.java b/services/core/java/com/android/server/display/BrightnessThrottler.java index bba5ba35dbc7..631e7518b746 100644 --- a/services/core/java/com/android/server/display/BrightnessThrottler.java +++ b/services/core/java/com/android/server/display/BrightnessThrottler.java @@ -37,9 +37,11 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData; import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel; +import com.android.server.display.config.SensorData; import com.android.server.display.feature.DeviceConfigParameterProvider; import com.android.server.display.utils.DebugUtils; import com.android.server.display.utils.DeviceConfigParsingUtils; +import com.android.server.display.utils.SensorUtils; import java.io.PrintWriter; import java.util.HashMap; @@ -79,7 +81,7 @@ class BrightnessThrottler { // Maps the throttling ID to the data. Sourced from DisplayDeviceConfig. @NonNull - private HashMap<String, ThermalBrightnessThrottlingData> mDdcThermalThrottlingDataMap; + private Map<String, ThermalBrightnessThrottlingData> mDdcThermalThrottlingDataMap; // Current throttling data being used. // Null if we do not support throttling. @@ -97,6 +99,10 @@ class BrightnessThrottler { // The brightness throttling configuration that should be used. private String mThermalBrightnessThrottlingDataId; + // Temperature Sensor to be monitored for throttling. + @NonNull + private SensorData mTempSensor; + // 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. // We need to store the data for every display device, so we do not need to update this each @@ -121,17 +127,19 @@ class BrightnessThrottler { BrightnessThrottler(Handler handler, Runnable throttlingChangeCallback, String uniqueDisplayId, String throttlingDataId, - @NonNull HashMap<String, ThermalBrightnessThrottlingData> - thermalBrightnessThrottlingDataMap) { - this(new Injector(), handler, handler, throttlingChangeCallback, - uniqueDisplayId, throttlingDataId, thermalBrightnessThrottlingDataMap); + @NonNull DisplayDeviceConfig displayDeviceConfig) { + this(new Injector(), handler, handler, throttlingChangeCallback, uniqueDisplayId, + throttlingDataId, + displayDeviceConfig.getThermalBrightnessThrottlingDataMapByThrottlingId(), + displayDeviceConfig.getTempSensor()); } @VisibleForTesting BrightnessThrottler(Injector injector, Handler handler, Handler deviceConfigHandler, Runnable throttlingChangeCallback, String uniqueDisplayId, String throttlingDataId, - @NonNull HashMap<String, ThermalBrightnessThrottlingData> - thermalBrightnessThrottlingDataMap) { + @NonNull Map<String, ThermalBrightnessThrottlingData> + thermalBrightnessThrottlingDataMap, + @NonNull SensorData tempSensor) { mInjector = injector; mHandler = handler; @@ -147,7 +155,7 @@ class BrightnessThrottler { mDdcThermalThrottlingDataMap = thermalBrightnessThrottlingDataMap; loadThermalBrightnessThrottlingDataFromDeviceConfig(); loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig(mDdcThermalThrottlingDataMap, - mThermalBrightnessThrottlingDataId, mUniqueDisplayId); + tempSensor, mThermalBrightnessThrottlingDataId, mUniqueDisplayId); } boolean deviceSupportsThrottling() { @@ -180,12 +188,14 @@ class BrightnessThrottler { } void loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig( - HashMap<String, ThermalBrightnessThrottlingData> ddcThrottlingDataMap, + Map<String, ThermalBrightnessThrottlingData> ddcThrottlingDataMap, + SensorData tempSensor, String brightnessThrottlingDataId, String uniqueDisplayId) { mDdcThermalThrottlingDataMap = ddcThrottlingDataMap; mThermalBrightnessThrottlingDataId = brightnessThrottlingDataId; mUniqueDisplayId = uniqueDisplayId; + mTempSensor = tempSensor; resetThermalThrottlingData(); } @@ -310,7 +320,7 @@ class BrightnessThrottler { } if (deviceSupportsThrottling()) { - mSkinThermalStatusObserver.startObserving(); + mSkinThermalStatusObserver.startObserving(mTempSensor); } } @@ -357,6 +367,7 @@ class BrightnessThrottler { private final class SkinThermalStatusObserver extends IThermalEventListener.Stub { private final Injector mInjector; private final Handler mHandler; + private SensorData mObserverTempSensor; private IThermalService mThermalService; private boolean mStarted; @@ -371,28 +382,51 @@ class BrightnessThrottler { if (DEBUG) { Slog.d(TAG, "New thermal throttling status = " + temp.getStatus()); } + + if (mObserverTempSensor.name != null + && !mObserverTempSensor.name.equals(temp.getName())) { + Slog.i(TAG, "Skipping thermal throttling notification as monitored sensor: " + + mObserverTempSensor.name + + " != notified sensor: " + + temp.getName()); + return; + } mHandler.post(() -> { final @Temperature.ThrottlingStatus int status = temp.getStatus(); thermalStatusChanged(status); }); } - void startObserving() { - if (mStarted) { + void startObserving(SensorData tempSensor) { + if (!mStarted || mObserverTempSensor == null) { + mObserverTempSensor = tempSensor; + registerThermalListener(); + return; + } + + String curType = mObserverTempSensor.type; + mObserverTempSensor = tempSensor; + if (curType.equals(tempSensor.type)) { if (DEBUG) { Slog.d(TAG, "Thermal status observer already started"); } return; } + stopObserving(); + registerThermalListener(); + } + + void registerThermalListener() { mThermalService = mInjector.getThermalService(); if (mThermalService == null) { Slog.e(TAG, "Could not observe thermal status. Service not available"); return; } + int temperatureType = SensorUtils.getSensorTemperatureType(mObserverTempSensor); try { // We get a callback immediately upon registering so there's no need to query // for the current value. - mThermalService.registerThermalEventListenerWithType(this, Temperature.TYPE_SKIN); + mThermalService.registerThermalEventListenerWithType(this, temperatureType); mStarted = true; } catch (RemoteException e) { Slog.e(TAG, "Failed to register thermal status listener", e); @@ -418,6 +452,7 @@ class BrightnessThrottler { void dump(PrintWriter writer) { writer.println(" SkinThermalStatusObserver:"); writer.println(" mStarted: " + mStarted); + writer.println(" mObserverTempSensor: " + mObserverTempSensor); if (mThermalService != null) { writer.println(" ThermalService available"); } else { diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index d1374a5ab9dc..9b2dcc53f456 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -384,6 +384,10 @@ import javax.xml.datatype.DatatypeConfigurationException; * </point> * </supportedModes> * </proxSensor> + * <tempSensor> + * <type>DISPLAY</type> + * <name>VIRTUAL-SKIN-DISPLAY</name> + * </tempSensor> * * <ambientLightHorizonLong>10001</ambientLightHorizonLong> * <ambientLightHorizonShort>2001</ambientLightHorizonShort> @@ -625,6 +629,12 @@ public class DisplayDeviceConfig { @Nullable private SensorData mProximitySensor; + // The details of the temperature sensor associated with this display. + // Throttling will be based on thermal status of this sensor. + // For empty values default back to sensor of TYPE_SKIN. + @NonNull + private SensorData mTempSensor; + private final List<RefreshRateLimitation> mRefreshRateLimitations = new ArrayList<>(2 /*initialCapacity*/); @@ -821,10 +831,10 @@ public class DisplayDeviceConfig { private String mLowBlockingZoneThermalMapId = null; private String mHighBlockingZoneThermalMapId = null; - private final HashMap<String, ThermalBrightnessThrottlingData> + private final Map<String, ThermalBrightnessThrottlingData> mThermalBrightnessThrottlingDataMapByThrottlingId = new HashMap<>(); - private final HashMap<String, PowerThrottlingData> + private final Map<String, PowerThrottlingData> mPowerThrottlingDataMapByThrottlingId = new HashMap<>(); private final Map<String, SparseArray<SurfaceControl.RefreshRateRange>> @@ -1489,6 +1499,13 @@ public class DisplayDeviceConfig { return mProximitySensor; } + /** + * @return temperature sensor data associated with the display. + */ + public SensorData getTempSensor() { + return mTempSensor; + } + boolean isAutoBrightnessAvailable() { return mAutoBrightnessAvailable; } @@ -1539,7 +1556,7 @@ public class DisplayDeviceConfig { /** * @return brightness throttling configuration data for this display, for each throttling id. */ - public HashMap<String, ThermalBrightnessThrottlingData> + public Map<String, ThermalBrightnessThrottlingData> getThermalBrightnessThrottlingDataMapByThrottlingId() { return mThermalBrightnessThrottlingDataMapByThrottlingId; } @@ -1558,7 +1575,7 @@ public class DisplayDeviceConfig { /** * @return power throttling configuration data for this display, for each throttling id. **/ - public HashMap<String, PowerThrottlingData> + public Map<String, PowerThrottlingData> getPowerThrottlingDataMapByThrottlingId() { return mPowerThrottlingDataMapByThrottlingId; } @@ -1871,6 +1888,7 @@ public class DisplayDeviceConfig { + "mAmbientLightSensor=" + mAmbientLightSensor + ", mScreenOffBrightnessSensor=" + mScreenOffBrightnessSensor + ", mProximitySensor=" + mProximitySensor + + ", mTempSensor=" + mTempSensor + ", mRefreshRateLimitations= " + Arrays.toString(mRefreshRateLimitations.toArray()) + ", mDensityMapping= " + mDensityMapping + ", mAutoBrightnessBrighteningLightDebounce= " @@ -1972,6 +1990,7 @@ public class DisplayDeviceConfig { mContext.getResources()); mScreenOffBrightnessSensor = SensorData.loadScreenOffBrightnessSensorConfig(config); mProximitySensor = SensorData.loadProxSensorConfig(config); + mTempSensor = SensorData.loadTempSensorConfig(mFlags, config); loadAmbientHorizonFromDdc(config); loadBrightnessChangeThresholds(config); loadAutoBrightnessConfigValues(config); @@ -1999,6 +2018,7 @@ public class DisplayDeviceConfig { loadBrightnessRampsFromConfigXml(); mAmbientLightSensor = SensorData.loadAmbientLightSensorConfig(mContext.getResources()); mProximitySensor = SensorData.loadSensorUnspecifiedConfig(); + mTempSensor = SensorData.loadTempSensorUnspecifiedConfig(); loadBrightnessChangeThresholdsFromXml(); loadAutoBrightnessConfigsFromConfigXml(); loadAutoBrightnessAvailableFromConfigXml(); @@ -2026,6 +2046,7 @@ public class DisplayDeviceConfig { setSimpleMappingStrategyValues(); mAmbientLightSensor = SensorData.loadAmbientLightSensorConfig(mContext.getResources()); mProximitySensor = SensorData.loadSensorUnspecifiedConfig(); + mTempSensor = SensorData.loadTempSensorUnspecifiedConfig(); loadAutoBrightnessAvailableFromConfigXml(); } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index d5863a73a0c3..3965d55b0c28 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -861,6 +861,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mThermalBrightnessThrottlingDataId = thermalBrightnessThrottlingDataId; mBrightnessThrottler.loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig( config.getThermalBrightnessThrottlingDataMapByThrottlingId(), + config.getTempSensor(), mThermalBrightnessThrottlingDataId, mUniqueDisplayId); } @@ -923,6 +924,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mBrightnessRangeController.loadFromConfig(hbmMetadata, token, info, mDisplayDeviceConfig); mBrightnessThrottler.loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig( mDisplayDeviceConfig.getThermalBrightnessThrottlingDataMapByThrottlingId(), + mDisplayDeviceConfig.getTempSensor(), mThermalBrightnessThrottlingDataId, mUniqueDisplayId); } @@ -1996,7 +1998,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call postBrightnessChangeRunnable(); }, mUniqueDisplayId, mLogicalDisplay.getDisplayInfoLocked().thermalBrightnessThrottlingDataId, - ddConfig.getThermalBrightnessThrottlingDataMapByThrottlingId()); + ddConfig); } private void blockScreenOn() { diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java index bc5fcb449c95..18e8fab54e3e 100644 --- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java +++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java @@ -38,6 +38,7 @@ import com.android.server.display.DisplayDeviceConfig.PowerThrottlingConfigData; import com.android.server.display.DisplayDeviceConfig.PowerThrottlingData; import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData; import com.android.server.display.brightness.BrightnessReason; +import com.android.server.display.config.SensorData; import com.android.server.display.feature.DeviceConfigParameterProvider; import com.android.server.display.feature.DisplayManagerFlags; @@ -336,5 +337,10 @@ public class BrightnessClamperController { public float getBrightnessWearBedtimeModeCap() { return mDisplayDeviceConfig.getBrightnessCapForWearBedtimeMode(); } + + @NonNull + public SensorData getTempSensor() { + return mDisplayDeviceConfig.getTempSensor(); + } } } diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessThermalClamper.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessThermalClamper.java index 944a8a65693b..449825831182 100644 --- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessThermalClamper.java +++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessThermalClamper.java @@ -35,8 +35,10 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData; import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel; +import com.android.server.display.config.SensorData; import com.android.server.display.feature.DeviceConfigParameterProvider; import com.android.server.display.utils.DeviceConfigParsingUtils; +import com.android.server.display.utils.SensorUtils; import java.io.PrintWriter; import java.util.List; @@ -49,9 +51,8 @@ class BrightnessThermalClamper extends BrightnessClamper<BrightnessThermalClamper.ThermalData> { private static final String TAG = "BrightnessThermalClamper"; - - @Nullable - private final IThermalService mThermalService; + @NonNull + private final ThermalStatusObserver mThermalStatusObserver; @NonNull private final DeviceConfigParameterProvider mConfigParameterProvider; // data from DeviceConfig, for all displays, for all dataSets @@ -66,7 +67,6 @@ class BrightnessThermalClamper extends // otherwise mDataFromDeviceConfig @Nullable private ThermalBrightnessThrottlingData mThermalThrottlingDataActive = null; - private boolean mStarted = false; @Nullable private String mUniqueDisplayId = null; @Nullable @@ -74,14 +74,6 @@ class BrightnessThermalClamper extends @Temperature.ThrottlingStatus private int mThrottlingStatus = Temperature.THROTTLING_NONE; - private final IThermalEventListener mThermalEventListener = new IThermalEventListener.Stub() { - @Override - public void notifyThrottling(Temperature temperature) { - @Temperature.ThrottlingStatus int status = temperature.getStatus(); - mHandler.post(() -> thermalStatusChanged(status)); - } - }; - private final BiFunction<String, String, ThrottlingLevel> mDataPointMapper = (key, value) -> { try { int status = DeviceConfigParsingUtils.parseThermalStatus(key); @@ -105,12 +97,11 @@ class BrightnessThermalClamper extends BrightnessThermalClamper(Injector injector, Handler handler, ClamperChangeListener listener, ThermalData thermalData) { super(handler, listener); - mThermalService = injector.getThermalService(); mConfigParameterProvider = injector.getDeviceConfigParameterProvider(); + mThermalStatusObserver = new ThermalStatusObserver(injector, handler); mHandler.post(() -> { setDisplayData(thermalData); loadOverrideData(); - start(); }); } @@ -139,32 +130,19 @@ class BrightnessThermalClamper extends @Override void stop() { - if (!mStarted) { - return; - } - try { - mThermalService.unregisterThermalEventListener(mThermalEventListener); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to unregister thermal status listener", e); - } - mStarted = false; + mThermalStatusObserver.stopObserving(); } @Override void dump(PrintWriter writer) { writer.println("BrightnessThermalClamper:"); - writer.println(" mStarted: " + mStarted); - if (mThermalService != null) { - writer.println(" ThermalService available"); - } else { - writer.println(" ThermalService not available"); - } writer.println(" mThrottlingStatus: " + mThrottlingStatus); writer.println(" mUniqueDisplayId: " + mUniqueDisplayId); writer.println(" mDataId: " + mDataId); writer.println(" mDataOverride: " + mThermalThrottlingDataOverride); writer.println(" mDataFromDeviceConfig: " + mThermalThrottlingDataFromDeviceConfig); writer.println(" mDataActive: " + mThermalThrottlingDataActive); + mThermalStatusObserver.dump(writer); super.dump(writer); } @@ -193,6 +171,7 @@ class BrightnessThermalClamper extends Slog.wtf(TAG, "Thermal throttling data is missing for thermalThrottlingDataId=" + mDataId); } + mThermalStatusObserver.registerSensor(data.getTempSensor()); } private void recalculateBrightnessCap() { @@ -226,19 +205,91 @@ class BrightnessThermalClamper extends } } - private void start() { - if (mThermalService == null) { - Slog.e(TAG, "Could not observe thermal status. Service not available"); - return; + + private final class ThermalStatusObserver extends IThermalEventListener.Stub { + private final Injector mInjector; + private final Handler mHandler; + private IThermalService mThermalService; + private boolean mStarted; + private SensorData mObserverTempSensor; + + ThermalStatusObserver(Injector injector, Handler handler) { + mInjector = injector; + mHandler = handler; + mStarted = false; } - try { - // We get a callback immediately upon registering so there's no need to query - // for the current value. - mThermalService.registerThermalEventListenerWithType(mThermalEventListener, - Temperature.TYPE_SKIN); - mStarted = true; - } catch (RemoteException e) { - Slog.e(TAG, "Failed to register thermal status listener", e); + + void registerSensor(SensorData tempSensor) { + if (!mStarted || mObserverTempSensor == null) { + mObserverTempSensor = tempSensor; + registerThermalListener(); + return; + } + + String curType = mObserverTempSensor.type; + mObserverTempSensor = tempSensor; + if (curType.equals(tempSensor.type)) { + Slog.d(TAG, "Thermal status observer already started"); + return; + } + stopObserving(); + registerThermalListener(); + } + + void registerThermalListener() { + mThermalService = mInjector.getThermalService(); + if (mThermalService == null) { + Slog.e(TAG, "Could not observe thermal status. Service not available"); + return; + } + int temperatureType = SensorUtils.getSensorTemperatureType(mObserverTempSensor); + try { + // We get a callback immediately upon registering so there's no need to query + // for the current value. + mThermalService.registerThermalEventListenerWithType(this, temperatureType); + mStarted = true; + } catch (RemoteException e) { + Slog.e(TAG, "Failed to register thermal status listener", e); + } + } + + @Override + public void notifyThrottling(Temperature temp) { + Slog.d(TAG, "New thermal throttling status = " + temp.getStatus()); + if (mObserverTempSensor.name != null + && !mObserverTempSensor.name.equals(temp.getName())) { + Slog.i(TAG, "Skipping thermal throttling notification as monitored sensor: " + + mObserverTempSensor.name + + " != notified sensor: " + + temp.getName()); + return; + } + @Temperature.ThrottlingStatus int status = temp.getStatus(); + mHandler.post(() -> thermalStatusChanged(status)); + } + + void stopObserving() { + if (!mStarted) { + return; + } + try { + mThermalService.unregisterThermalEventListener(this); + mStarted = false; + } catch (RemoteException e) { + Slog.e(TAG, "Failed to unregister thermal status listener", e); + } + mThermalService = null; + } + + void dump(PrintWriter writer) { + writer.println(" ThermalStatusObserver:"); + writer.println(" mStarted: " + mStarted); + writer.println(" mObserverTempSensor: " + mObserverTempSensor); + if (mThermalService != null) { + writer.println(" ThermalService available"); + } else { + writer.println(" ThermalService not available"); + } } } @@ -251,6 +302,9 @@ class BrightnessThermalClamper extends @Nullable ThermalBrightnessThrottlingData getThermalBrightnessThrottlingData(); + + @NonNull + SensorData getTempSensor(); } @VisibleForTesting diff --git a/services/core/java/com/android/server/display/config/SensorData.java b/services/core/java/com/android/server/display/config/SensorData.java index 3bb35bf7c49f..8e716f8380b6 100644 --- a/services/core/java/com/android/server/display/config/SensorData.java +++ b/services/core/java/com/android/server/display/config/SensorData.java @@ -22,6 +22,7 @@ import android.content.res.Resources; import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.display.feature.DisplayManagerFlags; import java.util.ArrayList; import java.util.Collections; @@ -32,6 +33,9 @@ import java.util.List; */ public class SensorData { + public static final String TEMPERATURE_TYPE_DISPLAY = "DISPLAY"; + public static final String TEMPERATURE_TYPE_SKIN = "SKIN"; + @Nullable public final String type; @Nullable @@ -143,6 +147,32 @@ public class SensorData { } /** + * Loads temperature sensor data for no config case. (Type: SKIN, Name: null) + */ + public static SensorData loadTempSensorUnspecifiedConfig() { + return new SensorData(TEMPERATURE_TYPE_SKIN, null); + } + + /** + * Loads temperature sensor data from given display config. + * If empty or null config given default to (Type: SKIN, Name: null) + */ + public static SensorData loadTempSensorConfig(DisplayManagerFlags flags, + DisplayConfiguration config) { + SensorDetails sensorDetails = config.getTempSensor(); + if (!flags.isSensorBasedBrightnessThrottlingEnabled() || sensorDetails == null) { + return new SensorData(TEMPERATURE_TYPE_SKIN, null); + } + String name = sensorDetails.getName(); + String type = sensorDetails.getType(); + if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) { + type = TEMPERATURE_TYPE_SKIN; + name = null; + } + return new SensorData(type, name); + } + + /** * Loads sensor unspecified config, this means system should use default sensor. * See also {@link com.android.server.display.utils.SensorUtils} */ diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java index 1ae255933f66..516d4b1d4125 100644 --- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java @@ -121,6 +121,11 @@ public class DisplayManagerFlags { Flags::refreshRateVotingTelemetry ); + private final FlagState mSensorBasedBrightnessThrottling = new FlagState( + Flags.FLAG_SENSOR_BASED_BRIGHTNESS_THROTTLING, + Flags::sensorBasedBrightnessThrottling + ); + /** * @return {@code true} if 'port' is allowed in display layout configuration file. */ @@ -247,6 +252,10 @@ public class DisplayManagerFlags { return mRefreshRateVotingTelemetry.isEnabled(); } + public boolean isSensorBasedBrightnessThrottlingEnabled() { + return mSensorBasedBrightnessThrottling.isEnabled(); + } + /** * dumps all flagstates * @param pw printWriter @@ -270,6 +279,7 @@ public class DisplayManagerFlags { pw.println(" " + mAutoBrightnessModesFlagState); pw.println(" " + mFastHdrTransitions); pw.println(" " + mRefreshRateVotingTelemetry); + pw.println(" " + mSensorBasedBrightnessThrottling); } private static class FlagState { diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig index c2f52b5ad8a0..63ab3a95822f 100644 --- a/services/core/java/com/android/server/display/feature/display_flags.aconfig +++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig @@ -184,3 +184,11 @@ flag { bug: "310029108" is_fixed_read_only: true } + +flag { + name: "sensor_based_brightness_throttling" + namespace: "display_manager" + description: "Feature flag for enabling brightness throttling using sensor from config." + bug: "294900859" + is_fixed_read_only: true +} diff --git a/services/core/java/com/android/server/display/utils/SensorUtils.java b/services/core/java/com/android/server/display/utils/SensorUtils.java index 8b9fe1083187..c63473a4b3d7 100644 --- a/services/core/java/com/android/server/display/utils/SensorUtils.java +++ b/services/core/java/com/android/server/display/utils/SensorUtils.java @@ -16,9 +16,11 @@ package com.android.server.display.utils; +import android.annotation.NonNull; import android.annotation.Nullable; import android.hardware.Sensor; import android.hardware.SensorManager; +import android.os.Temperature; import android.text.TextUtils; import com.android.server.display.config.SensorData; @@ -70,4 +72,17 @@ public class SensorUtils { return null; } + /** + * Convert string temperature type to its corresponding integer value. + */ + public static int getSensorTemperatureType(@NonNull SensorData tempSensor) { + if (tempSensor.type.equalsIgnoreCase(SensorData.TEMPERATURE_TYPE_DISPLAY)) { + return Temperature.TYPE_DISPLAY; + } else if (tempSensor.type.equalsIgnoreCase(SensorData.TEMPERATURE_TYPE_SKIN)) { + return Temperature.TYPE_SKIN; + } + throw new IllegalArgumentException( + "tempSensor doesn't support type: " + tempSensor.type); + } + } 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 a46916553abc..b38a2f9558e9 100644 --- a/services/core/xsd/display-device-config/display-device-config.xsd +++ b/services/core/xsd/display-device-config/display-device-config.xsd @@ -117,6 +117,9 @@ <xs:element type="sensorDetails" name="proxSensor"> <xs:annotation name="final"/> </xs:element> + <xs:element type="sensorDetails" name="tempSensor"> + <xs:annotation name="final"/> + </xs:element> <!-- Length of the ambient light horizon used to calculate the long & short term estimates of ambient light in milliseconds.--> diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt index 79ea274e2fca..b329db4a2076 100644 --- a/services/core/xsd/display-device-config/schema/current.txt +++ b/services/core/xsd/display-device-config/schema/current.txt @@ -133,6 +133,7 @@ package com.android.server.display.config { method public final java.math.BigDecimal getScreenBrightnessRampSlowIncreaseIdle(); method public final com.android.server.display.config.SensorDetails getScreenOffBrightnessSensor(); method public final com.android.server.display.config.IntegerArray getScreenOffBrightnessSensorValueToLux(); + method public final com.android.server.display.config.SensorDetails getTempSensor(); method @NonNull public final com.android.server.display.config.ThermalThrottling getThermalThrottling(); method public final com.android.server.display.config.UsiVersion getUsiVersion(); method public final void setAmbientBrightnessChangeThresholds(@NonNull com.android.server.display.config.Thresholds); @@ -167,6 +168,7 @@ package com.android.server.display.config { method public final void setScreenBrightnessRampSlowIncreaseIdle(java.math.BigDecimal); method public final void setScreenOffBrightnessSensor(com.android.server.display.config.SensorDetails); method public final void setScreenOffBrightnessSensorValueToLux(com.android.server.display.config.IntegerArray); + method public final void setTempSensor(com.android.server.display.config.SensorDetails); method public final void setThermalThrottling(@NonNull com.android.server.display.config.ThermalThrottling); method public final void setUsiVersion(com.android.server.display.config.UsiVersion); } diff --git a/services/tests/displayservicetests/src/com/android/server/display/BrightnessThrottlerTest.java b/services/tests/displayservicetests/src/com/android/server/display/BrightnessThrottlerTest.java index 8faaf5998d13..05c243fda2b8 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/BrightnessThrottlerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/BrightnessThrottlerTest.java @@ -43,6 +43,7 @@ import com.android.internal.os.BackgroundThread; import com.android.server.display.BrightnessThrottler.Injector; import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData; import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel; +import com.android.server.display.config.SensorData; import com.android.server.display.mode.DisplayModeDirectorTest; import org.junit.Before; @@ -56,6 +57,7 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; @SmallTest @RunWith(AndroidJUnit4.class) @@ -292,6 +294,53 @@ public class BrightnessThrottlerTest { assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE, throttler.getBrightnessMaxReason()); } + + @Test + public void testThermalThrottlingWithDisplaySensor() throws Exception { + final ThrottlingLevel level = + new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.25f); + List<ThrottlingLevel> levels = new ArrayList<>(List.of(level)); + final ThermalBrightnessThrottlingData data = ThermalBrightnessThrottlingData.create(levels); + final SensorData tempSensor = new SensorData("DISPLAY", "VIRTUAL-SKIN-DISPLAY"); + final BrightnessThrottler throttler = + createThrottlerSupportedWithTempSensor(data, tempSensor); + assertTrue(throttler.deviceSupportsThrottling()); + + verify(mThermalServiceMock) + .registerThermalEventListenerWithType( + mThermalEventListenerCaptor.capture(), eq(Temperature.TYPE_DISPLAY)); + final IThermalEventListener listener = mThermalEventListenerCaptor.getValue(); + + // Set VIRTUAL-SKIN-DISPLAY tatus too low to verify no throttling. + listener.notifyThrottling(getDisplayTempWithName(tempSensor.name, level.thermalStatus - 1)); + mTestLooper.dispatchAll(); + assertEquals(PowerManager.BRIGHTNESS_MAX, throttler.getBrightnessCap(), 0f); + assertFalse(throttler.isThrottled()); + assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE, throttler.getBrightnessMaxReason()); + + // Verify when skin sensor throttled, no brightness throttling triggered. + listener.notifyThrottling(getSkinTemp(level.thermalStatus + 1)); + mTestLooper.dispatchAll(); + assertEquals(PowerManager.BRIGHTNESS_MAX, throttler.getBrightnessCap(), 0f); + assertFalse(throttler.isThrottled()); + assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE, throttler.getBrightnessMaxReason()); + + // Verify when display sensor of another name throttled, no brightness throttling triggered. + listener.notifyThrottling(getDisplayTempWithName("ANOTHER-NAME", level.thermalStatus + 1)); + mTestLooper.dispatchAll(); + assertEquals(PowerManager.BRIGHTNESS_MAX, throttler.getBrightnessCap(), 0f); + assertFalse(throttler.isThrottled()); + assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE, throttler.getBrightnessMaxReason()); + + // Verify when display sensor of current name throttled, brightness throttling triggered. + listener.notifyThrottling(getDisplayTempWithName(tempSensor.name, level.thermalStatus + 1)); + mTestLooper.dispatchAll(); + assertEquals(level.brightness, throttler.getBrightnessCap(), 0f); + assertTrue(throttler.isThrottled()); + assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL, + throttler.getBrightnessMaxReason()); + } + @Test public void testUpdateThermalThrottlingData() throws Exception { // Initialise brightness throttling levels // Ensure that they are overridden by setting the data through device config. @@ -476,18 +525,30 @@ public class BrightnessThrottlerTest { return new BrightnessThrottler(mInjectorMock, mHandler, mHandler, /* throttlingChangeCallback= */ () -> {}, /* uniqueDisplayId= */ null, /* thermalThrottlingDataId= */ null, - /* thermalThrottlingDataMap= */ new HashMap<>(1)); + /* thermalThrottlingDataMap= */ new HashMap<>(1), + /* tempSensor= */ null); } private BrightnessThrottler createThrottlerSupported(ThermalBrightnessThrottlingData data) { + SensorData tempSensor = SensorData.loadTempSensorUnspecifiedConfig(); + return createThrottlerSupportedWithTempSensor(data, tempSensor); + } + private BrightnessThrottler createThrottlerSupportedWithTempSensor( + ThermalBrightnessThrottlingData data, SensorData tempSensor) { assertNotNull(data); - HashMap<String, ThermalBrightnessThrottlingData> throttlingDataMap = new HashMap<>(1); + Map<String, ThermalBrightnessThrottlingData> throttlingDataMap = new HashMap<>(1); throttlingDataMap.put("default", data); return new BrightnessThrottler(mInjectorMock, mHandler, BackgroundThread.getHandler(), - () -> {}, "123", "default", throttlingDataMap); + () -> {}, "123", "default", throttlingDataMap, tempSensor); } private Temperature getSkinTemp(@ThrottlingStatus int status) { return new Temperature(30.0f, Temperature.TYPE_SKIN, "test_skin_temp", status); } + + private Temperature getDisplayTempWithName( + String sensorName, @ThrottlingStatus int status) { + assertNotNull(sensorName); + return new Temperature(30.0f, Temperature.TYPE_DISPLAY, sensorName, status); + } } diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java index b29fc8828f58..2867041511b5 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java @@ -20,6 +20,7 @@ package com.android.server.display; import static com.android.internal.display.BrightnessSynchronizer.brightnessIntToFloat; import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT; import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE; +import static com.android.server.display.config.SensorData.TEMPERATURE_TYPE_SKIN; import static com.android.server.display.config.SensorData.SupportedMode; import static com.android.server.display.utils.DeviceConfigParsingUtils.ambientBrightnessThresholdsIntToFloat; import static com.android.server.display.utils.DeviceConfigParsingUtils.displayBrightnessThresholdsIntToFloat; @@ -106,6 +107,7 @@ public final class DisplayDeviceConfigTest { MockitoAnnotations.initMocks(this); when(mContext.getResources()).thenReturn(mResources); when(mFlags.areAutoBrightnessModesEnabled()).thenReturn(true); + when(mFlags.isSensorBasedBrightnessThrottlingEnabled()).thenReturn(true); mockDeviceConfigs(); } @@ -143,6 +145,8 @@ public final class DisplayDeviceConfigTest { assertEquals("", mDisplayDeviceConfig.getAmbientLightSensor().name); assertNull(mDisplayDeviceConfig.getProximitySensor().type); assertNull(mDisplayDeviceConfig.getProximitySensor().name); + assertEquals(TEMPERATURE_TYPE_SKIN, mDisplayDeviceConfig.getTempSensor().type); + assertNull(mDisplayDeviceConfig.getTempSensor().name); assertTrue(mDisplayDeviceConfig.isAutoBrightnessAvailable()); } @@ -592,6 +596,13 @@ public final class DisplayDeviceConfigTest { } @Test + public void testTempSensorFromDisplayConfig() throws IOException { + setupDisplayDeviceConfigFromDisplayConfigFile(); + assertEquals("DISPLAY", mDisplayDeviceConfig.getTempSensor().type); + assertEquals("VIRTUAL-SKIN-DISPLAY", mDisplayDeviceConfig.getTempSensor().name); + } + + @Test public void testBlockingZoneThresholdsFromDisplayConfig() throws IOException { setupDisplayDeviceConfigFromDisplayConfigFile(); @@ -1356,6 +1367,10 @@ public final class DisplayDeviceConfigTest { + "<name>Test Binned Brightness Sensor</name>\n" + "</screenOffBrightnessSensor>\n" + proxSensor + + "<tempSensor>\n" + + "<type>DISPLAY</type>\n" + + "<name>VIRTUAL-SKIN-DISPLAY</name>\n" + + "</tempSensor>\n" + "<ambientBrightnessChangeThresholds>\n" + "<brighteningThresholds>\n" + "<minimum>10</minimum>\n" diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessThermalClamperTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessThermalClamperTest.java index 37d0f6250aaf..34f352e7bf54 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessThermalClamperTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessThermalClamperTest.java @@ -37,10 +37,14 @@ import com.android.internal.annotations.Keep; import com.android.server.display.DisplayDeviceConfig; import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData; import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel; +import com.android.server.display.config.SensorData; import com.android.server.display.feature.DeviceConfigParameterProvider; import com.android.server.testutils.FakeDeviceConfigInterface; import com.android.server.testutils.TestHandler; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -50,9 +54,6 @@ import org.mockito.MockitoAnnotations; import java.util.List; -import junitparams.JUnitParamsRunner; -import junitparams.Parameters; - @RunWith(JUnitParamsRunner.class) public class BrightnessThermalClamperTest { @@ -125,13 +126,13 @@ public class BrightnessThermalClamperTest { public void testNotifyThrottlingAfterOnDisplayChange(List<ThrottlingLevel> throttlingLevels, @Temperature.ThrottlingStatus int throttlingStatus, boolean expectedActive, float expectedBrightness) throws RemoteException { - IThermalEventListener thermalEventListener = captureThermalEventListener(); + IThermalEventListener thermalEventListener = captureSkinThermalEventListener(); mClamper.onDisplayChanged(new TestThermalData(throttlingLevels)); mTestHandler.flush(); assertFalse(mClamper.isActive()); assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE); - thermalEventListener.notifyThrottling(createTemperature(throttlingStatus)); + thermalEventListener.notifyThrottling(createSkinTemperature(throttlingStatus)); mTestHandler.flush(); assertEquals(expectedActive, mClamper.isActive()); assertEquals(expectedBrightness, mClamper.getBrightnessCap(), FLOAT_TOLERANCE); @@ -139,11 +140,11 @@ public class BrightnessThermalClamperTest { @Test @Parameters(method = "testThrottlingData") - public void testOnDisplayChangeAfterNotifyThrottlng(List<ThrottlingLevel> throttlingLevels, + public void testOnDisplayChangeAfterNotifyThrottling(List<ThrottlingLevel> throttlingLevels, @Temperature.ThrottlingStatus int throttlingStatus, boolean expectedActive, float expectedBrightness) throws RemoteException { - IThermalEventListener thermalEventListener = captureThermalEventListener(); - thermalEventListener.notifyThrottling(createTemperature(throttlingStatus)); + IThermalEventListener thermalEventListener = captureSkinThermalEventListener(); + thermalEventListener.notifyThrottling(createSkinTemperature(throttlingStatus)); mTestHandler.flush(); assertFalse(mClamper.isActive()); assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE); @@ -156,8 +157,8 @@ public class BrightnessThermalClamperTest { @Test public void testOverrideData() throws RemoteException { - IThermalEventListener thermalEventListener = captureThermalEventListener(); - thermalEventListener.notifyThrottling(createTemperature(Temperature.THROTTLING_SEVERE)); + IThermalEventListener thermalEventListener = captureSkinThermalEventListener(); + thermalEventListener.notifyThrottling(createSkinTemperature(Temperature.THROTTLING_SEVERE)); mTestHandler.flush(); assertFalse(mClamper.isActive()); assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE); @@ -183,15 +184,60 @@ public class BrightnessThermalClamperTest { assertEquals(0.4f, mClamper.getBrightnessCap(), FLOAT_TOLERANCE); } - private IThermalEventListener captureThermalEventListener() throws RemoteException { + @Test + public void testDisplaySensorBasedThrottling() throws RemoteException { + final int severity = PowerManager.THERMAL_STATUS_SEVERE; + IThermalEventListener thermalEventListener = captureSkinThermalEventListener(); + // Update config to listen to display type sensor. + final SensorData tempSensor = new SensorData("DISPLAY", "VIRTUAL-SKIN-DISPLAY"); + final TestThermalData thermalData = + new TestThermalData( + DISPLAY_ID, + DisplayDeviceConfig.DEFAULT_ID, + List.of(new ThrottlingLevel(severity, 0.5f)), + tempSensor); + mClamper.onDisplayChanged(thermalData); + mTestHandler.flush(); + verify(mMockThermalService).unregisterThermalEventListener(thermalEventListener); + thermalEventListener = captureThermalEventListener(Temperature.TYPE_DISPLAY); + assertFalse(mClamper.isActive()); + + // Verify no throttling triggered when any other sensor notification received. + thermalEventListener.notifyThrottling(createSkinTemperature(severity)); + mTestHandler.flush(); + assertFalse(mClamper.isActive()); + + thermalEventListener.notifyThrottling(createDisplayTemperature("OTHER-SENSOR", severity)); + mTestHandler.flush(); + assertFalse(mClamper.isActive()); + + assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE); + + // Verify throttling triggered when display sensor of given name throttled. + thermalEventListener.notifyThrottling(createDisplayTemperature(tempSensor.name, severity)); + mTestHandler.flush(); + assertTrue(mClamper.isActive()); + assertEquals(0.5f, mClamper.getBrightnessCap(), FLOAT_TOLERANCE); + } + + private IThermalEventListener captureSkinThermalEventListener() throws RemoteException { + return captureThermalEventListener(Temperature.TYPE_SKIN); + } + + private IThermalEventListener captureThermalEventListener(int type) throws RemoteException { ArgumentCaptor<IThermalEventListener> captor = ArgumentCaptor.forClass( IThermalEventListener.class); verify(mMockThermalService).registerThermalEventListenerWithType(captor.capture(), eq( - Temperature.TYPE_SKIN)); + type)); return captor.getValue(); } - private Temperature createTemperature(@Temperature.ThrottlingStatus int status) { + private Temperature createDisplayTemperature( + @NonNull String sensorName, @Temperature.ThrottlingStatus int status) { + return new Temperature(100, Temperature.TYPE_DISPLAY, sensorName, status); + } + + private Temperature createSkinTemperature(@Temperature.ThrottlingStatus int status) { return new Temperature(100, Temperature.TYPE_SKIN, "test_temperature", status); } @@ -217,19 +263,26 @@ public class BrightnessThermalClamperTest { private final String mUniqueDisplayId; private final String mDataId; private final ThermalBrightnessThrottlingData mData; + private final SensorData mTempSensor; private TestThermalData() { - this(DISPLAY_ID, DisplayDeviceConfig.DEFAULT_ID, null); + this(DISPLAY_ID, DisplayDeviceConfig.DEFAULT_ID, null, + SensorData.loadTempSensorUnspecifiedConfig()); } private TestThermalData(List<ThrottlingLevel> data) { - this(DISPLAY_ID, DisplayDeviceConfig.DEFAULT_ID, data); + this(DISPLAY_ID, DisplayDeviceConfig.DEFAULT_ID, data, + SensorData.loadTempSensorUnspecifiedConfig()); } - private TestThermalData(String uniqueDisplayId, String dataId, List<ThrottlingLevel> data) { + + private TestThermalData(String uniqueDisplayId, String dataId, List<ThrottlingLevel> data, + SensorData tempSensor) { mUniqueDisplayId = uniqueDisplayId; mDataId = dataId; mData = ThermalBrightnessThrottlingData.create(data); + mTempSensor = tempSensor; } + @NonNull @Override public String getUniqueDisplayId() { @@ -247,5 +300,11 @@ public class BrightnessThermalClamperTest { public ThermalBrightnessThrottlingData getThermalBrightnessThrottlingData() { return mData; } + + @NonNull + @Override + public SensorData getTempSensor() { + return mTempSensor; + } } } |