diff options
11 files changed, 374 insertions, 110 deletions
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index cc115f13f5e3..d78fdfae266f 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -150,7 +150,9 @@ import javax.xml.datatype.DatatypeConfigurationException; * <screenBrightnessDefault>0.65</screenBrightnessDefault> * <powerThrottlingConfig> * <brightnessLowestCapAllowed>0.1</brightnessLowestCapAllowed> - * <pollingWindowMillis>15</pollingWindowMillis> + * <customAnimationRateSec>0.004</customAnimationRateSec> + * <pollingWindowMaxMillis>30000</pollingWindowMaxMillis> + * <pollingWindowMinMillis>10000</pollingWindowMinMillis> * <powerThrottlingMap> * <powerThrottlingPoint> * <thermalStatus>severe</thermalStatus> @@ -2184,9 +2186,13 @@ public class DisplayDeviceConfig { return; } float lowestBrightnessCap = powerThrottlingCfg.getBrightnessLowestCapAllowed().floatValue(); - int pollingWindowMillis = powerThrottlingCfg.getPollingWindowMillis().intValue(); + float customAnimationRateSec = powerThrottlingCfg.getCustomAnimationRateSec().floatValue(); + int pollingWindowMaxMillis = powerThrottlingCfg.getPollingWindowMaxMillis().intValue(); + int pollingWindowMinMillis = powerThrottlingCfg.getPollingWindowMinMillis().intValue(); mPowerThrottlingConfigData = new PowerThrottlingConfigData(lowestBrightnessCap, - pollingWindowMillis); + customAnimationRateSec, + pollingWindowMaxMillis, + pollingWindowMinMillis); } private void loadRefreshRateSetting(DisplayConfiguration config) { @@ -2980,12 +2986,19 @@ public class DisplayDeviceConfig { public static class PowerThrottlingConfigData { /** Lowest brightness cap allowed for this device. */ public final float brightnessLowestCapAllowed; - /** Time window for polling power in seconds. */ - public final int pollingWindowMillis; + /** Time take to animate brightness in seconds. */ + public final float customAnimationRateSec; + /** Time window for maximum polling power in milliseconds. */ + public final int pollingWindowMaxMillis; + /** Time window for minimum polling power in milliseconds. */ + public final int pollingWindowMinMillis; public PowerThrottlingConfigData(float brightnessLowestCapAllowed, - int pollingWindowMillis) { + float customAnimationRateSec, int pollingWindowMaxMillis, + int pollingWindowMinMillis) { this.brightnessLowestCapAllowed = brightnessLowestCapAllowed; - this.pollingWindowMillis = pollingWindowMillis; + this.customAnimationRateSec = customAnimationRateSec; + this.pollingWindowMaxMillis = pollingWindowMaxMillis; + this.pollingWindowMinMillis = pollingWindowMinMillis; } @Override @@ -2993,7 +3006,9 @@ public class DisplayDeviceConfig { return "PowerThrottlingConfigData{" + "brightnessLowestCapAllowed: " + brightnessLowestCapAllowed - + ", pollingWindowMillis: " + pollingWindowMillis + + ", customAnimationRateSec: " + customAnimationRateSec + + ", pollingWindowMaxMillis: " + pollingWindowMaxMillis + + ", pollingWindowMinMillis: " + pollingWindowMinMillis + "} "; } } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index cb3de73373ae..bf559c10b0ba 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -591,7 +591,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mThermalBrightnessThrottlingDataId, logicalDisplay.getPowerThrottlingDataIdLocked(), mDisplayDeviceConfig, displayDeviceInfo.width, displayDeviceInfo.height, - displayToken, mDisplayId), mContext, flags, mSensorManager); + displayToken, mDisplayId), mContext, flags, mSensorManager, + mDisplayBrightnessController.getCurrentBrightness()); // Seed the cached brightness saveBrightnessInfo(getScreenBrightnessSetting()); mAutomaticBrightnessStrategy = @@ -3305,10 +3306,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call BrightnessClamperController getBrightnessClamperController(Handler handler, BrightnessClamperController.ClamperChangeListener clamperChangeListener, BrightnessClamperController.DisplayDeviceData data, Context context, - DisplayManagerFlags flags, SensorManager sensorManager) { + DisplayManagerFlags flags, SensorManager sensorManager, float currentBrightness) { return new BrightnessClamperController(handler, clamperChangeListener, data, context, - flags, sensorManager); + flags, sensorManager, currentBrightness); } DisplayWhiteBalanceController getDisplayWhiteBalanceController(Handler handler, 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 d00ab83b2ec6..d3be33f51e5c 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 @@ -75,10 +75,13 @@ public class BrightnessClamperController { private ModifiersAggregatedState mModifiersAggregatedState = new ModifiersAggregatedState(); private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener; + private final DisplayManagerFlags mDisplayManagerFlags; private float mBrightnessCap = PowerManager.BRIGHTNESS_MAX; private float mCustomAnimationRate = DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET; @Nullable + private BrightnessPowerClamper mPowerClamper; + @Nullable private Type mClamperType = null; private boolean mClamperApplied = false; @@ -93,16 +96,18 @@ public class BrightnessClamperController { public BrightnessClamperController(Handler handler, ClamperChangeListener clamperChangeListener, DisplayDeviceData data, Context context, - DisplayManagerFlags flags, SensorManager sensorManager) { - this(new Injector(), handler, clamperChangeListener, data, context, flags, sensorManager); + DisplayManagerFlags flags, SensorManager sensorManager, float currentBrightness) { + this(new Injector(), handler, clamperChangeListener, data, context, flags, sensorManager, + currentBrightness); } @VisibleForTesting BrightnessClamperController(Injector injector, Handler handler, ClamperChangeListener clamperChangeListener, DisplayDeviceData data, Context context, - DisplayManagerFlags flags, SensorManager sensorManager) { + DisplayManagerFlags flags, SensorManager sensorManager, float currentBrightness) { mDeviceConfigParameterProvider = injector.getDeviceConfigParameterProvider(); mHandler = handler; + mDisplayManagerFlags = flags; mLightSensorController = injector.getLightSensorController(sensorManager, context, mLightSensorListener, mHandler); @@ -117,7 +122,15 @@ public class BrightnessClamperController { }; mClampers = injector.getClampers(handler, clamperChangeListenerInternal, data, flags, - context); + context, currentBrightness); + if (mDisplayManagerFlags.isPowerThrottlingClamperEnabled()) { + for (BrightnessClamper clamper: mClampers) { + if (clamper.getType() == Type.POWER) { + mPowerClamper = (BrightnessPowerClamper) clamper; + break; + } + } + } mModifiers = injector.getModifiers(flags, context, handler, clamperChangeListener, data); @@ -183,6 +196,12 @@ public class BrightnessClamperController { mModifiers.get(i).apply(request, builder); } + if (mDisplayManagerFlags.isPowerThrottlingClamperEnabled()) { + if (mPowerClamper != null) { + mPowerClamper.updateCurrentBrightness(cappedBrightness); + } + } + return builder.build(); } @@ -312,13 +331,17 @@ public class BrightnessClamperController { List<BrightnessClamper<? super DisplayDeviceData>> getClampers(Handler handler, ClamperChangeListener clamperChangeListener, DisplayDeviceData data, - DisplayManagerFlags flags, Context context) { + DisplayManagerFlags flags, Context context, float currentBrightness) { List<BrightnessClamper<? super DisplayDeviceData>> clampers = new ArrayList<>(); clampers.add( new BrightnessThermalClamper(handler, clamperChangeListener, data)); if (flags.isPowerThrottlingClamperEnabled()) { - clampers.add(new BrightnessPowerClamper(handler, clamperChangeListener, - data)); + // Check if power-throttling config is present. + PowerThrottlingConfigData configData = data.getPowerThrottlingConfigData(); + if (configData != null) { + clampers.add(new BrightnessPowerClamper(handler, clamperChangeListener, + data, currentBrightness)); + } } if (flags.isBrightnessWearBedtimeModeClamperEnabled()) { clampers.add(new BrightnessWearBedtimeModeClamper(handler, context, diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessPowerClamper.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessPowerClamper.java index 790322d75251..85e81f989845 100644 --- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessPowerClamper.java +++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessPowerClamper.java @@ -21,16 +21,23 @@ import static com.android.server.display.brightness.clamper.BrightnessClamperCon import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.Context; import android.os.Handler; +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.DeviceConfigInterface; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.display.DisplayBrightnessState; import com.android.server.display.DisplayDeviceConfig.PowerThrottlingConfigData; import com.android.server.display.DisplayDeviceConfig.PowerThrottlingData; import com.android.server.display.DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel; +import com.android.server.display.brightness.BrightnessUtils; import com.android.server.display.feature.DeviceConfigParameterProvider; import com.android.server.display.utils.DeviceConfigParsingUtils; @@ -65,14 +72,21 @@ class BrightnessPowerClamper extends private PowerThrottlingData mPowerThrottlingDataActive = null; @Nullable private PowerThrottlingConfigData mPowerThrottlingConfigData = null; - + @NonNull + private final ThermalLevelListener mThermalLevelListener; + @NonNull + private final PowerChangeListener mPowerChangeListener; private @Temperature.ThrottlingStatus int mCurrentThermalLevel = Temperature.THROTTLING_NONE; + private boolean mCurrentThermalLevelChanged = false; private float mCurrentAvgPowerConsumed = 0; @Nullable private String mUniqueDisplayId = null; @Nullable private String mDataId = null; - + private float mCurrentBrightness = PowerManager.BRIGHTNESS_INVALID; + private float mCustomAnimationRateSec = DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET; + private float mCustomAnimationRateSecDeviceConfig = + DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET; private final BiFunction<String, String, ThrottlingLevel> mDataPointMapper = (key, value) -> { try { int status = DeviceConfigParsingUtils.parseThermalStatus(key); @@ -88,23 +102,41 @@ class BrightnessPowerClamper extends BrightnessPowerClamper(Handler handler, ClamperChangeListener listener, - PowerData powerData) { - this(new Injector(), handler, listener, powerData); + PowerData powerData, float currentBrightness) { + this(new Injector(), handler, listener, powerData, currentBrightness); } @VisibleForTesting BrightnessPowerClamper(Injector injector, Handler handler, ClamperChangeListener listener, - PowerData powerData) { + PowerData powerData, float currentBrightness) { super(handler, listener); mInjector = injector; - mConfigParameterProvider = injector.getDeviceConfigParameterProvider(); + mCurrentBrightness = currentBrightness; + mPowerChangeListener = (powerConsumed, thermalStatus) -> { + recalculatePowerQuotaChange(powerConsumed, thermalStatus); + }; + mPowerThrottlingConfigData = powerData.getPowerThrottlingConfigData(); + if (mPowerThrottlingConfigData != null) { + mCustomAnimationRateSecDeviceConfig = mPowerThrottlingConfigData.customAnimationRateSec; + } + mThermalLevelListener = new ThermalLevelListener(handler); + mPmicMonitor = + mInjector.getPmicMonitor(mPowerChangeListener, + mThermalLevelListener.getThermalService(), + mPowerThrottlingConfigData.pollingWindowMaxMillis, + mPowerThrottlingConfigData.pollingWindowMinMillis); + mConfigParameterProvider = injector.getDeviceConfigParameterProvider(); mHandler.post(() -> { setDisplayData(powerData); loadOverrideData(); start(); }); + } + @VisibleForTesting + PowerChangeListener getPowerChangeListener() { + return mPowerChangeListener; } @Override @@ -114,6 +146,11 @@ class BrightnessPowerClamper extends } @Override + float getCustomAnimationRate() { + return mCustomAnimationRateSec; + } + + @Override void onDeviceConfigChanged() { mHandler.post(() -> { loadOverrideData(); @@ -134,6 +171,9 @@ class BrightnessPowerClamper extends if (mPmicMonitor != null) { mPmicMonitor.shutdown(); } + if (mThermalLevelListener != null) { + mThermalLevelListener.stop(); + } } /** @@ -144,11 +184,20 @@ class BrightnessPowerClamper extends pw.println(" mCurrentAvgPowerConsumed=" + mCurrentAvgPowerConsumed); pw.println(" mUniqueDisplayId=" + mUniqueDisplayId); pw.println(" mCurrentThermalLevel=" + mCurrentThermalLevel); + pw.println(" mCurrentThermalLevelChanged=" + mCurrentThermalLevelChanged); pw.println(" mPowerThrottlingDataFromDDC=" + (mPowerThrottlingDataFromDDC == null ? "null" : mPowerThrottlingDataFromDDC.toString())); + mThermalLevelListener.dump(pw); super.dump(pw); } + /** + * Updates current brightness, for power calculations. + */ + public void updateCurrentBrightness(float currentBrightness) { + mCurrentBrightness = currentBrightness; + } + private void recalculateActiveData() { if (mUniqueDisplayId == null || mDataId == null) { return; @@ -156,17 +205,11 @@ class BrightnessPowerClamper extends mPowerThrottlingDataActive = mPowerThrottlingDataOverride .getOrDefault(mUniqueDisplayId, Map.of()).getOrDefault(mDataId, mPowerThrottlingDataFromDDC); - if (mPowerThrottlingDataActive != null) { - if (mPmicMonitor != null) { - mPmicMonitor.stop(); - mPmicMonitor.start(); - } - } else { + if (mPowerThrottlingDataActive == null) { if (mPmicMonitor != null) { mPmicMonitor.stop(); } } - recalculateBrightnessCap(); } private void loadOverrideData() { @@ -198,21 +241,57 @@ class BrightnessPowerClamper extends if (mPowerThrottlingDataActive == null) { return; } - if (powerQuota > 0 && mCurrentAvgPowerConsumed > powerQuota) { - isActive = true; - // calculate new brightness Cap. - // Brightness has a linear relation to power-consumed. - targetBrightnessCap = - (powerQuota / mCurrentAvgPowerConsumed) * PowerManager.BRIGHTNESS_MAX; - // Cap to lowest allowed brightness on device. + if (powerQuota > 0) { + if (BrightnessUtils.isValidBrightnessValue(mCurrentBrightness) + && (mCurrentAvgPowerConsumed > powerQuota)) { + isActive = true; + // calculate new brightness Cap. + // Brightness has a linear relation to power-consumed. + targetBrightnessCap = + (powerQuota / mCurrentAvgPowerConsumed) * mCurrentBrightness; + } else if (mCurrentThermalLevelChanged) { + if (mCurrentThermalLevel == Temperature.THROTTLING_NONE) { + // reset pmic and remove the power-throttling cap. + isActive = true; + targetBrightnessCap = PowerManager.BRIGHTNESS_MAX; + mPmicMonitor.stop(); + } else { + isActive = true; + // Since the thermal status has changed, we need to remove power-throttling cap. + // Instead of recalculating and changing brightness again, adding flicker, + // we will wait for the next pmic cycle to re-evaluate this value + // make act on it, if needed. + targetBrightnessCap = PowerManager.BRIGHTNESS_MAX; + if (mPmicMonitor.isStopped()) { + mPmicMonitor.start(); + } + } + } else { // Current power consumed is under the quota. + isActive = true; + targetBrightnessCap = PowerManager.BRIGHTNESS_MAX; + } + } + + // Cap to lowest allowed brightness on device. + if (mPowerThrottlingConfigData != null) { targetBrightnessCap = Math.max(targetBrightnessCap, - mPowerThrottlingConfigData.brightnessLowestCapAllowed); + mPowerThrottlingConfigData.brightnessLowestCapAllowed); } if (mBrightnessCap != targetBrightnessCap || mIsActive != isActive) { mIsActive = isActive; + Slog.i(TAG, "Power clamper changing current brightness cap mBrightnessCap: " + + mBrightnessCap + " to target brightness cap:" + targetBrightnessCap + + " for current screen brightness: " + mCurrentBrightness); mBrightnessCap = targetBrightnessCap; + Slog.i(TAG, "Power clamper changed state: thermalStatus:" + mCurrentThermalLevel + + " mCurrentThermalLevelChanged:" + mCurrentThermalLevelChanged + + " mCurrentAvgPowerConsumed:" + mCurrentAvgPowerConsumed + + " mCustomAnimationRateSec:" + mCustomAnimationRateSecDeviceConfig); + mCustomAnimationRateSec = mCustomAnimationRateSecDeviceConfig; mChangeListener.onChanged(); + } else { + mCustomAnimationRateSec = DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET; } } @@ -234,6 +313,11 @@ class BrightnessPowerClamper extends private void recalculatePowerQuotaChange(float avgPowerConsumed, int thermalStatus) { mHandler.post(() -> { + if (mCurrentThermalLevel != thermalStatus) { + mCurrentThermalLevelChanged = true; + } else { + mCurrentThermalLevelChanged = false; + } mCurrentThermalLevel = thermalStatus; mCurrentAvgPowerConsumed = avgPowerConsumed; recalculateBrightnessCap(); @@ -244,14 +328,107 @@ class BrightnessPowerClamper extends if (mPowerThrottlingConfigData == null) { return; } - PowerChangeListener listener = (powerConsumed, thermalStatus) -> { - recalculatePowerQuotaChange(powerConsumed, thermalStatus); - }; - mPmicMonitor = - mInjector.getPmicMonitor(listener, mPowerThrottlingConfigData.pollingWindowMillis); + if (mPowerThrottlingConfigData.pollingWindowMaxMillis + <= mPowerThrottlingConfigData.pollingWindowMinMillis) { + Slog.e(TAG, "Brightness power max polling window:" + + mPowerThrottlingConfigData.pollingWindowMaxMillis + + " msec, should be greater than brightness min polling window:" + + mPowerThrottlingConfigData.pollingWindowMinMillis + " msec."); + return; + } + if ((mPowerThrottlingConfigData.pollingWindowMaxMillis + % mPowerThrottlingConfigData.pollingWindowMinMillis) != 0) { + Slog.e(TAG, "Brightness power max polling window:" + + mPowerThrottlingConfigData.pollingWindowMaxMillis + + " msec, is not divisible by brightness min polling window:" + + mPowerThrottlingConfigData.pollingWindowMinMillis + " msec."); + return; + } + mCustomAnimationRateSecDeviceConfig = mPowerThrottlingConfigData.customAnimationRateSec; + mThermalLevelListener.start(); + } + + private void activatePmicMonitor() { + if (!mPmicMonitor.isStopped()) { + return; + } mPmicMonitor.start(); } + private void deactivatePmicMonitor(@Temperature.ThrottlingStatus int status) { + if (status != Temperature.THROTTLING_NONE) { + return; + } + if (mPmicMonitor.isStopped()) { + return; + } + mPmicMonitor.stop(); + } + + private final class ThermalLevelListener extends IThermalEventListener.Stub { + private final Handler mHandler; + private IThermalService mThermalService; + private boolean mStarted; + + ThermalLevelListener(Handler handler) { + mHandler = handler; + mStarted = false; + mThermalService = IThermalService.Stub.asInterface( + ServiceManager.getService(Context.THERMAL_SERVICE)); + } + + IThermalService getThermalService() { + return mThermalService; + } + + void start() { + if (mStarted) { + return; + } + if (mThermalService == null) { + return; + } + try { + // TODO b/279114539 Try DISPLAY first and then fallback to SKIN. + mThermalService.registerThermalEventListenerWithType(this, Temperature.TYPE_SKIN); + mStarted = true; + } catch (RemoteException e) { + Slog.e(TAG, "Failed to register thermal status listener", e); + } + } + + @Override + public void notifyThrottling(Temperature temp) { + @Temperature.ThrottlingStatus int status = temp.getStatus(); + if (status >= Temperature.THROTTLING_LIGHT) { + Slog.d(TAG, "Activating pmic monitor due to thermal state:" + status); + mHandler.post(() -> activatePmicMonitor()); + } else { + if (!mPmicMonitor.isStopped()) { + mHandler.post(() -> deactivatePmicMonitor(status)); + } + } + } + + void stop() { + 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(" ThermalLevelObserver:"); + writer.println(" mStarted: " + mStarted); + } + } + public interface PowerData { @NonNull String getUniqueDisplayId(); @@ -279,8 +456,12 @@ class BrightnessPowerClamper extends @VisibleForTesting static class Injector { - PmicMonitor getPmicMonitor(PowerChangeListener listener, int pollingTime) { - return new PmicMonitor(listener, pollingTime); + PmicMonitor getPmicMonitor(PowerChangeListener powerChangeListener, + IThermalService thermalService, + int pollingMaxTimeMillis, + int pollingMinTimeMillis) { + return new PmicMonitor(powerChangeListener, thermalService, pollingMaxTimeMillis, + pollingMinTimeMillis); } DeviceConfigParameterProvider getDeviceConfigParameterProvider() { diff --git a/services/core/java/com/android/server/display/brightness/clamper/PmicMonitor.java b/services/core/java/com/android/server/display/brightness/clamper/PmicMonitor.java index 26784f2353ff..355f4fe65279 100644 --- a/services/core/java/com/android/server/display/brightness/clamper/PmicMonitor.java +++ b/services/core/java/com/android/server/display/brightness/clamper/PmicMonitor.java @@ -18,15 +18,12 @@ package com.android.server.display.brightness.clamper; import static com.android.server.display.brightness.clamper.BrightnessPowerClamper.PowerChangeListener; -import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.Context; import android.hardware.power.stats.EnergyConsumer; import android.hardware.power.stats.EnergyConsumerResult; import android.hardware.power.stats.EnergyConsumerType; import android.os.IThermalService; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.Temperature; import android.power.PowerStatsInternal; import android.util.IntArray; @@ -51,25 +48,30 @@ public class PmicMonitor { // The executor to periodically monitor the display power. private final ScheduledExecutorService mExecutor; - @NonNull - private final PowerChangeListener mPowerChangeListener; - private final long mPowerMonitorPeriodConfigSecs; + private final long mPowerMonitorPeriodConfigMillis; private final PowerStatsInternal mPowerStatsInternal; @VisibleForTesting final IThermalService mThermalService; + @VisibleForTesting PowerChangeListener mPowerChangeListener; private ScheduledFuture<?> mPmicMonitorFuture; private float mLastEnergyConsumed = 0; - private float mCurrentAvgPower = 0; + private float mCurrentTotalAvgPower = 0; private Temperature mCurrentTemperature; private long mCurrentTimestampMillis = 0; - - PmicMonitor(PowerChangeListener listener, int powerMonitorPeriodConfigSecs) { + private float[] mAvgPowerCircularList; + private int mPowerListStart = 0; + private int mPowerListEnd = 0; + + PmicMonitor(PowerChangeListener listener, + IThermalService thermalService, + int pollingMaxTimeMillis, + int pollingMinTimeMillis) { mPowerChangeListener = listener; + mThermalService = thermalService; mPowerStatsInternal = LocalServices.getService(PowerStatsInternal.class); - mThermalService = IThermalService.Stub.asInterface( - ServiceManager.getService(Context.THERMAL_SERVICE)); + mAvgPowerCircularList = new float[pollingMaxTimeMillis / pollingMinTimeMillis]; // start a periodic worker thread. mExecutor = Executors.newSingleThreadScheduledExecutor(); - mPowerMonitorPeriodConfigSecs = (long) powerMonitorPeriodConfigSecs; + mPowerMonitorPeriodConfigMillis = pollingMinTimeMillis; } @Nullable @@ -141,12 +143,28 @@ public class PmicMonitor { // capture thermal state. Temperature displayTemperature = getDisplayTemperature(); - mCurrentAvgPower = currentPower; + boolean isBufferFull = false; + mAvgPowerCircularList[mPowerListEnd] = currentPower; + mCurrentTotalAvgPower += currentPower; + mPowerListEnd = + (mPowerListEnd + 1) % mAvgPowerCircularList.length; + if (mPowerListStart == mPowerListEnd) { + isBufferFull = true; + } + mCurrentTemperature = displayTemperature; mLastEnergyConsumed = displayResults[0].energyUWs; mCurrentTimestampMillis = displayResults[0].timestampMs; - if (mCurrentTemperature != null) { - mPowerChangeListener.onChanged(mCurrentAvgPower, mCurrentTemperature.getStatus()); + + if (mCurrentTemperature != null && isBufferFull) { + mPowerChangeListener.onChanged(mCurrentTotalAvgPower / mAvgPowerCircularList.length, + mCurrentTemperature.getStatus()); + } + + // average power long-term list is full, reset values for next cycle. + if (isBufferFull) { + mCurrentTotalAvgPower = mCurrentTotalAvgPower - mAvgPowerCircularList[mPowerListStart]; + mPowerListStart = (mPowerListStart + 1) % mAvgPowerCircularList.length; } } @@ -165,11 +183,11 @@ public class PmicMonitor { if (mPmicMonitorFuture == null) { mPmicMonitorFuture = mExecutor.scheduleAtFixedRate( this::capturePeriodicDisplayPower, - mPowerMonitorPeriodConfigSecs, - mPowerMonitorPeriodConfigSecs, - TimeUnit.SECONDS); + mPowerMonitorPeriodConfigMillis, + mPowerMonitorPeriodConfigMillis, + TimeUnit.MILLISECONDS); } else { - Slog.e(TAG, "already scheduled, stop() called before start."); + Slog.e(TAG, "PMIC already scheduled, stop() called before start."); } } @@ -184,6 +202,23 @@ public class PmicMonitor { } /** + * Updates PMIC configuration. + */ + public void updateConfiguration() { + if (mPmicMonitorFuture != null) { + mPmicMonitorFuture.cancel(true); + mPmicMonitorFuture = null; + } + } + + /** + * Returns if PMIC monitor is stopped. + */ + public boolean isStopped() { + return mPmicMonitorFuture == null; + } + + /** * Shutdown power IC service and worker thread. */ public void shutdown() { 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 4231149336ec..0eafb59bdeac 100644 --- a/services/core/xsd/display-device-config/display-device-config.xsd +++ b/services/core/xsd/display-device-config/display-device-config.xsd @@ -42,7 +42,7 @@ <xs:annotation name="nonnull"/> <xs:annotation name="final"/> </xs:element> - <xs:element type="thermalThrottling" name="thermalThrottling"> + <xs:element type="thermalThrottling" name="thermalThrottling" minOccurs="0" maxOccurs="1"> <xs:annotation name="nonnull"/> <xs:annotation name="final"/> </xs:element> @@ -464,7 +464,15 @@ <xs:annotation name="nonnull"/> <xs:annotation name="final"/> </xs:element> - <xs:element name="pollingWindowMillis" type="xs:nonNegativeInteger"> + <xs:element name="customAnimationRateSec" type="nonNegativeDecimal" minOccurs="0" maxOccurs="1"> + <xs:annotation name="nonnull"/> + <xs:annotation name="final"/> + </xs:element> + <xs:element name="pollingWindowMaxMillis" type="xs:nonNegativeInteger"> + <xs:annotation name="nonnull"/> + <xs:annotation name="final"/> + </xs:element> + <xs:element name="pollingWindowMinMillis" type="xs:nonNegativeInteger"> <xs:annotation name="nonnull"/> <xs:annotation name="final"/> </xs:element> diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt index cec2787ca51f..355b0ab15a62 100644 --- a/services/core/xsd/display-device-config/schema/current.txt +++ b/services/core/xsd/display-device-config/schema/current.txt @@ -345,10 +345,14 @@ package com.android.server.display.config { public class PowerThrottlingConfig { ctor public PowerThrottlingConfig(); method @NonNull public final java.math.BigDecimal getBrightnessLowestCapAllowed(); - method @NonNull public final java.math.BigInteger getPollingWindowMillis(); + method @NonNull public final java.math.BigDecimal getCustomAnimationRateSec(); + method @NonNull public final java.math.BigInteger getPollingWindowMaxMillis(); + method @NonNull public final java.math.BigInteger getPollingWindowMinMillis(); method public final java.util.List<com.android.server.display.config.PowerThrottlingMap> getPowerThrottlingMap(); method public final void setBrightnessLowestCapAllowed(@NonNull java.math.BigDecimal); - method public final void setPollingWindowMillis(@NonNull java.math.BigInteger); + method public final void setCustomAnimationRateSec(@NonNull java.math.BigDecimal); + method public final void setPollingWindowMaxMillis(@NonNull java.math.BigInteger); + method public final void setPollingWindowMinMillis(@NonNull java.math.BigInteger); } public class PowerThrottlingMap { 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 d4506831d9c2..fd05b26c320b 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java @@ -263,7 +263,9 @@ public final class DisplayDeviceConfigTest { mDisplayDeviceConfig.getPowerThrottlingConfigData(); assertNotNull(powerThrottlingConfigData); assertEquals(0.1f, powerThrottlingConfigData.brightnessLowestCapAllowed, SMALL_DELTA); - assertEquals(10, powerThrottlingConfigData.pollingWindowMillis); + assertEquals(15f, powerThrottlingConfigData.customAnimationRateSec, SMALL_DELTA); + assertEquals(20000, powerThrottlingConfigData.pollingWindowMaxMillis); + assertEquals(10000, powerThrottlingConfigData.pollingWindowMinMillis); } @Test @@ -1295,7 +1297,9 @@ public final class DisplayDeviceConfigTest { private String getPowerThrottlingConfig() { return "<powerThrottlingConfig >\n" + "<brightnessLowestCapAllowed>0.1</brightnessLowestCapAllowed>\n" - + "<pollingWindowMillis>10</pollingWindowMillis>\n" + + "<customAnimationRateSec>15</customAnimationRateSec>\n" + + "<pollingWindowMaxMillis>20000</pollingWindowMaxMillis>\n" + + "<pollingWindowMinMillis>10000</pollingWindowMinMillis>\n" + "<powerThrottlingMap>\n" + "<powerThrottlingPoint>\n" + "<thermalStatus>light</thermalStatus>\n" diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java index 2166cb7639ef..d0aec3b6cef8 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java @@ -2587,7 +2587,7 @@ public final class DisplayPowerControllerTest { BrightnessClamperController getBrightnessClamperController(Handler handler, BrightnessClamperController.ClamperChangeListener clamperChangeListener, BrightnessClamperController.DisplayDeviceData data, Context context, - DisplayManagerFlags flags, SensorManager sensorManager) { + DisplayManagerFlags flags, SensorManager sensorManager, float currentBrightness) { return mClamperController; } diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java index 0a03702d4688..f9dc12258667 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java @@ -358,7 +358,7 @@ public class BrightnessClamperControllerTest { private BrightnessClamperController createBrightnessClamperController() { return new BrightnessClamperController(mTestInjector, mTestHandler, mMockExternalListener, - mMockDisplayDeviceData, mMockContext, mFlags, mSensorManager); + mMockDisplayDeviceData, mMockContext, mFlags, mSensorManager, 0); } interface TestDisplayListenerModifier extends BrightnessStateModifier, @@ -396,7 +396,7 @@ public class BrightnessClamperControllerTest { Handler handler, BrightnessClamperController.ClamperChangeListener clamperChangeListener, BrightnessClamperController.DisplayDeviceData data, - DisplayManagerFlags flags, Context context) { + DisplayManagerFlags flags, Context context, float currentBrightness) { mCapturedChangeListener = clamperChangeListener; return mClampers; } diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessPowerClamperTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessPowerClamperTest.java index b3f33ad858fe..c4898da62d81 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessPowerClamperTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessPowerClamperTest.java @@ -21,6 +21,7 @@ import static com.android.server.display.brightness.clamper.BrightnessPowerClamp import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import android.os.IThermalService; import android.os.PowerManager; import android.os.RemoteException; import android.os.Temperature; @@ -58,12 +59,18 @@ public class BrightnessPowerClamperTest { private final FakeDeviceConfigInterface mFakeDeviceConfigInterface = new FakeDeviceConfigInterface(); private final TestHandler mTestHandler = new TestHandler(null); + private final TestInjector mTestInjector = new TestInjector(); private BrightnessPowerClamper mClamper; + private final float mCurrentBrightness = 0.6f; + private PowerChangeListener mPowerChangeListener; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mClamper = new BrightnessPowerClamper(new TestInjector(), mTestHandler, - mMockClamperChangeListener, new TestPowerData()); + mClamper = new BrightnessPowerClamper(mTestInjector, mTestHandler, + mMockClamperChangeListener, new TestPowerData(), mCurrentBrightness); + mPowerChangeListener = mClamper.getPowerChangeListener(); + mPmicMonitor = mTestInjector.getPmicMonitor(mPowerChangeListener, null, 5, 10); + mPmicMonitor.setPowerChangeListener(mPowerChangeListener); mTestHandler.flush(); } @@ -79,36 +86,27 @@ public class BrightnessPowerClamperTest { } @Test - public void testPowerThrottlingNoOngoingAnimation() throws RemoteException { - mPmicMonitor.setThermalStatus(Temperature.THROTTLING_SEVERE); + public void testPowerThrottlingWithThermalLevelLight() throws RemoteException { + mPmicMonitor.setThermalStatus(Temperature.THROTTLING_LIGHT); mTestHandler.flush(); assertFalse(mClamper.isActive()); assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE); // update a new device config for power-throttling. mClamper.onDisplayChanged(new TestPowerData( - List.of(new ThrottlingLevel(PowerManager.THERMAL_STATUS_SEVERE, 100f)))); + List.of(new ThrottlingLevel(PowerManager.THERMAL_STATUS_LIGHT, 100f)))); mPmicMonitor.setAvgPowerConsumed(200f); float expectedBrightness = 0.5f; - expectedBrightness = expectedBrightness * PowerManager.BRIGHTNESS_MAX; + expectedBrightness = expectedBrightness * mCurrentBrightness; mTestHandler.flush(); // Assume current brightness as max, as there is no throttling. assertEquals(expectedBrightness, mClamper.getBrightnessCap(), FLOAT_TOLERANCE); - mPmicMonitor.setThermalStatus(Temperature.THROTTLING_CRITICAL); - // update a new device config for power-throttling. - mClamper.onDisplayChanged(new TestPowerData( - List.of(new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 50f)))); - - mPmicMonitor.setAvgPowerConsumed(100f); - expectedBrightness = 0.5f * PowerManager.BRIGHTNESS_MAX; - mTestHandler.flush(); - assertEquals(expectedBrightness, mClamper.getBrightnessCap(), FLOAT_TOLERANCE); } @Test - public void testPowerThrottlingWithOngoingAnimation() throws RemoteException { + public void testPowerThrottlingWithThermalLevelSevere() throws RemoteException { mPmicMonitor.setThermalStatus(Temperature.THROTTLING_SEVERE); mTestHandler.flush(); assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE); @@ -119,20 +117,10 @@ public class BrightnessPowerClamperTest { mPmicMonitor.setAvgPowerConsumed(200f); float expectedBrightness = 0.5f; - expectedBrightness = expectedBrightness * PowerManager.BRIGHTNESS_MAX; - + expectedBrightness = expectedBrightness * mCurrentBrightness; mTestHandler.flush(); // Assume current brightness as max, as there is no throttling. assertEquals(expectedBrightness, mClamper.getBrightnessCap(), FLOAT_TOLERANCE); - mPmicMonitor.setThermalStatus(Temperature.THROTTLING_CRITICAL); - // update a new device config for power-throttling. - mClamper.onDisplayChanged(new TestPowerData( - List.of(new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 50f)))); - - mPmicMonitor.setAvgPowerConsumed(100f); - expectedBrightness = 0.5f * PowerManager.BRIGHTNESS_MAX; - mTestHandler.flush(); - assertEquals(expectedBrightness, mClamper.getBrightnessCap(), FLOAT_TOLERANCE); } @Test @@ -148,8 +136,7 @@ public class BrightnessPowerClamperTest { mPmicMonitor.setAvgPowerConsumed(200f); float expectedBrightness = 0.5f; - expectedBrightness = expectedBrightness * PowerManager.BRIGHTNESS_MAX; - + expectedBrightness = expectedBrightness * mCurrentBrightness; mTestHandler.flush(); assertEquals(expectedBrightness, mClamper.getBrightnessCap(), FLOAT_TOLERANCE); @@ -169,10 +156,11 @@ public class BrightnessPowerClamperTest { private static class TestPmicMonitor extends PmicMonitor { private Temperature mCurrentTemperature; - private final PowerChangeListener mListener; - TestPmicMonitor(PowerChangeListener listener, int pollingTime) { - super(listener, pollingTime); - mListener = listener; + private PowerChangeListener mListener; + TestPmicMonitor(PowerChangeListener listener, + IThermalService thermalService, + int pollingTimeMax, int pollingTimeMin) { + super(listener, thermalService, pollingTimeMax, pollingTimeMin); } public void setAvgPowerConsumed(float power) { int status = mCurrentTemperature.getStatus(); @@ -181,13 +169,18 @@ public class BrightnessPowerClamperTest { public void setThermalStatus(@Temperature.ThrottlingStatus int status) { mCurrentTemperature = new Temperature(100, Temperature.TYPE_SKIN, "test_temp", status); } + public void setPowerChangeListener(PowerChangeListener listener) { + mListener = listener; + } } private class TestInjector extends BrightnessPowerClamper.Injector { @Override TestPmicMonitor getPmicMonitor(PowerChangeListener listener, - int pollingTime) { - mPmicMonitor = new TestPmicMonitor(listener, pollingTime); + IThermalService thermalService, + int minPollingTimeMillis, int maxPollingTimeMillis) { + mPmicMonitor = new TestPmicMonitor(listener, thermalService, maxPollingTimeMillis, + minPollingTimeMillis); return mPmicMonitor; } @@ -216,7 +209,7 @@ public class BrightnessPowerClamperTest { mUniqueDisplayId = uniqueDisplayId; mDataId = dataId; mData = PowerThrottlingData.create(data); - mConfigData = new PowerThrottlingConfigData(0.1f, 10); + mConfigData = new PowerThrottlingConfigData(0.1f, 10, 20, 10); } @NonNull |