summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceConfig.java31
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java7
-rw-r--r--services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java37
-rw-r--r--services/core/java/com/android/server/display/brightness/clamper/BrightnessPowerClamper.java237
-rw-r--r--services/core/java/com/android/server/display/brightness/clamper/PmicMonitor.java73
-rw-r--r--services/core/xsd/display-device-config/display-device-config.xsd12
-rw-r--r--services/core/xsd/display-device-config/schema/current.txt8
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java8
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java2
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java4
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessPowerClamperTest.java65
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