1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.power; 18 19 import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP; 20 import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE; 21 import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING; 22 import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING; 23 import static android.os.PowerManagerInternal.isInteractive; 24 25 import static com.android.internal.util.LatencyTracker.ACTION_TURN_ON_SCREEN; 26 import static com.android.server.power.PowerManagerService.TRACE_SCREEN_ON; 27 import static com.android.server.power.PowerManagerService.USER_ACTIVITY_SCREEN_BRIGHT; 28 import static com.android.server.power.PowerManagerService.WAKE_LOCK_DOZE; 29 import static com.android.server.power.PowerManagerService.WAKE_LOCK_DRAW; 30 import static com.android.server.power.PowerManagerService.WAKE_LOCK_SCREEN_BRIGHT; 31 import static com.android.server.power.PowerManagerService.WAKE_LOCK_SCREEN_DIM; 32 import static com.android.server.power.PowerManagerService.WAKE_LOCK_STAY_AWAKE; 33 34 import android.hardware.display.DisplayManagerInternal; 35 import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; 36 import android.os.PowerManager; 37 import android.os.PowerManagerInternal; 38 import android.os.PowerSaveState; 39 import android.os.Trace; 40 import android.util.Slog; 41 import android.view.Display; 42 43 import com.android.internal.annotations.VisibleForTesting; 44 import com.android.internal.util.LatencyTracker; 45 46 /** 47 * Used to store power related requests to every display in a 48 * {@link com.android.server.display.DisplayGroup}. 49 * For each {@link com.android.server.display.DisplayGroup} there exists a {@link PowerGroup}. 50 * The mapping is tracked in {@link PowerManagerService}. 51 * <p><b>Note:</b> Methods with the {@code *Locked} suffix require the 52 * {@code PowerManagerService#mLock} to be held by the caller. 53 */ 54 public class PowerGroup { 55 private static final String TAG = PowerGroup.class.getSimpleName(); 56 private static final boolean DEBUG = false; 57 58 @VisibleForTesting 59 final DisplayPowerRequest mDisplayPowerRequest = new DisplayPowerRequest(); 60 private final PowerGroupListener mWakefulnessListener; 61 private final Notifier mNotifier; 62 private final DisplayManagerInternal mDisplayManagerInternal; 63 private final boolean mSupportsSandman; 64 private final int mGroupId; 65 /** True if DisplayManagerService has applied all the latest display states that were requested 66 * for this group. */ 67 private boolean mReady; 68 /** True if this group is in the process of powering on */ 69 private boolean mPoweringOn; 70 /** True if this group is about to dream */ 71 private boolean mIsSandmanSummoned; 72 private int mUserActivitySummary; 73 /** The current wakefulness of this group */ 74 private int mWakefulness; 75 private int mWakeLockSummary; 76 private long mLastPowerOnTime; 77 private long mLastUserActivityTime; 78 private long mLastUserActivityTimeNoChangeLights; 79 @PowerManager.UserActivityEvent 80 private int mLastUserActivityEvent; 81 /** Timestamp (milliseconds since boot) of the last time the power group was awoken.*/ 82 private long mLastWakeTime; 83 /** Timestamp (milliseconds since boot) of the last time the power group was put to sleep. */ 84 private long mLastSleepTime; 85 PowerGroup(int groupId, PowerGroupListener wakefulnessListener, Notifier notifier, DisplayManagerInternal displayManagerInternal, int wakefulness, boolean ready, boolean supportsSandman, long eventTime)86 PowerGroup(int groupId, PowerGroupListener wakefulnessListener, Notifier notifier, 87 DisplayManagerInternal displayManagerInternal, int wakefulness, boolean ready, 88 boolean supportsSandman, long eventTime) { 89 mGroupId = groupId; 90 mWakefulnessListener = wakefulnessListener; 91 mNotifier = notifier; 92 mDisplayManagerInternal = displayManagerInternal; 93 mWakefulness = wakefulness; 94 mReady = ready; 95 mSupportsSandman = supportsSandman; 96 mLastWakeTime = eventTime; 97 mLastSleepTime = eventTime; 98 } 99 PowerGroup(int wakefulness, PowerGroupListener wakefulnessListener, Notifier notifier, DisplayManagerInternal displayManagerInternal, long eventTime)100 PowerGroup(int wakefulness, PowerGroupListener wakefulnessListener, Notifier notifier, 101 DisplayManagerInternal displayManagerInternal, long eventTime) { 102 mGroupId = Display.DEFAULT_DISPLAY_GROUP; 103 mWakefulnessListener = wakefulnessListener; 104 mNotifier = notifier; 105 mDisplayManagerInternal = displayManagerInternal; 106 mWakefulness = wakefulness; 107 mReady = false; 108 mSupportsSandman = true; 109 mLastWakeTime = eventTime; 110 mLastSleepTime = eventTime; 111 } 112 getLastWakeTimeLocked()113 long getLastWakeTimeLocked() { 114 return mLastWakeTime; 115 } 116 getLastSleepTimeLocked()117 long getLastSleepTimeLocked() { 118 return mLastSleepTime; 119 } 120 getWakefulnessLocked()121 int getWakefulnessLocked() { 122 return mWakefulness; 123 } 124 getGroupId()125 int getGroupId() { 126 return mGroupId; 127 } 128 129 /** 130 * Sets the {@code wakefulness} value for this {@link PowerGroup}. 131 * 132 * @return {@code true} if the wakefulness value was changed; {@code false} otherwise. 133 */ setWakefulnessLocked(int newWakefulness, long eventTime, int uid, int reason, int opUid, String opPackageName, String details)134 boolean setWakefulnessLocked(int newWakefulness, long eventTime, int uid, int reason, int opUid, 135 String opPackageName, String details) { 136 if (mWakefulness != newWakefulness) { 137 if (newWakefulness == WAKEFULNESS_AWAKE) { 138 setLastPowerOnTimeLocked(eventTime); 139 setIsPoweringOnLocked(true); 140 mLastWakeTime = eventTime; 141 } else if (isInteractive(mWakefulness) && !isInteractive(newWakefulness)) { 142 mLastSleepTime = eventTime; 143 } 144 mWakefulness = newWakefulness; 145 mWakefulnessListener.onWakefulnessChangedLocked(mGroupId, mWakefulness, eventTime, 146 reason, uid, opUid, opPackageName, details); 147 return true; 148 } 149 return false; 150 } 151 152 /** 153 * Returns {@code true} if every display in this group has its requested state matching 154 * its actual state. 155 */ isReadyLocked()156 boolean isReadyLocked() { 157 return mReady; 158 } 159 160 /** 161 * Sets whether the displays of this group are all ready. 162 * 163 * <p>A display is ready if its reported 164 * {@link android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks#onStateChanged() 165 * actual state} matches its 166 * {@link android.hardware.display.DisplayManagerInternal#requestPowerState requested state}. 167 * 168 * @param isReady {@code true} if every display in the group is ready; otherwise {@code false}. 169 * @return {@code true} if the ready state changed; otherwise {@code false}. 170 */ setReadyLocked(boolean isReady)171 boolean setReadyLocked(boolean isReady) { 172 if (mReady != isReady) { 173 mReady = isReady; 174 return true; 175 } 176 return false; 177 } 178 getLastPowerOnTimeLocked()179 long getLastPowerOnTimeLocked() { 180 return mLastPowerOnTime; 181 } 182 setLastPowerOnTimeLocked(long time)183 void setLastPowerOnTimeLocked(long time) { 184 mLastPowerOnTime = time; 185 } 186 isPoweringOnLocked()187 boolean isPoweringOnLocked() { 188 return mPoweringOn; 189 } 190 setIsPoweringOnLocked(boolean isPoweringOnNew)191 void setIsPoweringOnLocked(boolean isPoweringOnNew) { 192 mPoweringOn = isPoweringOnNew; 193 } 194 isSandmanSummonedLocked()195 boolean isSandmanSummonedLocked() { 196 return mIsSandmanSummoned; 197 } 198 199 /** 200 * Sets whether or not the sandman is summoned for this {@link PowerGroup}. 201 * 202 * @param isSandmanSummoned {@code true} to summon the sandman; {@code false} to unsummon. 203 */ setSandmanSummonedLocked(boolean isSandmanSummoned)204 void setSandmanSummonedLocked(boolean isSandmanSummoned) { 205 mIsSandmanSummoned = isSandmanSummoned; 206 } 207 wakeUpLocked(long eventTime, @PowerManager.WakeReason int reason, String details, int uid, String opPackageName, int opUid, LatencyTracker latencyTracker)208 void wakeUpLocked(long eventTime, @PowerManager.WakeReason int reason, String details, int uid, 209 String opPackageName, int opUid, LatencyTracker latencyTracker) { 210 if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE) { 211 return; 212 } 213 214 Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakePowerGroup" + mGroupId); 215 try { 216 Slog.i(TAG, "Waking up power group from " 217 + PowerManagerInternal.wakefulnessToString(mWakefulness) 218 + " (groupId=" + mGroupId 219 + ", uid=" + uid 220 + ", reason=" + PowerManager.wakeReasonToString(reason) 221 + ", details=" + details 222 + ")..."); 223 Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, mGroupId); 224 // The instrument will be timed out automatically after 2 seconds. 225 latencyTracker.onActionStart(ACTION_TURN_ON_SCREEN, String.valueOf(mGroupId)); 226 227 setWakefulnessLocked(WAKEFULNESS_AWAKE, eventTime, uid, reason, opUid, 228 opPackageName, details); 229 } finally { 230 Trace.traceEnd(Trace.TRACE_TAG_POWER); 231 } 232 } 233 dreamLocked(long eventTime, int uid, boolean allowWake)234 boolean dreamLocked(long eventTime, int uid, boolean allowWake) { 235 if (eventTime < mLastWakeTime || (!allowWake && mWakefulness != WAKEFULNESS_AWAKE)) { 236 return false; 237 } 238 239 Trace.traceBegin(Trace.TRACE_TAG_POWER, "dreamPowerGroup" + getGroupId()); 240 try { 241 Slog.i(TAG, "Napping power group (groupId=" + getGroupId() + ", uid=" + uid + ")..."); 242 setSandmanSummonedLocked(true); 243 setWakefulnessLocked(WAKEFULNESS_DREAMING, eventTime, uid, /* reason= */0, 244 /* opUid= */ 0, /* opPackageName= */ null, /* details= */ null); 245 } finally { 246 Trace.traceEnd(Trace.TRACE_TAG_POWER); 247 } 248 return true; 249 } 250 dozeLocked(long eventTime, int uid, @PowerManager.GoToSleepReason int reason)251 boolean dozeLocked(long eventTime, int uid, @PowerManager.GoToSleepReason int reason) { 252 if (eventTime < getLastWakeTimeLocked() || !isInteractive(mWakefulness)) { 253 return false; 254 } 255 256 Trace.traceBegin(Trace.TRACE_TAG_POWER, "powerOffDisplay"); 257 try { 258 reason = Math.min(PowerManager.GO_TO_SLEEP_REASON_MAX, 259 Math.max(reason, PowerManager.GO_TO_SLEEP_REASON_MIN)); 260 long millisSinceLastUserActivity = eventTime - Math.max( 261 mLastUserActivityTimeNoChangeLights, mLastUserActivityTime); 262 Slog.i(TAG, "Powering off display group due to " 263 + PowerManager.sleepReasonToString(reason) 264 + " (groupId= " + getGroupId() + ", uid= " + uid 265 + ", millisSinceLastUserActivity=" + millisSinceLastUserActivity 266 + ", lastUserActivityEvent=" + PowerManager.userActivityEventToString( 267 mLastUserActivityEvent) + ")..."); 268 269 setSandmanSummonedLocked(/* isSandmanSummoned= */ true); 270 setWakefulnessLocked(WAKEFULNESS_DOZING, eventTime, uid, reason, /* opUid= */ 0, 271 /* opPackageName= */ null, /* details= */ null); 272 } finally { 273 Trace.traceEnd(Trace.TRACE_TAG_POWER); 274 } 275 return true; 276 } 277 sleepLocked(long eventTime, int uid, @PowerManager.GoToSleepReason int reason)278 boolean sleepLocked(long eventTime, int uid, @PowerManager.GoToSleepReason int reason) { 279 if (eventTime < mLastWakeTime || getWakefulnessLocked() == WAKEFULNESS_ASLEEP) { 280 return false; 281 } 282 283 Trace.traceBegin(Trace.TRACE_TAG_POWER, "sleepPowerGroup"); 284 try { 285 Slog.i(TAG, 286 "Sleeping power group (groupId=" + getGroupId() + ", uid=" + uid + ", reason=" 287 + PowerManager.sleepReasonToString(reason) + ")..."); 288 setSandmanSummonedLocked(/* isSandmanSummoned= */ true); 289 setWakefulnessLocked(WAKEFULNESS_ASLEEP, eventTime, uid, reason, /* opUid= */0, 290 /* opPackageName= */ null, /* details= */ null); 291 } finally { 292 Trace.traceEnd(Trace.TRACE_TAG_POWER); 293 } 294 return true; 295 } 296 getLastUserActivityTimeLocked()297 long getLastUserActivityTimeLocked() { 298 return mLastUserActivityTime; 299 } 300 setLastUserActivityTimeLocked(long lastUserActivityTime, @PowerManager.UserActivityEvent int event)301 void setLastUserActivityTimeLocked(long lastUserActivityTime, 302 @PowerManager.UserActivityEvent int event) { 303 mLastUserActivityTime = lastUserActivityTime; 304 mLastUserActivityEvent = event; 305 } 306 getLastUserActivityTimeNoChangeLightsLocked()307 public long getLastUserActivityTimeNoChangeLightsLocked() { 308 return mLastUserActivityTimeNoChangeLights; 309 } 310 setLastUserActivityTimeNoChangeLightsLocked(long time, @PowerManager.UserActivityEvent int event)311 public void setLastUserActivityTimeNoChangeLightsLocked(long time, 312 @PowerManager.UserActivityEvent int event) { 313 mLastUserActivityTimeNoChangeLights = time; 314 mLastUserActivityEvent = event; 315 } 316 getUserActivitySummaryLocked()317 public int getUserActivitySummaryLocked() { 318 return mUserActivitySummary; 319 } 320 isPolicyBrightLocked()321 public boolean isPolicyBrightLocked() { 322 return mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT; 323 } 324 isPolicyDimLocked()325 public boolean isPolicyDimLocked() { 326 return mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DIM; 327 } 328 isPolicyVrLocked()329 public boolean isPolicyVrLocked() { 330 return mDisplayPowerRequest.isVr(); 331 332 } 333 isBrightOrDimLocked()334 public boolean isBrightOrDimLocked() { 335 return mDisplayPowerRequest.isBrightOrDim(); 336 } 337 setUserActivitySummaryLocked(int summary)338 public void setUserActivitySummaryLocked(int summary) { 339 mUserActivitySummary = summary; 340 } 341 getWakeLockSummaryLocked()342 public int getWakeLockSummaryLocked() { 343 return mWakeLockSummary; 344 } 345 346 /** 347 * Query whether a wake lock is at least partially responsible for keeping the device awake. 348 * 349 * This does not necessarily mean the wake lock is the sole reason the device is awake; there 350 * could also be user activity keeping the device awake, for example. It just means a wake lock 351 * is being held that would keep the device awake even if nothing else was. 352 * 353 * @return whether the PowerGroup is being kept awake at least in part because a wake lock is 354 * being held. 355 */ hasWakeLockKeepingScreenOnLocked()356 public boolean hasWakeLockKeepingScreenOnLocked() { 357 final int screenOnWakeLockMask = 358 WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM | WAKE_LOCK_STAY_AWAKE; 359 return (mWakeLockSummary & (screenOnWakeLockMask)) != 0; 360 } 361 setWakeLockSummaryLocked(int summary)362 public void setWakeLockSummaryLocked(int summary) { 363 mWakeLockSummary = summary; 364 } 365 366 /** 367 * Whether or not this DisplayGroup supports dreaming. 368 * @return {@code true} if this DisplayGroup supports dreaming; otherwise {@code false}. 369 */ supportsSandmanLocked()370 public boolean supportsSandmanLocked() { 371 return mSupportsSandman; 372 } 373 374 /** 375 * Return true if we must keep a suspend blocker active on behalf of a power group. 376 * We do so if the screen is on or is in transition between states. 377 */ needSuspendBlockerLocked(boolean proximityPositive, boolean suspendWhenScreenOffDueToProximityConfig)378 boolean needSuspendBlockerLocked(boolean proximityPositive, 379 boolean suspendWhenScreenOffDueToProximityConfig) { 380 if (isBrightOrDimLocked()) { 381 // If we asked for the screen to be on but it is off due to the proximity 382 // sensor then we may suspend but only if the configuration allows it. 383 // On some hardware it may not be safe to suspend because the proximity 384 // sensor may not be correctly configured as a wake-up source. 385 if (!mDisplayPowerRequest.useProximitySensor || !proximityPositive 386 || !suspendWhenScreenOffDueToProximityConfig) { 387 return true; 388 } 389 } 390 391 if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE 392 && mDisplayPowerRequest.dozeScreenState == Display.STATE_ON) { 393 // Although we are in DOZE and would normally allow the device to suspend, 394 // the doze service has explicitly requested the display to remain in the ON 395 // state which means we should hold the display suspend blocker. 396 return true; 397 } 398 return false; 399 } 400 401 @VisibleForTesting getDesiredScreenPolicyLocked(boolean quiescent, boolean dozeAfterScreenOff, boolean vrModeEnabled, boolean bootCompleted, boolean screenBrightnessBoostInProgress)402 int getDesiredScreenPolicyLocked(boolean quiescent, boolean dozeAfterScreenOff, 403 boolean vrModeEnabled, boolean bootCompleted, boolean screenBrightnessBoostInProgress) { 404 final int wakefulness = getWakefulnessLocked(); 405 final int wakeLockSummary = getWakeLockSummaryLocked(); 406 if (wakefulness == WAKEFULNESS_ASLEEP || quiescent) { 407 return DisplayPowerRequest.POLICY_OFF; 408 } else if (wakefulness == WAKEFULNESS_DOZING) { 409 if ((wakeLockSummary & WAKE_LOCK_DOZE) != 0) { 410 return DisplayPowerRequest.POLICY_DOZE; 411 } 412 if (dozeAfterScreenOff) { 413 return DisplayPowerRequest.POLICY_OFF; 414 } 415 // Fall through and preserve the current screen policy if not configured to 416 // doze after screen off. This causes the screen off transition to be skipped. 417 } 418 419 // It is important that POLICY_VR check happens after the wakefulness checks above so 420 // that VR-mode does not prevent displays from transitioning to the correct state when 421 // dozing or sleeping. 422 if (vrModeEnabled) { 423 return DisplayPowerRequest.POLICY_VR; 424 } 425 426 if ((wakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0 427 || !bootCompleted 428 || (getUserActivitySummaryLocked() & USER_ACTIVITY_SCREEN_BRIGHT) != 0 429 || screenBrightnessBoostInProgress) { 430 return DisplayPowerRequest.POLICY_BRIGHT; 431 } 432 433 return DisplayPowerRequest.POLICY_DIM; 434 } 435 getPolicyLocked()436 int getPolicyLocked() { 437 return mDisplayPowerRequest.policy; 438 } 439 updateLocked(float screenBrightnessOverride, boolean useProximitySensor, boolean boostScreenBrightness, int dozeScreenState, float dozeScreenBrightness, boolean overrideDrawWakeLock, PowerSaveState powerSaverState, boolean quiescent, boolean dozeAfterScreenOff, boolean vrModeEnabled, boolean bootCompleted, boolean screenBrightnessBoostInProgress, boolean waitForNegativeProximity)440 boolean updateLocked(float screenBrightnessOverride, boolean useProximitySensor, 441 boolean boostScreenBrightness, int dozeScreenState, float dozeScreenBrightness, 442 boolean overrideDrawWakeLock, PowerSaveState powerSaverState, boolean quiescent, 443 boolean dozeAfterScreenOff, boolean vrModeEnabled, boolean bootCompleted, 444 boolean screenBrightnessBoostInProgress, boolean waitForNegativeProximity) { 445 mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked(quiescent, dozeAfterScreenOff, 446 vrModeEnabled, bootCompleted, screenBrightnessBoostInProgress); 447 mDisplayPowerRequest.screenBrightnessOverride = screenBrightnessOverride; 448 mDisplayPowerRequest.useProximitySensor = useProximitySensor; 449 mDisplayPowerRequest.boostScreenBrightness = boostScreenBrightness; 450 451 if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) { 452 mDisplayPowerRequest.dozeScreenState = dozeScreenState; 453 if ((getWakeLockSummaryLocked() & WAKE_LOCK_DRAW) != 0 && !overrideDrawWakeLock) { 454 if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) { 455 mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE; 456 } 457 if (mDisplayPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND) { 458 mDisplayPowerRequest.dozeScreenState = Display.STATE_ON; 459 } 460 } 461 mDisplayPowerRequest.dozeScreenBrightness = dozeScreenBrightness; 462 } else { 463 mDisplayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN; 464 mDisplayPowerRequest.dozeScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; 465 } 466 mDisplayPowerRequest.lowPowerMode = powerSaverState.batterySaverEnabled; 467 mDisplayPowerRequest.screenLowPowerBrightnessFactor = powerSaverState.brightnessFactor; 468 boolean ready = mDisplayManagerInternal.requestPowerState(mGroupId, mDisplayPowerRequest, 469 waitForNegativeProximity); 470 mNotifier.onScreenPolicyUpdate(mGroupId, mDisplayPowerRequest.policy); 471 return ready; 472 } 473 474 protected interface PowerGroupListener { 475 /** 476 * Informs the recipient about a wakefulness change of a {@link PowerGroup}. 477 * 478 * @param groupId The PowerGroup's id for which the wakefulness has changed. 479 * @param wakefulness The new wakefulness. 480 * @param eventTime The time of the event. 481 * @param reason The reason, any of {@link android.os.PowerManager.WakeReason} or 482 * {@link android.os.PowerManager.GoToSleepReason}. 483 * @param uid The uid which caused the wakefulness change. 484 * @param opUid The uid used for AppOps. 485 * @param opPackageName The Package name used for AppOps. 486 * @param details Details about the event. 487 */ onWakefulnessChangedLocked(int groupId, int wakefulness, long eventTime, int reason, int uid, int opUid, String opPackageName, String details)488 void onWakefulnessChangedLocked(int groupId, int wakefulness, long eventTime, int reason, 489 int uid, int opUid, String opPackageName, String details); 490 } 491 } 492