Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 892d60c7 authored by Manali Bhutiyani's avatar Manali Bhutiyani Committed by Android (Google) Code Review
Browse files

Merge "[power-throttling] Fine tune algorithm" into main

parents f3762c68 c65d8403
Loading
Loading
Loading
Loading
+23 −8
Original line number Diff line number Diff line
@@ -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
                    + "} ";
        }
    }
+4 −3
Original line number Diff line number Diff line
@@ -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,
+30 −7
Original line number Diff line number Diff line
@@ -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()) {
                // Check if power-throttling config is present.
                PowerThrottlingConfigData configData = data.getPowerThrottlingConfigData();
                if (configData != null) {
                    clampers.add(new BrightnessPowerClamper(handler, clamperChangeListener,
                        data));
                            data, currentBrightness));
                }
            }
            if (flags.isBrightnessWearBedtimeModeClamperEnabled()) {
                clampers.add(new BrightnessWearBedtimeModeClamper(handler, context,
+209 −28
Original line number Diff line number Diff line
@@ -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
@@ -113,6 +145,11 @@ class BrightnessPowerClamper extends
        return Type.POWER;
    }

    @Override
    float getCustomAnimationRate() {
        return mCustomAnimationRateSec;
    }

    @Override
    void onDeviceConfigChanged() {
        mHandler.post(() -> {
@@ -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) {
        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) * PowerManager.BRIGHTNESS_MAX;
                    (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);
        }

        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() {
+54 −19

File changed.

Preview size limit exceeded, changes collapsed.

Loading