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

Commit 265f9a6c authored by Fiona Campbell's avatar Fiona Campbell Committed by Michael Wright
Browse files

Brightnessthrottler updateable through DeviceConfig

Add listener and methods to allow BrightnessThrottler to be updated
though DeviceConfig.

Bug: 224567082
Test: atest com.android.server.display
Test: adb shell device_config put display_manager
brightness_throttling_data
"local:4619827677550801152,3,moderate,0.5,severe,0.379518072,emergency,0.248995984;local:4619827677550801151,1,moderate,0.75;local:4619827677550801150,0"
adb shell dumpsys display | grep -A20 BrightnessThrottler

Change-Id: If4fe4875d6a05cb03fbf69abb8a62a645098b3a0
parent 8a1e0cf1
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -1448,5 +1448,15 @@ public final class DisplayManager {
         * @hide
         */
        String KEY_HIGH_REFRESH_RATE_BLACKLIST = "high_refresh_rate_blacklist";

        /**
         * Key for the brightness throttling data as a String formatted:
         * <displayId>,<no of throttling levels>,[<severity as string>,<brightness cap>]
         * Where the latter part is repeated for each throttling level, and the entirety is repeated
         * for each display, separated by a semicolon.
         * For example:
         * 123,1,critical,0.8;456,2,moderate,0.9,critical,0.7
         */
        String KEY_BRIGHTNESS_THROTTLING_DATA = "brightness_throttling_data";
    }
}
+195 −10
Original line number Diff line number Diff line
@@ -16,21 +16,31 @@

package com.android.server.display;

import android.annotation.NonNull;
import android.content.Context;
import android.hardware.display.BrightnessInfo;
import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IThermalEventListener;
import android.os.IThermalService;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.Temperature;
import android.provider.DeviceConfig;
import android.provider.DeviceConfigInterface;
import android.util.Slog;

import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData;
import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executor;

/**
 * This class monitors various conditions, such as skin temperature throttling status, and limits
@@ -44,28 +54,54 @@ class BrightnessThrottler {

    private final Injector mInjector;
    private final Handler mHandler;
    private BrightnessThrottlingData mThrottlingData;
    // We need a separate handler for unit testing. These two handlers are the same throughout the
    // non-test code.
    private final Handler mDeviceConfigHandler;
    private final Runnable mThrottlingChangeCallback;
    private final SkinThermalStatusObserver mSkinThermalStatusObserver;
    private final DeviceConfigListener mDeviceConfigListener;
    private final DeviceConfigInterface mDeviceConfig;

    private int mThrottlingStatus;
    private BrightnessThrottlingData mThrottlingData;
    private BrightnessThrottlingData mDdcThrottlingData;
    private float mBrightnessCap = PowerManager.BRIGHTNESS_MAX;
    private @BrightnessInfo.BrightnessMaxReason int mBrightnessMaxReason =
        BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
    private String mUniqueDisplayId;

    // The most recent string that has been set from DeviceConfig
    private String mBrightnessThrottlingDataString;

    // This is a collection of brightness throttling data that has been written as overrides from
    // the DeviceConfig. This will always take priority over the display device config data.
    private HashMap<String, BrightnessThrottlingData> mBrightnessThrottlingDataOverride =
            new HashMap<>(1);

    BrightnessThrottler(Handler handler, BrightnessThrottlingData throttlingData,
            Runnable throttlingChangeCallback) {
        this(new Injector(), handler, throttlingData, throttlingChangeCallback);
            Runnable throttlingChangeCallback, String uniqueDisplayId) {
        this(new Injector(), handler, handler, throttlingData, throttlingChangeCallback,
                uniqueDisplayId);
    }

    BrightnessThrottler(Injector injector, Handler handler, BrightnessThrottlingData throttlingData,
            Runnable throttlingChangeCallback) {
    @VisibleForTesting
    BrightnessThrottler(Injector injector, Handler handler, Handler deviceConfigHandler,
            BrightnessThrottlingData throttlingData, Runnable throttlingChangeCallback,
            String uniqueDisplayId) {
        mInjector = injector;

        mHandler = handler;
        mDeviceConfigHandler = deviceConfigHandler;
        mThrottlingData = throttlingData;
        mDdcThrottlingData = throttlingData;
        mThrottlingChangeCallback = throttlingChangeCallback;
        mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler);

        resetThrottlingData(mThrottlingData);
        mUniqueDisplayId = uniqueDisplayId;
        mDeviceConfig = injector.getDeviceConfig();
        mDeviceConfigListener = new DeviceConfigListener();

        resetThrottlingData(mThrottlingData, mUniqueDisplayId);
    }

    boolean deviceSupportsThrottling() {
@@ -86,7 +122,7 @@ class BrightnessThrottler {

    void stop() {
        mSkinThermalStatusObserver.stopObserving();

        mDeviceConfig.removeOnPropertiesChangedListener(mDeviceConfigListener);
        // We're asked to stop throttling, so reset brightness restrictions.
        mBrightnessCap = PowerManager.BRIGHTNESS_MAX;
        mBrightnessMaxReason = BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
@@ -97,9 +133,19 @@ class BrightnessThrottler {
        mThrottlingStatus = THROTTLING_INVALID;
    }

    void resetThrottlingData(BrightnessThrottlingData throttlingData) {
    private void resetThrottlingData() {
        resetThrottlingData(mDdcThrottlingData, mUniqueDisplayId);
    }

    void resetThrottlingData(BrightnessThrottlingData throttlingData, String displayId) {
        stop();
        mThrottlingData = throttlingData;

        mUniqueDisplayId = displayId;
        mDdcThrottlingData = throttlingData;
        mDeviceConfigListener.startListening();
        reloadBrightnessThrottlingDataOverride();
        mThrottlingData = mBrightnessThrottlingDataOverride.getOrDefault(mUniqueDisplayId,
                throttlingData);

        if (deviceSupportsThrottling()) {
            mSkinThermalStatusObserver.startObserving();
@@ -173,14 +219,148 @@ class BrightnessThrottler {
    private void dumpLocal(PrintWriter pw) {
        pw.println("BrightnessThrottler:");
        pw.println("  mThrottlingData=" + mThrottlingData);
        pw.println("  mDdcThrottlingData=" + mDdcThrottlingData);
        pw.println("  mUniqueDisplayId=" + mUniqueDisplayId);
        pw.println("  mThrottlingStatus=" + mThrottlingStatus);
        pw.println("  mBrightnessCap=" + mBrightnessCap);
        pw.println("  mBrightnessMaxReason=" +
            BrightnessInfo.briMaxReasonToString(mBrightnessMaxReason));
        pw.println("  mBrightnessThrottlingDataOverride=" + mBrightnessThrottlingDataOverride);
        pw.println("  mBrightnessThrottlingDataString=" + mBrightnessThrottlingDataString);

        mSkinThermalStatusObserver.dump(pw);
    }

    private String getBrightnessThrottlingDataString() {
        return mDeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
                DisplayManager.DeviceConfig.KEY_BRIGHTNESS_THROTTLING_DATA,
                /* defaultValue= */ null);
    }

    private boolean parseAndSaveData(@NonNull String strArray,
            @NonNull HashMap<String, BrightnessThrottlingData> tempBrightnessThrottlingData) {
        boolean validConfig = true;
        String[] items = strArray.split(",");
        int i = 0;

        try {
            String uniqueDisplayId = items[i++];

            // number of throttling points
            int noOfThrottlingPoints = Integer.parseInt(items[i++]);
            List<ThrottlingLevel> throttlingLevels = new ArrayList<>(noOfThrottlingPoints);

            // throttling level and point
            for (int j = 0; j < noOfThrottlingPoints; j++) {
                String severity = items[i++];
                int status = parseThermalStatus(severity);

                float brightnessPoint = parseBrightness(items[i++]);

                throttlingLevels.add(new ThrottlingLevel(status, brightnessPoint));
            }
            BrightnessThrottlingData toSave =
                    DisplayDeviceConfig.BrightnessThrottlingData.create(throttlingLevels);
            tempBrightnessThrottlingData.put(uniqueDisplayId, toSave);
        } catch (NumberFormatException | IndexOutOfBoundsException
                | UnknownThermalStatusException e) {
            validConfig = false;
            Slog.e(TAG, "Throttling data is invalid array: '" + strArray + "'", e);
        }

        if (i != items.length) {
            validConfig = false;
        }

        return validConfig;
    }

    public void reloadBrightnessThrottlingDataOverride() {
        HashMap<String, BrightnessThrottlingData> tempBrightnessThrottlingData =
                new HashMap<>(1);
        mBrightnessThrottlingDataString = getBrightnessThrottlingDataString();
        boolean validConfig = true;
        mBrightnessThrottlingDataOverride.clear();
        if (mBrightnessThrottlingDataString != null) {
            String[] throttlingDataSplits = mBrightnessThrottlingDataString.split(";");
            for (String s : throttlingDataSplits) {
                if (!parseAndSaveData(s, tempBrightnessThrottlingData)) {
                    validConfig = false;
                    break;
                }
            }

            if (validConfig) {
                mBrightnessThrottlingDataOverride.putAll(tempBrightnessThrottlingData);
                tempBrightnessThrottlingData.clear();
            }

        } else {
            Slog.w(TAG, "DeviceConfig BrightnessThrottlingData is null");
        }
    }

    /**
     * Listens to config data change and updates the brightness throttling data using
     * DisplayManager#KEY_BRIGHTNESS_THROTTLING_DATA.
     * The format should be a string similar to: "local:4619827677550801152,2,moderate,0.5,severe,
     * 0.379518072;local:4619827677550801151,1,moderate,0.75"
     * In this order:
     * <displayId>,<no of throttling levels>,[<severity as string>,<brightness cap>]
     * Where the latter part is repeated for each throttling level, and the entirety is repeated
     * for each display, separated by a semicolon.
     */
    public class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener {
        public Executor mExecutor = new HandlerExecutor(mDeviceConfigHandler);

        public void startListening() {
            mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
                    mExecutor, this);
        }

        @Override
        public void onPropertiesChanged(DeviceConfig.Properties properties) {
            reloadBrightnessThrottlingDataOverride();
            resetThrottlingData();
        }
    }

    private float parseBrightness(String intVal) throws NumberFormatException {
        float value = Float.parseFloat(intVal);
        if (value < PowerManager.BRIGHTNESS_MIN || value > PowerManager.BRIGHTNESS_MAX) {
            throw new NumberFormatException("Brightness constraint value out of bounds.");
        }
        return value;
    }

    @PowerManager.ThermalStatus private int parseThermalStatus(@NonNull String value)
            throws UnknownThermalStatusException {
        switch (value) {
            case "none":
                return PowerManager.THERMAL_STATUS_NONE;
            case "light":
                return PowerManager.THERMAL_STATUS_LIGHT;
            case "moderate":
                return PowerManager.THERMAL_STATUS_MODERATE;
            case "severe":
                return PowerManager.THERMAL_STATUS_SEVERE;
            case "critical":
                return PowerManager.THERMAL_STATUS_CRITICAL;
            case "emergency":
                return PowerManager.THERMAL_STATUS_EMERGENCY;
            case "shutdown":
                return PowerManager.THERMAL_STATUS_SHUTDOWN;
            default:
                throw new UnknownThermalStatusException("Invalid Thermal Status: " + value);
        }
    }

    private static class UnknownThermalStatusException extends Exception {
        UnknownThermalStatusException(String message) {
            super(message);
        }
    }

    private final class SkinThermalStatusObserver extends IThermalEventListener.Stub {
        private final Injector mInjector;
        private final Handler mHandler;
@@ -258,5 +438,10 @@ class BrightnessThrottler {
            return IThermalService.Stub.asInterface(
                    ServiceManager.getService(Context.THERMAL_SERVICE));
        }

        @NonNull
        public DeviceConfigInterface getDeviceConfig() {
            return DeviceConfigInterface.REAL;
        }
    }
}
+51 −5
Original line number Diff line number Diff line
@@ -279,9 +279,13 @@ public class DisplayDeviceConfig {
    private HighBrightnessModeData mHbmData;
    private DensityMapping mDensityMapping;
    private String mLoadedFrom = null;
    private Spline mSdrToHdrRatioSpline;

    // Brightness Throttling data may be updated via the DeviceConfig. Here we store the original
    // data, which comes from the ddc, and the current one, which may be the DeviceConfig
    // overwritten value.
    private BrightnessThrottlingData mBrightnessThrottlingData;
    private Spline mSdrToHdrRatioSpline;
    private BrightnessThrottlingData mOriginalBrightnessThrottlingData;

    private DisplayDeviceConfig(Context context) {
        mContext = context;
@@ -422,6 +426,10 @@ public class DisplayDeviceConfig {
        return config;
    }

    void setBrightnessThrottlingData(BrightnessThrottlingData brightnessThrottlingData) {
        mBrightnessThrottlingData = brightnessThrottlingData;
    }

    /**
     * Return the brightness mapping nits array.
     *
@@ -637,6 +645,7 @@ public class DisplayDeviceConfig {
                + ", mHbmData=" + mHbmData
                + ", mSdrToHdrRatioSpline=" + mSdrToHdrRatioSpline
                + ", mBrightnessThrottlingData=" + mBrightnessThrottlingData
                + ", mOriginalBrightnessThrottlingData=" + mOriginalBrightnessThrottlingData
                + ", mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease
                + ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
                + ", mBrightnessRampSlowDecrease=" + mBrightnessRampSlowDecrease
@@ -932,6 +941,7 @@ public class DisplayDeviceConfig {

        if (!badConfig) {
            mBrightnessThrottlingData = BrightnessThrottlingData.create(throttlingLevels);
            mOriginalBrightnessThrottlingData = mBrightnessThrottlingData;
        }
    }

@@ -1407,7 +1417,9 @@ public class DisplayDeviceConfig {
    /**
     * Container for brightness throttling data.
     */
    static class BrightnessThrottlingData {
    public static class BrightnessThrottlingData {
        public List<ThrottlingLevel> throttlingLevels;

        static class ThrottlingLevel {
            public @PowerManager.ThermalStatus int thermalStatus;
            public float brightness;
@@ -1421,9 +1433,25 @@ public class DisplayDeviceConfig {
            public String toString() {
                return "[" + thermalStatus + "," + brightness + "]";
            }

            @Override
            public boolean equals(Object obj) {
                if (!(obj instanceof ThrottlingLevel)) {
                    return false;
                }
                ThrottlingLevel otherThrottlingLevel = (ThrottlingLevel) obj;

        public List<ThrottlingLevel> throttlingLevels;
                return otherThrottlingLevel.thermalStatus == this.thermalStatus
                        && otherThrottlingLevel.brightness == this.brightness;
            }
            @Override
            public int hashCode() {
                int result = 1;
                result = 31 * result + thermalStatus;
                result = 31 * result + Float.hashCode(brightness);
                return result;
            }
        }

        static public BrightnessThrottlingData create(List<ThrottlingLevel> throttlingLevels)
        {
@@ -1482,12 +1510,30 @@ public class DisplayDeviceConfig {
                + "} ";
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }

            if (!(obj instanceof BrightnessThrottlingData)) {
                return false;
            }

            BrightnessThrottlingData otherBrightnessThrottlingData = (BrightnessThrottlingData) obj;
            return throttlingLevels.equals(otherBrightnessThrottlingData.throttlingLevels);
        }

        @Override
        public int hashCode() {
            return throttlingLevels.hashCode();
        }

        private BrightnessThrottlingData(List<ThrottlingLevel> inLevels) {
            throttlingLevels = new ArrayList<>(inLevels.size());
            for (ThrottlingLevel level : inLevels) {
                throttlingLevels.add(new ThrottlingLevel(level.thermalStatus, level.brightness));
            }
        }

    }
}
+2 −2
Original line number Diff line number Diff line
@@ -861,7 +861,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
                    }
                });
        mBrightnessThrottler.resetThrottlingData(
                mDisplayDeviceConfig.getBrightnessThrottlingData());
                mDisplayDeviceConfig.getBrightnessThrottlingData(), mUniqueDisplayId);
    }

    private void sendUpdatePowerState() {
@@ -1816,7 +1816,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
                () -> {
                    sendUpdatePowerStateLocked();
                    postBrightnessChangeRunnable();
                });
                }, mUniqueDisplayId);
    }

    private void blockScreenOn() {
+174 −7

File changed.

Preview size limit exceeded, changes collapsed.

Loading