Loading services/core/java/com/android/server/display/DisplayManagerService.java +61 −3 Original line number Diff line number Diff line Loading @@ -104,6 +104,7 @@ import android.os.UserManager; import android.provider.Settings; import android.sysprop.DisplayProperties; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.EventLog; import android.util.IntArray; Loading Loading @@ -256,6 +257,13 @@ public final class DisplayManagerService extends SystemService { final SparseArray<Pair<IVirtualDevice, DisplayWindowPolicyController>> mDisplayWindowPolicyControllers = new SparseArray<>(); /** * Map of every internal primary display device {@link HighBrightnessModeMetadata}s indexed by * {@link DisplayDevice#mUniqueId}. */ public final ArrayMap<String, HighBrightnessModeMetadata> mHighBrightnessModeMetadataMap = new ArrayMap<>(); // List of all currently registered display adapters. private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>(); Loading Loading @@ -1570,7 +1578,16 @@ public final class DisplayManagerService extends SystemService { DisplayPowerController dpc = mDisplayPowerControllers.get(displayId); if (dpc != null) { dpc.onDisplayChanged(); final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); if (device == null) { Slog.wtf(TAG, "Display Device is null in DisplayManagerService for display: " + display.getDisplayIdLocked()); return; } final String uniqueId = device.getUniqueId(); HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMap.get(uniqueId); dpc.onDisplayChanged(hbmMetadata); } } Loading Loading @@ -1627,7 +1644,15 @@ public final class DisplayManagerService extends SystemService { final int displayId = display.getDisplayIdLocked(); final DisplayPowerController dpc = mDisplayPowerControllers.get(displayId); if (dpc != null) { dpc.onDisplayChanged(); final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); if (device == null) { Slog.wtf(TAG, "Display Device is null in DisplayManagerService for display: " + display.getDisplayIdLocked()); return; } final String uniqueId = device.getUniqueId(); HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMap.get(uniqueId); dpc.onDisplayChanged(hbmMetadata); } } Loading Loading @@ -2611,6 +2636,31 @@ public final class DisplayManagerService extends SystemService { mLogicalDisplayMapper.forEachLocked(this::addDisplayPowerControllerLocked); } private HighBrightnessModeMetadata getHighBrightnessModeMetadata(LogicalDisplay display) { final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); if (device == null) { Slog.wtf(TAG, "Display Device is null in DisplayPowerController for display: " + display.getDisplayIdLocked()); return null; } // HBM brightness mode is only applicable to internal physical displays. if (display.getDisplayInfoLocked().type != Display.TYPE_INTERNAL) { return null; } final String uniqueId = device.getUniqueId(); if (mHighBrightnessModeMetadataMap.containsKey(uniqueId)) { return mHighBrightnessModeMetadataMap.get(uniqueId); } // HBM Time info not present. Create a new one for this physical display. HighBrightnessModeMetadata hbmInfo = new HighBrightnessModeMetadata(); mHighBrightnessModeMetadataMap.put(uniqueId, hbmInfo); return hbmInfo; } private void addDisplayPowerControllerLocked(LogicalDisplay display) { if (mPowerHandler == null) { // initPowerManagement has not yet been called. Loading @@ -2622,10 +2672,18 @@ public final class DisplayManagerService extends SystemService { final BrightnessSetting brightnessSetting = new BrightnessSetting(mPersistentDataStore, display, mSyncRoot); // If display is internal and has a HighBrightnessModeMetadata mapping, use that. // Or create a new one and use that. // We also need to pass a mapping of the HighBrightnessModeTimeInfoMap to // displayPowerController, so the hbm info can be correctly associated // with the corresponding displaydevice. HighBrightnessModeMetadata hbmMetadata = getHighBrightnessModeMetadata(display); final DisplayPowerController displayPowerController = new DisplayPowerController( mContext, mDisplayPowerCallbacks, mPowerHandler, mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting, () -> handleBrightnessChange(display)); () -> handleBrightnessChange(display), hbmMetadata); mDisplayPowerControllers.append(display.getDisplayIdLocked(), displayPowerController); } Loading services/core/java/com/android/server/display/DisplayPowerController.java +9 −5 Original line number Diff line number Diff line Loading @@ -391,6 +391,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private float[] mNitsRange; private final HighBrightnessModeController mHbmController; private final HighBrightnessModeMetadata mHighBrightnessModeMetadata; private final BrightnessThrottler mBrightnessThrottler; Loading Loading @@ -511,7 +512,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call DisplayPowerCallbacks callbacks, Handler handler, SensorManager sensorManager, DisplayBlanker blanker, LogicalDisplay logicalDisplay, BrightnessTracker brightnessTracker, BrightnessSetting brightnessSetting, Runnable onBrightnessChangeRunnable) { Runnable onBrightnessChangeRunnable, HighBrightnessModeMetadata hbmMetadata) { mLogicalDisplay = logicalDisplay; mDisplayId = mLogicalDisplay.getDisplayIdLocked(); final String displayIdStr = "[" + mDisplayId + "]"; Loading @@ -521,6 +522,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mSuspendBlockerIdProxPositive = displayIdStr + "prox positive"; mSuspendBlockerIdProxNegative = displayIdStr + "prox negative"; mSuspendBlockerIdProxDebounce = displayIdStr + "prox debounce"; mHighBrightnessModeMetadata = hbmMetadata; mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId(); Loading Loading @@ -793,7 +795,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call * of each display need to be properly reflected in AutomaticBrightnessController. */ @GuardedBy("DisplayManagerService.mSyncRoot") public void onDisplayChanged() { public void onDisplayChanged(HighBrightnessModeMetadata hbmMetadata) { final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); if (device == null) { Slog.wtf(TAG, "Display Device is null in DisplayPowerController for display: " Loading @@ -815,7 +817,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mUniqueDisplayId = uniqueId; mDisplayStatsId = mUniqueDisplayId.hashCode(); mDisplayDeviceConfig = config; loadFromDisplayDeviceConfig(token, info); loadFromDisplayDeviceConfig(token, info, hbmMetadata); /// Since the underlying display-device changed, we really don't know the // last command that was sent to change it's state. Lets assume it is unknown so Loading Loading @@ -872,7 +874,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info) { private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info, HighBrightnessModeMetadata hbmMetadata) { // All properties that depend on the associated DisplayDevice and the DDC must be // updated here. loadBrightnessRampRates(); Loading @@ -885,6 +888,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mBrightnessRampIncreaseMaxTimeMillis, mBrightnessRampDecreaseMaxTimeMillis); } mHbmController.setHighBrightnessModeMetadata(hbmMetadata); mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId, mDisplayDeviceConfig.getHighBrightnessModeData(), new HighBrightnessModeController.HdrBrightnessDeviceConfig() { Loading Loading @@ -1965,7 +1969,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mAutomaticBrightnessController != null) { mAutomaticBrightnessController.update(); } }, mContext); }, mHighBrightnessModeMetadata, mContext); } private BrightnessThrottler createBrightnessThrottlerLocked() { Loading services/core/java/com/android/server/display/HbmEvent.java 0 → 100644 +46 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.display; /** * Represents an event in which High Brightness Mode was enabled. */ class HbmEvent { private long mStartTimeMillis; private long mEndTimeMillis; HbmEvent(long startTimeMillis, long endTimeMillis) { this.mStartTimeMillis = startTimeMillis; this.mEndTimeMillis = endTimeMillis; } public long getStartTimeMillis() { return mStartTimeMillis; } public long getEndTimeMillis() { return mEndTimeMillis; } @Override public String toString() { return "HbmEvent: {startTimeMillis:" + mStartTimeMillis + ", endTimeMillis: " + mEndTimeMillis + "}, total: " + ((mEndTimeMillis - mStartTimeMillis) / 1000) + "]"; } } services/core/java/com/android/server/display/HighBrightnessModeController.java +51 −61 Original line number Diff line number Diff line Loading @@ -42,8 +42,8 @@ import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData; import com.android.server.display.DisplayManagerService.Clock; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.Iterator; import java.util.LinkedList; /** * Controls the status of high-brightness mode for devices that support it. This class assumes that Loading Loading @@ -105,30 +105,24 @@ class HighBrightnessModeController { private int mHbmStatsState = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF; /** * If HBM is currently running, this is the start time for the current HBM session. * If HBM is currently running, this is the start time and set of all events, * for the current HBM session. */ private long mRunningStartTimeMillis = -1; /** * 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.timeWindowMillis}. */ private LinkedList<HbmEvent> mEvents = new LinkedList<>(); private HighBrightnessModeMetadata mHighBrightnessModeMetadata = null; HighBrightnessModeController(Handler handler, int width, int height, IBinder displayToken, String displayUniqueId, float brightnessMin, float brightnessMax, HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg, Runnable hbmChangeCallback, Context context) { Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata, Context context) { this(new Injector(), handler, width, height, displayToken, displayUniqueId, brightnessMin, brightnessMax, hbmData, hdrBrightnessCfg, hbmChangeCallback, context); brightnessMax, hbmData, hdrBrightnessCfg, hbmChangeCallback, hbmMetadata, context); } @VisibleForTesting HighBrightnessModeController(Injector injector, Handler handler, int width, int height, IBinder displayToken, String displayUniqueId, float brightnessMin, float brightnessMax, HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg, Runnable hbmChangeCallback, Context context) { Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata, Context context) { mInjector = injector; mContext = context; mClock = injector.getClock(); Loading @@ -137,6 +131,7 @@ class HighBrightnessModeController { mBrightnessMin = brightnessMin; mBrightnessMax = brightnessMax; mHbmChangeCallback = hbmChangeCallback; mHighBrightnessModeMetadata = hbmMetadata; mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler); mSettingsObserver = new SettingsObserver(mHandler); mRecalcRunnable = this::recalculateTimeAllowance; Loading Loading @@ -222,19 +217,22 @@ class HighBrightnessModeController { // If we are starting or ending a high brightness mode session, store the current // session in mRunningStartTimeMillis, or the old one in mEvents. final boolean wasHbmDrainingAvailableTime = mRunningStartTimeMillis != -1; final long runningStartTime = mHighBrightnessModeMetadata.getRunningStartTimeMillis(); final boolean wasHbmDrainingAvailableTime = runningStartTime != -1; final boolean shouldHbmDrainAvailableTime = mBrightness > mHbmData.transitionPoint && !mIsHdrLayerPresent; if (wasHbmDrainingAvailableTime != shouldHbmDrainAvailableTime) { final long currentTime = mClock.uptimeMillis(); if (shouldHbmDrainAvailableTime) { mRunningStartTimeMillis = currentTime; mHighBrightnessModeMetadata.setRunningStartTimeMillis(currentTime); } else { mEvents.addFirst(new HbmEvent(mRunningStartTimeMillis, currentTime)); mRunningStartTimeMillis = -1; final HbmEvent hbmEvent = new HbmEvent(runningStartTime, currentTime); mHighBrightnessModeMetadata.addHbmEvent(hbmEvent); mHighBrightnessModeMetadata.setRunningStartTimeMillis(-1); if (DEBUG) { Slog.d(TAG, "New HBM event: " + mEvents.getFirst()); Slog.d(TAG, "New HBM event: " + mHighBrightnessModeMetadata.getHbmEventQueue().peekFirst()); } } } Loading @@ -260,6 +258,10 @@ class HighBrightnessModeController { mSettingsObserver.stopObserving(); } void setHighBrightnessModeMetadata(HighBrightnessModeMetadata hbmInfo) { mHighBrightnessModeMetadata = hbmInfo; } void resetHbmData(int width, int height, IBinder displayToken, String displayUniqueId, HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg) { mWidth = width; Loading Loading @@ -316,20 +318,22 @@ class HighBrightnessModeController { pw.println(" mBrightnessMax=" + mBrightnessMax); pw.println(" remainingTime=" + calculateRemainingTime(mClock.uptimeMillis())); pw.println(" mIsTimeAvailable= " + mIsTimeAvailable); pw.println(" mRunningStartTimeMillis=" + TimeUtils.formatUptime(mRunningStartTimeMillis)); pw.println(" mRunningStartTimeMillis=" + TimeUtils.formatUptime(mHighBrightnessModeMetadata.getRunningStartTimeMillis())); pw.println(" mIsThermalStatusWithinLimit=" + mIsThermalStatusWithinLimit); pw.println(" mIsBlockedByLowPowerMode=" + mIsBlockedByLowPowerMode); pw.println(" width*height=" + mWidth + "*" + mHeight); pw.println(" mEvents="); final long currentTime = mClock.uptimeMillis(); long lastStartTime = currentTime; if (mRunningStartTimeMillis != -1) { lastStartTime = dumpHbmEvent(pw, new HbmEvent(mRunningStartTimeMillis, currentTime)); long runningStartTimeMillis = mHighBrightnessModeMetadata.getRunningStartTimeMillis(); if (runningStartTimeMillis != -1) { lastStartTime = dumpHbmEvent(pw, new HbmEvent(runningStartTimeMillis, currentTime)); } for (HbmEvent event : mEvents) { if (lastStartTime > event.endTimeMillis) { for (HbmEvent event : mHighBrightnessModeMetadata.getHbmEventQueue()) { if (lastStartTime > event.getEndTimeMillis()) { pw.println(" event: [normal brightness]: " + TimeUtils.formatDuration(lastStartTime - event.endTimeMillis)); + TimeUtils.formatDuration(lastStartTime - event.getEndTimeMillis())); } lastStartTime = dumpHbmEvent(pw, event); } Loading @@ -338,12 +342,12 @@ class HighBrightnessModeController { } private long dumpHbmEvent(PrintWriter pw, HbmEvent event) { final long duration = event.endTimeMillis - event.startTimeMillis; final long duration = event.getEndTimeMillis() - event.getStartTimeMillis(); pw.println(" event: [" + TimeUtils.formatUptime(event.startTimeMillis) + ", " + TimeUtils.formatUptime(event.endTimeMillis) + "] (" + TimeUtils.formatUptime(event.getStartTimeMillis()) + ", " + TimeUtils.formatUptime(event.getEndTimeMillis()) + "] (" + TimeUtils.formatDuration(duration) + ")"); return event.startTimeMillis; return event.getStartTimeMillis(); } private boolean isCurrentlyAllowed() { Loading Loading @@ -372,13 +376,15 @@ class HighBrightnessModeController { // First, lets see how much time we've taken for any currently running // session of HBM. if (mRunningStartTimeMillis > 0) { if (mRunningStartTimeMillis > currentTime) { long runningStartTimeMillis = mHighBrightnessModeMetadata.getRunningStartTimeMillis(); if (runningStartTimeMillis > 0) { if (runningStartTimeMillis > currentTime) { Slog.e(TAG, "Start time set to the future. curr: " + currentTime + ", start: " + mRunningStartTimeMillis); mRunningStartTimeMillis = currentTime; + ", start: " + runningStartTimeMillis); mHighBrightnessModeMetadata.setRunningStartTimeMillis(currentTime); runningStartTimeMillis = currentTime; } timeAlreadyUsed = currentTime - mRunningStartTimeMillis; timeAlreadyUsed = currentTime - runningStartTimeMillis; } if (DEBUG) { Loading @@ -387,18 +393,19 @@ class HighBrightnessModeController { // Next, lets iterate through the history of previous sessions and add those times. final long windowstartTimeMillis = currentTime - mHbmData.timeWindowMillis; Iterator<HbmEvent> it = mEvents.iterator(); Iterator<HbmEvent> it = mHighBrightnessModeMetadata.getHbmEventQueue().iterator(); while (it.hasNext()) { final HbmEvent event = it.next(); // If this event ended before the current Timing window, discard forever and ever. if (event.endTimeMillis < windowstartTimeMillis) { if (event.getEndTimeMillis() < windowstartTimeMillis) { it.remove(); continue; } final long startTimeMillis = Math.max(event.startTimeMillis, windowstartTimeMillis); timeAlreadyUsed += event.endTimeMillis - startTimeMillis; final long startTimeMillis = Math.max(event.getStartTimeMillis(), windowstartTimeMillis); timeAlreadyUsed += event.getEndTimeMillis() - startTimeMillis; } if (DEBUG) { Loading @@ -425,17 +432,18 @@ class HighBrightnessModeController { // Calculate the time at which we want to recalculate mIsTimeAvailable in case a lux or // brightness change doesn't happen before then. long nextTimeout = -1; final ArrayDeque<HbmEvent> hbmEvents = mHighBrightnessModeMetadata.getHbmEventQueue(); if (mBrightness > mHbmData.transitionPoint) { // if we're in high-lux now, timeout when we run out of allowed time. nextTimeout = currentTime + remainingTime; } else if (!mIsTimeAvailable && mEvents.size() > 0) { } else if (!mIsTimeAvailable && hbmEvents.size() > 0) { // If we are not allowed...timeout when the oldest event moved outside of the timing // window by at least minTime. Basically, we're calculating the soonest time we can // get {@code timeMinMillis} back to us. final long windowstartTimeMillis = currentTime - mHbmData.timeWindowMillis; final HbmEvent lastEvent = mEvents.getLast(); final HbmEvent lastEvent = hbmEvents.peekLast(); final long startTimePlusMinMillis = Math.max(windowstartTimeMillis, lastEvent.startTimeMillis) Math.max(windowstartTimeMillis, lastEvent.getStartTimeMillis()) + mHbmData.timeMinMillis; final long timeWhenMinIsGainedBack = currentTime + (startTimePlusMinMillis - windowstartTimeMillis) - remainingTime; Loading @@ -459,9 +467,10 @@ class HighBrightnessModeController { + ", mUnthrottledBrightness: " + mUnthrottledBrightness + ", mThrottlingReason: " + BrightnessInfo.briMaxReasonToString(mThrottlingReason) + ", RunningStartTimeMillis: " + mRunningStartTimeMillis + ", RunningStartTimeMillis: " + mHighBrightnessModeMetadata.getRunningStartTimeMillis() + ", nextTimeout: " + (nextTimeout != -1 ? (nextTimeout - currentTime) : -1) + ", events: " + mEvents); + ", events: " + hbmEvents); } if (nextTimeout != -1) { Loading Loading @@ -588,25 +597,6 @@ class HighBrightnessModeController { } } /** * Represents an event in which High Brightness Mode was enabled. */ private static class HbmEvent { public long startTimeMillis; public long endTimeMillis; HbmEvent(long startTimeMillis, long endTimeMillis) { this.startTimeMillis = startTimeMillis; this.endTimeMillis = endTimeMillis; } @Override public String toString() { return "[Event: {" + startTimeMillis + ", " + endTimeMillis + "}, total: " + ((endTimeMillis - startTimeMillis) / 1000) + "]"; } } @VisibleForTesting class HdrListener extends SurfaceControlHdrLayerInfoListener { @Override Loading services/core/java/com/android/server/display/HighBrightnessModeMetadata.java 0 → 100644 +58 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.display; import java.util.ArrayDeque; /** * Represents High Brightness Mode metadata associated * with a specific internal physical display. * Required for separately storing data like time information, * and related events when display was in HBM mode per * physical internal display. */ class HighBrightnessModeMetadata { /** * Queue of previous HBM-events ordered from most recent to least recent. * Meant to store only the events that fall into the most recent * {@link HighBrightnessModeData#timeWindowMillis mHbmData.timeWindowMillis}. */ private final ArrayDeque<HbmEvent> mEvents = new ArrayDeque<>(); /** * If HBM is currently running, this is the start time for the current HBM session. */ private long mRunningStartTimeMillis = -1; public long getRunningStartTimeMillis() { return mRunningStartTimeMillis; } public void setRunningStartTimeMillis(long setTime) { mRunningStartTimeMillis = setTime; } public ArrayDeque<HbmEvent> getHbmEventQueue() { return mEvents; } public void addHbmEvent(HbmEvent hbmEvent) { mEvents.addFirst(hbmEvent); } } Loading
services/core/java/com/android/server/display/DisplayManagerService.java +61 −3 Original line number Diff line number Diff line Loading @@ -104,6 +104,7 @@ import android.os.UserManager; import android.provider.Settings; import android.sysprop.DisplayProperties; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.EventLog; import android.util.IntArray; Loading Loading @@ -256,6 +257,13 @@ public final class DisplayManagerService extends SystemService { final SparseArray<Pair<IVirtualDevice, DisplayWindowPolicyController>> mDisplayWindowPolicyControllers = new SparseArray<>(); /** * Map of every internal primary display device {@link HighBrightnessModeMetadata}s indexed by * {@link DisplayDevice#mUniqueId}. */ public final ArrayMap<String, HighBrightnessModeMetadata> mHighBrightnessModeMetadataMap = new ArrayMap<>(); // List of all currently registered display adapters. private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>(); Loading Loading @@ -1570,7 +1578,16 @@ public final class DisplayManagerService extends SystemService { DisplayPowerController dpc = mDisplayPowerControllers.get(displayId); if (dpc != null) { dpc.onDisplayChanged(); final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); if (device == null) { Slog.wtf(TAG, "Display Device is null in DisplayManagerService for display: " + display.getDisplayIdLocked()); return; } final String uniqueId = device.getUniqueId(); HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMap.get(uniqueId); dpc.onDisplayChanged(hbmMetadata); } } Loading Loading @@ -1627,7 +1644,15 @@ public final class DisplayManagerService extends SystemService { final int displayId = display.getDisplayIdLocked(); final DisplayPowerController dpc = mDisplayPowerControllers.get(displayId); if (dpc != null) { dpc.onDisplayChanged(); final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); if (device == null) { Slog.wtf(TAG, "Display Device is null in DisplayManagerService for display: " + display.getDisplayIdLocked()); return; } final String uniqueId = device.getUniqueId(); HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMap.get(uniqueId); dpc.onDisplayChanged(hbmMetadata); } } Loading Loading @@ -2611,6 +2636,31 @@ public final class DisplayManagerService extends SystemService { mLogicalDisplayMapper.forEachLocked(this::addDisplayPowerControllerLocked); } private HighBrightnessModeMetadata getHighBrightnessModeMetadata(LogicalDisplay display) { final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); if (device == null) { Slog.wtf(TAG, "Display Device is null in DisplayPowerController for display: " + display.getDisplayIdLocked()); return null; } // HBM brightness mode is only applicable to internal physical displays. if (display.getDisplayInfoLocked().type != Display.TYPE_INTERNAL) { return null; } final String uniqueId = device.getUniqueId(); if (mHighBrightnessModeMetadataMap.containsKey(uniqueId)) { return mHighBrightnessModeMetadataMap.get(uniqueId); } // HBM Time info not present. Create a new one for this physical display. HighBrightnessModeMetadata hbmInfo = new HighBrightnessModeMetadata(); mHighBrightnessModeMetadataMap.put(uniqueId, hbmInfo); return hbmInfo; } private void addDisplayPowerControllerLocked(LogicalDisplay display) { if (mPowerHandler == null) { // initPowerManagement has not yet been called. Loading @@ -2622,10 +2672,18 @@ public final class DisplayManagerService extends SystemService { final BrightnessSetting brightnessSetting = new BrightnessSetting(mPersistentDataStore, display, mSyncRoot); // If display is internal and has a HighBrightnessModeMetadata mapping, use that. // Or create a new one and use that. // We also need to pass a mapping of the HighBrightnessModeTimeInfoMap to // displayPowerController, so the hbm info can be correctly associated // with the corresponding displaydevice. HighBrightnessModeMetadata hbmMetadata = getHighBrightnessModeMetadata(display); final DisplayPowerController displayPowerController = new DisplayPowerController( mContext, mDisplayPowerCallbacks, mPowerHandler, mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting, () -> handleBrightnessChange(display)); () -> handleBrightnessChange(display), hbmMetadata); mDisplayPowerControllers.append(display.getDisplayIdLocked(), displayPowerController); } Loading
services/core/java/com/android/server/display/DisplayPowerController.java +9 −5 Original line number Diff line number Diff line Loading @@ -391,6 +391,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private float[] mNitsRange; private final HighBrightnessModeController mHbmController; private final HighBrightnessModeMetadata mHighBrightnessModeMetadata; private final BrightnessThrottler mBrightnessThrottler; Loading Loading @@ -511,7 +512,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call DisplayPowerCallbacks callbacks, Handler handler, SensorManager sensorManager, DisplayBlanker blanker, LogicalDisplay logicalDisplay, BrightnessTracker brightnessTracker, BrightnessSetting brightnessSetting, Runnable onBrightnessChangeRunnable) { Runnable onBrightnessChangeRunnable, HighBrightnessModeMetadata hbmMetadata) { mLogicalDisplay = logicalDisplay; mDisplayId = mLogicalDisplay.getDisplayIdLocked(); final String displayIdStr = "[" + mDisplayId + "]"; Loading @@ -521,6 +522,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mSuspendBlockerIdProxPositive = displayIdStr + "prox positive"; mSuspendBlockerIdProxNegative = displayIdStr + "prox negative"; mSuspendBlockerIdProxDebounce = displayIdStr + "prox debounce"; mHighBrightnessModeMetadata = hbmMetadata; mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId(); Loading Loading @@ -793,7 +795,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call * of each display need to be properly reflected in AutomaticBrightnessController. */ @GuardedBy("DisplayManagerService.mSyncRoot") public void onDisplayChanged() { public void onDisplayChanged(HighBrightnessModeMetadata hbmMetadata) { final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); if (device == null) { Slog.wtf(TAG, "Display Device is null in DisplayPowerController for display: " Loading @@ -815,7 +817,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mUniqueDisplayId = uniqueId; mDisplayStatsId = mUniqueDisplayId.hashCode(); mDisplayDeviceConfig = config; loadFromDisplayDeviceConfig(token, info); loadFromDisplayDeviceConfig(token, info, hbmMetadata); /// Since the underlying display-device changed, we really don't know the // last command that was sent to change it's state. Lets assume it is unknown so Loading Loading @@ -872,7 +874,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info) { private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info, HighBrightnessModeMetadata hbmMetadata) { // All properties that depend on the associated DisplayDevice and the DDC must be // updated here. loadBrightnessRampRates(); Loading @@ -885,6 +888,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mBrightnessRampIncreaseMaxTimeMillis, mBrightnessRampDecreaseMaxTimeMillis); } mHbmController.setHighBrightnessModeMetadata(hbmMetadata); mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId, mDisplayDeviceConfig.getHighBrightnessModeData(), new HighBrightnessModeController.HdrBrightnessDeviceConfig() { Loading Loading @@ -1965,7 +1969,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mAutomaticBrightnessController != null) { mAutomaticBrightnessController.update(); } }, mContext); }, mHighBrightnessModeMetadata, mContext); } private BrightnessThrottler createBrightnessThrottlerLocked() { Loading
services/core/java/com/android/server/display/HbmEvent.java 0 → 100644 +46 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.display; /** * Represents an event in which High Brightness Mode was enabled. */ class HbmEvent { private long mStartTimeMillis; private long mEndTimeMillis; HbmEvent(long startTimeMillis, long endTimeMillis) { this.mStartTimeMillis = startTimeMillis; this.mEndTimeMillis = endTimeMillis; } public long getStartTimeMillis() { return mStartTimeMillis; } public long getEndTimeMillis() { return mEndTimeMillis; } @Override public String toString() { return "HbmEvent: {startTimeMillis:" + mStartTimeMillis + ", endTimeMillis: " + mEndTimeMillis + "}, total: " + ((mEndTimeMillis - mStartTimeMillis) / 1000) + "]"; } }
services/core/java/com/android/server/display/HighBrightnessModeController.java +51 −61 Original line number Diff line number Diff line Loading @@ -42,8 +42,8 @@ import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData; import com.android.server.display.DisplayManagerService.Clock; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.Iterator; import java.util.LinkedList; /** * Controls the status of high-brightness mode for devices that support it. This class assumes that Loading Loading @@ -105,30 +105,24 @@ class HighBrightnessModeController { private int mHbmStatsState = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF; /** * If HBM is currently running, this is the start time for the current HBM session. * If HBM is currently running, this is the start time and set of all events, * for the current HBM session. */ private long mRunningStartTimeMillis = -1; /** * 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.timeWindowMillis}. */ private LinkedList<HbmEvent> mEvents = new LinkedList<>(); private HighBrightnessModeMetadata mHighBrightnessModeMetadata = null; HighBrightnessModeController(Handler handler, int width, int height, IBinder displayToken, String displayUniqueId, float brightnessMin, float brightnessMax, HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg, Runnable hbmChangeCallback, Context context) { Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata, Context context) { this(new Injector(), handler, width, height, displayToken, displayUniqueId, brightnessMin, brightnessMax, hbmData, hdrBrightnessCfg, hbmChangeCallback, context); brightnessMax, hbmData, hdrBrightnessCfg, hbmChangeCallback, hbmMetadata, context); } @VisibleForTesting HighBrightnessModeController(Injector injector, Handler handler, int width, int height, IBinder displayToken, String displayUniqueId, float brightnessMin, float brightnessMax, HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg, Runnable hbmChangeCallback, Context context) { Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata, Context context) { mInjector = injector; mContext = context; mClock = injector.getClock(); Loading @@ -137,6 +131,7 @@ class HighBrightnessModeController { mBrightnessMin = brightnessMin; mBrightnessMax = brightnessMax; mHbmChangeCallback = hbmChangeCallback; mHighBrightnessModeMetadata = hbmMetadata; mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler); mSettingsObserver = new SettingsObserver(mHandler); mRecalcRunnable = this::recalculateTimeAllowance; Loading Loading @@ -222,19 +217,22 @@ class HighBrightnessModeController { // If we are starting or ending a high brightness mode session, store the current // session in mRunningStartTimeMillis, or the old one in mEvents. final boolean wasHbmDrainingAvailableTime = mRunningStartTimeMillis != -1; final long runningStartTime = mHighBrightnessModeMetadata.getRunningStartTimeMillis(); final boolean wasHbmDrainingAvailableTime = runningStartTime != -1; final boolean shouldHbmDrainAvailableTime = mBrightness > mHbmData.transitionPoint && !mIsHdrLayerPresent; if (wasHbmDrainingAvailableTime != shouldHbmDrainAvailableTime) { final long currentTime = mClock.uptimeMillis(); if (shouldHbmDrainAvailableTime) { mRunningStartTimeMillis = currentTime; mHighBrightnessModeMetadata.setRunningStartTimeMillis(currentTime); } else { mEvents.addFirst(new HbmEvent(mRunningStartTimeMillis, currentTime)); mRunningStartTimeMillis = -1; final HbmEvent hbmEvent = new HbmEvent(runningStartTime, currentTime); mHighBrightnessModeMetadata.addHbmEvent(hbmEvent); mHighBrightnessModeMetadata.setRunningStartTimeMillis(-1); if (DEBUG) { Slog.d(TAG, "New HBM event: " + mEvents.getFirst()); Slog.d(TAG, "New HBM event: " + mHighBrightnessModeMetadata.getHbmEventQueue().peekFirst()); } } } Loading @@ -260,6 +258,10 @@ class HighBrightnessModeController { mSettingsObserver.stopObserving(); } void setHighBrightnessModeMetadata(HighBrightnessModeMetadata hbmInfo) { mHighBrightnessModeMetadata = hbmInfo; } void resetHbmData(int width, int height, IBinder displayToken, String displayUniqueId, HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg) { mWidth = width; Loading Loading @@ -316,20 +318,22 @@ class HighBrightnessModeController { pw.println(" mBrightnessMax=" + mBrightnessMax); pw.println(" remainingTime=" + calculateRemainingTime(mClock.uptimeMillis())); pw.println(" mIsTimeAvailable= " + mIsTimeAvailable); pw.println(" mRunningStartTimeMillis=" + TimeUtils.formatUptime(mRunningStartTimeMillis)); pw.println(" mRunningStartTimeMillis=" + TimeUtils.formatUptime(mHighBrightnessModeMetadata.getRunningStartTimeMillis())); pw.println(" mIsThermalStatusWithinLimit=" + mIsThermalStatusWithinLimit); pw.println(" mIsBlockedByLowPowerMode=" + mIsBlockedByLowPowerMode); pw.println(" width*height=" + mWidth + "*" + mHeight); pw.println(" mEvents="); final long currentTime = mClock.uptimeMillis(); long lastStartTime = currentTime; if (mRunningStartTimeMillis != -1) { lastStartTime = dumpHbmEvent(pw, new HbmEvent(mRunningStartTimeMillis, currentTime)); long runningStartTimeMillis = mHighBrightnessModeMetadata.getRunningStartTimeMillis(); if (runningStartTimeMillis != -1) { lastStartTime = dumpHbmEvent(pw, new HbmEvent(runningStartTimeMillis, currentTime)); } for (HbmEvent event : mEvents) { if (lastStartTime > event.endTimeMillis) { for (HbmEvent event : mHighBrightnessModeMetadata.getHbmEventQueue()) { if (lastStartTime > event.getEndTimeMillis()) { pw.println(" event: [normal brightness]: " + TimeUtils.formatDuration(lastStartTime - event.endTimeMillis)); + TimeUtils.formatDuration(lastStartTime - event.getEndTimeMillis())); } lastStartTime = dumpHbmEvent(pw, event); } Loading @@ -338,12 +342,12 @@ class HighBrightnessModeController { } private long dumpHbmEvent(PrintWriter pw, HbmEvent event) { final long duration = event.endTimeMillis - event.startTimeMillis; final long duration = event.getEndTimeMillis() - event.getStartTimeMillis(); pw.println(" event: [" + TimeUtils.formatUptime(event.startTimeMillis) + ", " + TimeUtils.formatUptime(event.endTimeMillis) + "] (" + TimeUtils.formatUptime(event.getStartTimeMillis()) + ", " + TimeUtils.formatUptime(event.getEndTimeMillis()) + "] (" + TimeUtils.formatDuration(duration) + ")"); return event.startTimeMillis; return event.getStartTimeMillis(); } private boolean isCurrentlyAllowed() { Loading Loading @@ -372,13 +376,15 @@ class HighBrightnessModeController { // First, lets see how much time we've taken for any currently running // session of HBM. if (mRunningStartTimeMillis > 0) { if (mRunningStartTimeMillis > currentTime) { long runningStartTimeMillis = mHighBrightnessModeMetadata.getRunningStartTimeMillis(); if (runningStartTimeMillis > 0) { if (runningStartTimeMillis > currentTime) { Slog.e(TAG, "Start time set to the future. curr: " + currentTime + ", start: " + mRunningStartTimeMillis); mRunningStartTimeMillis = currentTime; + ", start: " + runningStartTimeMillis); mHighBrightnessModeMetadata.setRunningStartTimeMillis(currentTime); runningStartTimeMillis = currentTime; } timeAlreadyUsed = currentTime - mRunningStartTimeMillis; timeAlreadyUsed = currentTime - runningStartTimeMillis; } if (DEBUG) { Loading @@ -387,18 +393,19 @@ class HighBrightnessModeController { // Next, lets iterate through the history of previous sessions and add those times. final long windowstartTimeMillis = currentTime - mHbmData.timeWindowMillis; Iterator<HbmEvent> it = mEvents.iterator(); Iterator<HbmEvent> it = mHighBrightnessModeMetadata.getHbmEventQueue().iterator(); while (it.hasNext()) { final HbmEvent event = it.next(); // If this event ended before the current Timing window, discard forever and ever. if (event.endTimeMillis < windowstartTimeMillis) { if (event.getEndTimeMillis() < windowstartTimeMillis) { it.remove(); continue; } final long startTimeMillis = Math.max(event.startTimeMillis, windowstartTimeMillis); timeAlreadyUsed += event.endTimeMillis - startTimeMillis; final long startTimeMillis = Math.max(event.getStartTimeMillis(), windowstartTimeMillis); timeAlreadyUsed += event.getEndTimeMillis() - startTimeMillis; } if (DEBUG) { Loading @@ -425,17 +432,18 @@ class HighBrightnessModeController { // Calculate the time at which we want to recalculate mIsTimeAvailable in case a lux or // brightness change doesn't happen before then. long nextTimeout = -1; final ArrayDeque<HbmEvent> hbmEvents = mHighBrightnessModeMetadata.getHbmEventQueue(); if (mBrightness > mHbmData.transitionPoint) { // if we're in high-lux now, timeout when we run out of allowed time. nextTimeout = currentTime + remainingTime; } else if (!mIsTimeAvailable && mEvents.size() > 0) { } else if (!mIsTimeAvailable && hbmEvents.size() > 0) { // If we are not allowed...timeout when the oldest event moved outside of the timing // window by at least minTime. Basically, we're calculating the soonest time we can // get {@code timeMinMillis} back to us. final long windowstartTimeMillis = currentTime - mHbmData.timeWindowMillis; final HbmEvent lastEvent = mEvents.getLast(); final HbmEvent lastEvent = hbmEvents.peekLast(); final long startTimePlusMinMillis = Math.max(windowstartTimeMillis, lastEvent.startTimeMillis) Math.max(windowstartTimeMillis, lastEvent.getStartTimeMillis()) + mHbmData.timeMinMillis; final long timeWhenMinIsGainedBack = currentTime + (startTimePlusMinMillis - windowstartTimeMillis) - remainingTime; Loading @@ -459,9 +467,10 @@ class HighBrightnessModeController { + ", mUnthrottledBrightness: " + mUnthrottledBrightness + ", mThrottlingReason: " + BrightnessInfo.briMaxReasonToString(mThrottlingReason) + ", RunningStartTimeMillis: " + mRunningStartTimeMillis + ", RunningStartTimeMillis: " + mHighBrightnessModeMetadata.getRunningStartTimeMillis() + ", nextTimeout: " + (nextTimeout != -1 ? (nextTimeout - currentTime) : -1) + ", events: " + mEvents); + ", events: " + hbmEvents); } if (nextTimeout != -1) { Loading Loading @@ -588,25 +597,6 @@ class HighBrightnessModeController { } } /** * Represents an event in which High Brightness Mode was enabled. */ private static class HbmEvent { public long startTimeMillis; public long endTimeMillis; HbmEvent(long startTimeMillis, long endTimeMillis) { this.startTimeMillis = startTimeMillis; this.endTimeMillis = endTimeMillis; } @Override public String toString() { return "[Event: {" + startTimeMillis + ", " + endTimeMillis + "}, total: " + ((endTimeMillis - startTimeMillis) / 1000) + "]"; } } @VisibleForTesting class HdrListener extends SurfaceControlHdrLayerInfoListener { @Override Loading
services/core/java/com/android/server/display/HighBrightnessModeMetadata.java 0 → 100644 +58 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.display; import java.util.ArrayDeque; /** * Represents High Brightness Mode metadata associated * with a specific internal physical display. * Required for separately storing data like time information, * and related events when display was in HBM mode per * physical internal display. */ class HighBrightnessModeMetadata { /** * Queue of previous HBM-events ordered from most recent to least recent. * Meant to store only the events that fall into the most recent * {@link HighBrightnessModeData#timeWindowMillis mHbmData.timeWindowMillis}. */ private final ArrayDeque<HbmEvent> mEvents = new ArrayDeque<>(); /** * If HBM is currently running, this is the start time for the current HBM session. */ private long mRunningStartTimeMillis = -1; public long getRunningStartTimeMillis() { return mRunningStartTimeMillis; } public void setRunningStartTimeMillis(long setTime) { mRunningStartTimeMillis = setTime; } public ArrayDeque<HbmEvent> getHbmEventQueue() { return mEvents; } public void addHbmEvent(HbmEvent hbmEvent) { mEvents.addFirst(hbmEvent); } }