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

Commit bfb3312c authored by Santos Cordon's avatar Santos Cordon Committed by Automerger Merge Worker
Browse files

Merge "Add low-power/thermal checks to highBrightnessMode" into sc-dev am: 77a21b70

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14920943

Change-Id: I3696756eec3702e9ba402d97885a978465fe7c8d
parents eb6ccc2b 77a21b70
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ class AutomaticBrightnessController {
    private static final int MSG_INVALIDATE_SHORT_TERM_MODEL = 3;
    private static final int MSG_UPDATE_FOREGROUND_APP = 4;
    private static final int MSG_UPDATE_FOREGROUND_APP_SYNC = 5;
    private static final int MSG_RUN_UPDATE = 6;

    // Length of the ambient light horizon used to calculate the long term estimate of ambient
    // light.
@@ -360,6 +361,13 @@ class AutomaticBrightnessController {
        return mBrightnessMapper.getDefaultConfig();
    }

    /**
     * Force recalculate of the state of automatic brightness.
     */
    public void update() {
        mHandler.sendEmptyMessage(MSG_RUN_UPDATE);
    }

    private boolean setDisplayPolicy(int policy) {
        if (mDisplayPolicy == policy) {
            return false;
@@ -910,6 +918,10 @@ class AutomaticBrightnessController {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_RUN_UPDATE:
                    updateAutoBrightness(true /*sendUpdate*/, false /*isManuallySet*/);
                    break;

                case MSG_UPDATE_AMBIENT_LUX:
                    updateAmbientLux();
                    break;
+44 −3
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import com.android.server.display.config.NitsMap;
import com.android.server.display.config.Point;
import com.android.server.display.config.RefreshRateRange;
import com.android.server.display.config.SensorDetails;
import com.android.server.display.config.ThermalStatus;
import com.android.server.display.config.XmlParser;

import org.xmlpull.v1.XmlPullParserException;
@@ -657,6 +658,8 @@ public class DisplayDeviceConfig {
            mHbmData.timeWindowMillis = hbmTiming.getTimeWindowSecs_all().longValue() * 1000;
            mHbmData.timeMaxMillis = hbmTiming.getTimeMaxSecs_all().longValue() * 1000;
            mHbmData.timeMinMillis = hbmTiming.getTimeMinSecs_all().longValue() * 1000;
            mHbmData.thermalStatusLimit = convertThermalStatus(hbm.getThermalStatusLimit_all());
            mHbmData.allowInLowPowerMode = hbm.getAllowInLowPowerMode_all();
            final RefreshRateRange rr = hbm.getRefreshRate_all();
            if (rr != null) {
                final float min = rr.getMinimum().floatValue();
@@ -743,6 +746,31 @@ public class DisplayDeviceConfig {
        }
    }

    private @PowerManager.ThermalStatus int convertThermalStatus(ThermalStatus value) {
        if (value == null) {
            return PowerManager.THERMAL_STATUS_NONE;
        }
        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:
                Slog.wtf(TAG, "Unexpected Thermal Status: " + value);
                return PowerManager.THERMAL_STATUS_NONE;
        }
    }

    static class SensorData {
        public String type;
        public String name;
@@ -781,6 +809,12 @@ public class DisplayDeviceConfig {
        /** Brightness level at which we transition from normal to high-brightness. */
        public float transitionPoint;

        /** Enable HBM only if the thermal status is not higher than this. */
        public @PowerManager.ThermalStatus int thermalStatusLimit;

        /** Whether HBM is allowed when {@code Settings.Global.LOW_POWER_MODE} is active. */
        public boolean allowInLowPowerMode;

        /** Time window for HBM. */
        public long timeWindowMillis;

@@ -792,13 +826,16 @@ public class DisplayDeviceConfig {

        HighBrightnessModeData() {}

        HighBrightnessModeData(float minimumLux, float transitionPoint,
                long timeWindowMillis, long timeMaxMillis, long timeMinMillis) {
        HighBrightnessModeData(float minimumLux, float transitionPoint, long timeWindowMillis,
                long timeMaxMillis, long timeMinMillis,
                @PowerManager.ThermalStatus int thermalStatusLimit, boolean allowInLowPowerMode) {
            this.minimumLux = minimumLux;
            this.transitionPoint = transitionPoint;
            this.timeWindowMillis = timeWindowMillis;
            this.timeMaxMillis = timeMaxMillis;
            this.timeMinMillis = timeMinMillis;
            this.thermalStatusLimit = thermalStatusLimit;
            this.allowInLowPowerMode = allowInLowPowerMode;
        }

        /**
@@ -807,10 +844,12 @@ public class DisplayDeviceConfig {
         */
        public void copyTo(@NonNull HighBrightnessModeData other) {
            other.minimumLux = minimumLux;
            other.transitionPoint = transitionPoint;
            other.timeWindowMillis = timeWindowMillis;
            other.timeMaxMillis = timeMaxMillis;
            other.timeMinMillis = timeMinMillis;
            other.transitionPoint = transitionPoint;
            other.thermalStatusLimit = thermalStatusLimit;
            other.allowInLowPowerMode = allowInLowPowerMode;
        }

        @Override
@@ -821,6 +860,8 @@ public class DisplayDeviceConfig {
                    + ", timeWindow: " + timeWindowMillis + "ms"
                    + ", timeMax: " + timeMaxMillis + "ms"
                    + ", timeMin: " + timeMinMillis + "ms"
                    + ", thermalStatusLimit: " + thermalStatusLimit
                    + ", allowInLowPowerMode: " + allowInLowPowerMode
                    + "} ";
        }
    }
+3 −1
Original line number Diff line number Diff line
@@ -1518,7 +1518,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
                () -> {
                    sendUpdatePowerStateLocked();
                    mHandler.post(mOnBrightnessChangeRunnable);
                });
                    // TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern.
                    mAutomaticBrightnessController.update();
                }, mContext);
    }

    private void blockScreenOn() {
+193 −10
Original line number Diff line number Diff line
@@ -16,11 +16,21 @@

package com.android.server.display;

import android.content.Context;
import android.database.ContentObserver;
import android.hardware.display.BrightnessInfo;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.IThermalEventListener;
import android.os.IThermalService;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.Temperature;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
import android.util.TimeUtils;
import android.view.SurfaceControlHdrLayerInfoListener;
@@ -52,6 +62,10 @@ class HighBrightnessModeController {
    private final Runnable mHbmChangeCallback;
    private final Runnable mRecalcRunnable;
    private final Clock mClock;
    private final SkinThermalStatusObserver mSkinThermalStatusObserver;
    private final Context mContext;
    private final SettingsObserver mSettingsObserver;
    private final Injector mInjector;

    private SurfaceControlHdrLayerInfoListener mHdrListener;
    private HighBrightnessModeData mHbmData;
@@ -63,6 +77,8 @@ class HighBrightnessModeController {
    private float mAutoBrightness;
    private int mHbmMode = BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
    private boolean mIsHdrLayerPresent = false;
    private boolean mIsThermalStatusWithinLimit = true;
    private boolean mIsBlockedByLowPowerMode = false;

    /**
     * If HBM is currently running, this is the start time for the current HBM session.
@@ -72,29 +88,33 @@ class HighBrightnessModeController {
    /**
     * List of previous HBM-events ordered from most recent to least recent.
     * Meant to store only the events that fall into the most recent
     * {@link mHbmData.timeWindowSecs}.
     * {@link mHbmData.timeWindowMillis}.
     */
    private LinkedList<HbmEvent> mEvents = new LinkedList<>();

    HighBrightnessModeController(Handler handler, IBinder displayToken, float brightnessMin,
            float brightnessMax, HighBrightnessModeData hbmData, Runnable hbmChangeCallback) {
        this(SystemClock::uptimeMillis, handler, displayToken, brightnessMin, brightnessMax,
                hbmData, hbmChangeCallback);
            float brightnessMax, HighBrightnessModeData hbmData, Runnable hbmChangeCallback,
            Context context) {
        this(new Injector(), handler, displayToken, brightnessMin, brightnessMax,
                hbmData, hbmChangeCallback, context);
    }

    @VisibleForTesting
    HighBrightnessModeController(Clock clock, Handler handler, IBinder displayToken,
    HighBrightnessModeController(Injector injector, Handler handler, IBinder displayToken,
            float brightnessMin, float brightnessMax, HighBrightnessModeData hbmData,
            Runnable hbmChangeCallback) {
        mClock = clock;
            Runnable hbmChangeCallback, Context context) {
        mInjector = injector;
        mClock = injector.getClock();
        mHandler = handler;
        mBrightnessMin = brightnessMin;
        mBrightnessMax = brightnessMax;
        mHbmChangeCallback = hbmChangeCallback;
        mContext = context;
        mAutoBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
        mRecalcRunnable = this::recalculateTimeAllowance;
        mHdrListener = new HdrListener();

        mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler);
        mSettingsObserver = new SettingsObserver(mHandler);
        resetHbmData(displayToken, hbmData);
    }

@@ -178,14 +198,26 @@ class HighBrightnessModeController {

    void stop() {
        registerHdrListener(null /*displayToken*/);
        mSkinThermalStatusObserver.stopObserving();
        mSettingsObserver.stopObserving();
    }

    void resetHbmData(IBinder displayToken, HighBrightnessModeData hbmData) {
        mHbmData = hbmData;
        unregisterHdrListener();
        mSkinThermalStatusObserver.stopObserving();
        mSettingsObserver.stopObserving();
        if (deviceSupportsHbm()) {
            registerHdrListener(displayToken);
            recalculateTimeAllowance();
            if (mHbmData.thermalStatusLimit > PowerManager.THERMAL_STATUS_NONE) {
                mIsThermalStatusWithinLimit = true;
                mSkinThermalStatusObserver.startObserving();
            }
            if (!mHbmData.allowInLowPowerMode) {
                mIsBlockedByLowPowerMode = false;
                mSettingsObserver.startObserving();
            }
        }
    }

@@ -208,6 +240,8 @@ class HighBrightnessModeController {
        pw.println("  mBrightnessMin=" + mBrightnessMin);
        pw.println("  mBrightnessMax=" + mBrightnessMax);
        pw.println("  mRunningStartTimeMillis=" + TimeUtils.formatUptime(mRunningStartTimeMillis));
        pw.println("  mIsThermalStatusWithinLimit=" + mIsThermalStatusWithinLimit);
        pw.println("  mIsBlockedByLowPowerMode=" + mIsBlockedByLowPowerMode);
        pw.println("  mEvents=");
        final long currentTime = mClock.uptimeMillis();
        long lastStartTime = currentTime;
@@ -221,6 +255,8 @@ class HighBrightnessModeController {
            }
            lastStartTime = dumpHbmEvent(pw, event);
        }

        mSkinThermalStatusObserver.dump(pw);
    }

    private long dumpHbmEvent(PrintWriter pw, HbmEvent event) {
@@ -234,7 +270,8 @@ class HighBrightnessModeController {

    private boolean isCurrentlyAllowed() {
        return mIsHdrLayerPresent
                || (mIsAutoBrightnessEnabled && mIsTimeAvailable && mIsInAllowedAmbientRange);
                || (mIsAutoBrightnessEnabled && mIsTimeAvailable && mIsInAllowedAmbientRange
                && mIsThermalStatusWithinLimit && !mIsBlockedByLowPowerMode);
    }

    private boolean deviceSupportsHbm() {
@@ -327,6 +364,12 @@ class HighBrightnessModeController {
                    + ", remainingAllowedTime: " + remainingTime
                    + ", isLuxHigh: " + mIsInAllowedAmbientRange
                    + ", isHBMCurrentlyAllowed: " + isCurrentlyAllowed()
                    + ", isHdrLayerPresent: " + mIsHdrLayerPresent
                    + ", isAutoBrightnessEnabled: " +  mIsAutoBrightnessEnabled
                    + ", mIsTimeAvailable: " + mIsTimeAvailable
                    + ", mIsInAllowedAmbientRange: " + mIsInAllowedAmbientRange
                    + ", mIsThermalStatusWithinLimit: " + mIsThermalStatusWithinLimit
                    + ", mIsBlockedByLowPowerMode: " + mIsBlockedByLowPowerMode
                    + ", brightness: " + mAutoBrightness
                    + ", RunningStartTimeMillis: " + mRunningStartTimeMillis
                    + ", nextTimeout: " + (nextTimeout != -1 ? (nextTimeout - currentTime) : -1)
@@ -337,8 +380,11 @@ class HighBrightnessModeController {
            mHandler.removeCallbacks(mRecalcRunnable);
            mHandler.postAtTime(mRecalcRunnable, nextTimeout + 1);
        }

        // Update the state of the world
        updateHbmMode();
    }

    private void updateHbmMode() {
        int newHbmMode = calculateHighBrightnessMode();
        if (mHbmMode != newHbmMode) {
            mHbmMode = newHbmMode;
@@ -409,4 +455,141 @@ class HighBrightnessModeController {
            });
        }
    }

    private final class SkinThermalStatusObserver extends IThermalEventListener.Stub {
        private final Injector mInjector;
        private final Handler mHandler;

        private IThermalService mThermalService;
        private boolean mStarted;

        SkinThermalStatusObserver(Injector injector, Handler handler) {
            mInjector = injector;
            mHandler = handler;
        }

        @Override
        public void notifyThrottling(Temperature temp) {
            if (DEBUG) {
                Slog.d(TAG, "New thermal throttling status "
                        + ", current thermal status = " + temp.getStatus()
                        + ", threshold = " + mHbmData.thermalStatusLimit);
            }
            mHandler.post(() -> {
                mIsThermalStatusWithinLimit = temp.getStatus() <= mHbmData.thermalStatusLimit;
                // This recalculates HbmMode and runs mHbmChangeCallback if the mode has changed
                updateHbmMode();
            });
        }

        void startObserving() {
            if (mStarted) {
                if (DEBUG) {
                    Slog.d(TAG, "Thermal status observer already started");
                }
                return;
            }
            mThermalService = mInjector.getThermalService();
            if (mThermalService == null) {
                Slog.w(TAG, "Could not observe thermal status. Service not available");
                return;
            }
            try {
                // We get a callback immediately upon registering so there's no need to query
                // for the current value.
                mThermalService.registerThermalEventListenerWithType(this, Temperature.TYPE_SKIN);
                mStarted = true;
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to register thermal status listener", e);
            }
        }

        void stopObserving() {
            mIsThermalStatusWithinLimit = true;
            if (!mStarted) {
                if (DEBUG) {
                    Slog.d(TAG, "Stop skipped because thermal status observer not started");
                }
                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("  SkinThermalStatusObserver:");
            writer.println("    mStarted: " + mStarted);
            if (mThermalService != null) {
                writer.println("    ThermalService available");
            } else {
                writer.println("    ThermalService not available");
            }
        }
    }

    private final class SettingsObserver extends ContentObserver {
        private final Uri mLowPowerModeSetting = Settings.Global.getUriFor(
                Settings.Global.LOW_POWER_MODE);
        private boolean mStarted;

        SettingsObserver(Handler handler) {
            super(handler);
        }

        @Override
        public void onChange(boolean selfChange, Uri uri) {
            updateLowPower();
        }

        void startObserving() {
            if (!mStarted) {
                mContext.getContentResolver().registerContentObserver(mLowPowerModeSetting,
                        false /*notifyForDescendants*/, this, UserHandle.USER_ALL);
                mStarted = true;
                updateLowPower();
            }
        }

        void stopObserving() {
            mIsBlockedByLowPowerMode = false;
            if (mStarted) {
                mContext.getContentResolver().unregisterContentObserver(this);
                mStarted = false;
            }
        }

        private void updateLowPower() {
            final boolean isLowPowerMode = isLowPowerMode();
            if (isLowPowerMode == mIsBlockedByLowPowerMode) {
                return;
            }
            if (DEBUG) {
                Slog.d(TAG, "Settings.Global.LOW_POWER_MODE enabled: " + isLowPowerMode);
            }
            mIsBlockedByLowPowerMode = isLowPowerMode;
            // this recalculates HbmMode and runs mHbmChangeCallback if the mode has changed
            updateHbmMode();
        }

        private boolean isLowPowerMode() {
            return Settings.Global.getInt(
                    mContext.getContentResolver(), Settings.Global.LOW_POWER_MODE, 0) != 0;
        }
    }

    public static class Injector {
        public Clock getClock() {
            return SystemClock::uptimeMillis;
        }

        public IThermalService getThermalService() {
            return IThermalService.Stub.asInterface(
                    ServiceManager.getService(Context.THERMAL_SERVICE));
        }
    }
}
+23 −0
Original line number Diff line number Diff line
@@ -81,6 +81,16 @@
                <xs:annotation name="nullable"/>
                <xs:annotation name="final"/>
            </xs:element>
            <!-- The highest (most severe) thermal status at which high-brightness-mode is allowed
                 to operate. -->
            <xs:element name="thermalStatusLimit" type="thermalStatus" minOccurs="0" maxOccurs="1">
                <xs:annotation name="nonnull"/>
                <xs:annotation name="final"/>
            </xs:element>
            <xs:element name="allowInLowPowerMode" type="xs:boolean" minOccurs="0" maxOccurs="1">
                <xs:annotation name="nonnull"/>
                <xs:annotation name="final"/>
            </xs:element>
        </xs:all>
        <xs:attribute name="enabled" type="xs:boolean" use="optional"/>
    </xs:complexType>
@@ -102,6 +112,19 @@
        </xs:all>
    </xs:complexType>

    <!-- Maps to PowerManager.THERMAL_STATUS_* values. -->
    <xs:simpleType name="thermalStatus">
        <xs:restriction base="xs:string">
            <xs:enumeration value="none"/>
            <xs:enumeration value="light"/>
            <xs:enumeration value="moderate"/>
            <xs:enumeration value="severe"/>
            <xs:enumeration value="critical"/>
            <xs:enumeration value="emergency"/>
            <xs:enumeration value="shutdown"/>
        </xs:restriction>
    </xs:simpleType>

    <xs:complexType name="nitsMap">
        <xs:sequence>
            <xs:element name="point" type="point" maxOccurs="unbounded" minOccurs="2">
Loading