Loading services/core/java/com/android/server/display/AutomaticBrightnessController.java +12 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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; Loading Loading @@ -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; Loading services/core/java/com/android/server/display/DisplayDeviceConfig.java +44 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; } /** Loading @@ -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 Loading @@ -821,6 +860,8 @@ public class DisplayDeviceConfig { + ", timeWindow: " + timeWindowMillis + "ms" + ", timeMax: " + timeMaxMillis + "ms" + ", timeMin: " + timeMinMillis + "ms" + ", thermalStatusLimit: " + thermalStatusLimit + ", allowInLowPowerMode: " + allowInLowPowerMode + "} "; } } Loading services/core/java/com/android/server/display/DisplayPowerController.java +3 −1 Original line number Diff line number Diff line Loading @@ -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() { Loading services/core/java/com/android/server/display/HighBrightnessModeController.java +193 −10 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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. Loading @@ -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); } Loading Loading @@ -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(); } } } Loading @@ -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; Loading @@ -221,6 +255,8 @@ class HighBrightnessModeController { } lastStartTime = dumpHbmEvent(pw, event); } mSkinThermalStatusObserver.dump(pw); } private long dumpHbmEvent(PrintWriter pw, HbmEvent event) { Loading @@ -234,7 +270,8 @@ class HighBrightnessModeController { private boolean isCurrentlyAllowed() { return mIsHdrLayerPresent || (mIsAutoBrightnessEnabled && mIsTimeAvailable && mIsInAllowedAmbientRange); || (mIsAutoBrightnessEnabled && mIsTimeAvailable && mIsInAllowedAmbientRange && mIsThermalStatusWithinLimit && !mIsBlockedByLowPowerMode); } private boolean deviceSupportsHbm() { Loading Loading @@ -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) Loading @@ -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; Loading Loading @@ -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)); } } } services/core/xsd/display-device-config/display-device-config.xsd +23 −0 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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 Loading
services/core/java/com/android/server/display/AutomaticBrightnessController.java +12 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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; Loading Loading @@ -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; Loading
services/core/java/com/android/server/display/DisplayDeviceConfig.java +44 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; } /** Loading @@ -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 Loading @@ -821,6 +860,8 @@ public class DisplayDeviceConfig { + ", timeWindow: " + timeWindowMillis + "ms" + ", timeMax: " + timeMaxMillis + "ms" + ", timeMin: " + timeMinMillis + "ms" + ", thermalStatusLimit: " + thermalStatusLimit + ", allowInLowPowerMode: " + allowInLowPowerMode + "} "; } } Loading
services/core/java/com/android/server/display/DisplayPowerController.java +3 −1 Original line number Diff line number Diff line Loading @@ -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() { Loading
services/core/java/com/android/server/display/HighBrightnessModeController.java +193 −10 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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. Loading @@ -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); } Loading Loading @@ -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(); } } } Loading @@ -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; Loading @@ -221,6 +255,8 @@ class HighBrightnessModeController { } lastStartTime = dumpHbmEvent(pw, event); } mSkinThermalStatusObserver.dump(pw); } private long dumpHbmEvent(PrintWriter pw, HbmEvent event) { Loading @@ -234,7 +270,8 @@ class HighBrightnessModeController { private boolean isCurrentlyAllowed() { return mIsHdrLayerPresent || (mIsAutoBrightnessEnabled && mIsTimeAvailable && mIsInAllowedAmbientRange); || (mIsAutoBrightnessEnabled && mIsTimeAvailable && mIsInAllowedAmbientRange && mIsThermalStatusWithinLimit && !mIsBlockedByLowPowerMode); } private boolean deviceSupportsHbm() { Loading Loading @@ -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) Loading @@ -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; Loading Loading @@ -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)); } } }
services/core/xsd/display-device-config/display-device-config.xsd +23 −0 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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