1 /* 2 * Copyright (C) 2022 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.display; 18 19 import android.annotation.IntDef; 20 import android.hardware.display.DisplayManagerInternal; 21 import android.util.Slog; 22 23 import com.android.internal.annotations.GuardedBy; 24 import com.android.internal.annotations.VisibleForTesting; 25 import com.android.server.display.utils.DebugUtils; 26 27 import java.io.PrintWriter; 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 31 /** 32 * A utility class to acquire/release suspend blockers and manage appropriate states around it. 33 * It is also a channel to asynchronously update the PowerManagerService about the changes in the 34 * display states as needed. 35 */ 36 public final class WakelockController { 37 public static final int WAKE_LOCK_PROXIMITY_POSITIVE = 1; 38 public static final int WAKE_LOCK_PROXIMITY_NEGATIVE = 2; 39 public static final int WAKE_LOCK_PROXIMITY_DEBOUNCE = 3; 40 public static final int WAKE_LOCK_STATE_CHANGED = 4; 41 public static final int WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE = 5; 42 public static final int WAKE_LOCK_UNFINISHED_BUSINESS = 6; 43 44 @VisibleForTesting 45 static final int WAKE_LOCK_MAX = WAKE_LOCK_UNFINISHED_BUSINESS; 46 47 private static final String TAG = "WakelockController"; 48 49 // To enable these logs, run: 50 // 'adb shell setprop persist.log.tag.WakelockController DEBUG && adb reboot' 51 private static final boolean DEBUG = DebugUtils.isDebuggable(TAG); 52 53 @IntDef(flag = true, prefix = "WAKE_LOCK_", value = { 54 WAKE_LOCK_PROXIMITY_POSITIVE, 55 WAKE_LOCK_PROXIMITY_NEGATIVE, 56 WAKE_LOCK_PROXIMITY_DEBOUNCE, 57 WAKE_LOCK_STATE_CHANGED, 58 WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE, 59 WAKE_LOCK_UNFINISHED_BUSINESS 60 }) 61 @Retention(RetentionPolicy.SOURCE) 62 public @interface WAKE_LOCK_TYPE { 63 } 64 65 private final Object mLock = new Object(); 66 67 // Asynchronous callbacks into the power manager service. 68 // Only invoked from the handler thread while no locks are held. 69 private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks; 70 71 // Identifiers for suspend blocker acquisition requests 72 private final String mSuspendBlockerIdUnfinishedBusiness; 73 @GuardedBy("mLock") 74 private final String mSuspendBlockerOverrideDozeScreenState; 75 private final String mSuspendBlockerIdOnStateChanged; 76 private final String mSuspendBlockerIdProxPositive; 77 private final String mSuspendBlockerIdProxNegative; 78 private final String mSuspendBlockerIdProxDebounce; 79 80 // True if we have unfinished business and are holding a suspend-blocker. 81 private boolean mUnfinishedBusiness; 82 83 // True if we have are holding a suspend-blocker to override the doze screen state. 84 @GuardedBy("mLock") 85 private boolean mIsOverrideDozeScreenStateAcquired; 86 87 // True if we have have debounced the proximity change impact and are holding a suspend-blocker. 88 private boolean mHasProximityDebounced; 89 90 // The ID of the LogicalDisplay tied to this. 91 private final int mDisplayId; 92 private final String mTag; 93 94 // When true, it implies a wakelock is being held to guarantee the update happens before we 95 // collapse into suspend and so needs to be cleaned up if the thread is exiting. 96 // Should only be accessed on the Handler thread of the class managing the Display states 97 // (i.e. DisplayPowerController2). 98 private boolean mOnStateChangedPending; 99 100 // When true, it implies that a positive proximity wakelock is currently held. Used to keep 101 // track if suspend blocker acquisitions is pending when shutting down the 102 // DisplayPowerController2. Should only be accessed on the Handler thread of the class 103 // managing the Display states (i.e. DisplayPowerController2). 104 private boolean mIsProximityPositiveAcquired; 105 106 // When true, it implies that a negative proximity wakelock is currently held. Used to keep 107 // track if suspend blocker acquisitions is pending when shutting down the 108 // DisplayPowerController2. Should only be accessed on the Handler thread of the class 109 // managing the Display states (i.e. DisplayPowerController2). 110 private boolean mIsProximityNegativeAcquired; 111 112 /** 113 * The constructor of WakelockController. Manages the initialization of all the local entities 114 * needed for its appropriate functioning. 115 */ WakelockController(int displayId, DisplayManagerInternal.DisplayPowerCallbacks callbacks)116 public WakelockController(int displayId, 117 DisplayManagerInternal.DisplayPowerCallbacks callbacks) { 118 mDisplayId = displayId; 119 mTag = TAG + "[" + mDisplayId + "]"; 120 mDisplayPowerCallbacks = callbacks; 121 mSuspendBlockerIdUnfinishedBusiness = "[" + displayId + "]unfinished business"; 122 mSuspendBlockerOverrideDozeScreenState = "[" + displayId + "]override doze screen state"; 123 mSuspendBlockerIdOnStateChanged = "[" + displayId + "]on state changed"; 124 mSuspendBlockerIdProxPositive = "[" + displayId + "]prox positive"; 125 mSuspendBlockerIdProxNegative = "[" + displayId + "]prox negative"; 126 mSuspendBlockerIdProxDebounce = "[" + displayId + "]prox debounce"; 127 } 128 129 /** 130 * A utility to acquire a wakelock 131 * 132 * @param wakelock The type of Wakelock to be acquired 133 * @return True of the wakelock is successfully acquired. False if it is already acquired 134 */ acquireWakelock(@AKE_LOCK_TYPE int wakelock)135 public boolean acquireWakelock(@WAKE_LOCK_TYPE int wakelock) { 136 return acquireWakelockInternal(wakelock); 137 } 138 139 /** 140 * A utility to release a wakelock 141 * 142 * @param wakelock The type of Wakelock to be released 143 * @return True of an acquired wakelock is successfully released. False if it is already 144 * acquired 145 */ releaseWakelock(@AKE_LOCK_TYPE int wakelock)146 public boolean releaseWakelock(@WAKE_LOCK_TYPE int wakelock) { 147 return releaseWakelockInternal(wakelock); 148 } 149 150 /** 151 * A utility to release all the wakelock acquired by the system 152 */ releaseAll()153 public void releaseAll() { 154 for (int i = WAKE_LOCK_PROXIMITY_POSITIVE; i <= WAKE_LOCK_MAX; i++) { 155 releaseWakelockInternal(i); 156 } 157 } 158 acquireWakelockInternal(@AKE_LOCK_TYPE int wakelock)159 private boolean acquireWakelockInternal(@WAKE_LOCK_TYPE int wakelock) { 160 switch (wakelock) { 161 case WAKE_LOCK_PROXIMITY_POSITIVE: 162 return acquireProxPositiveSuspendBlocker(); 163 case WAKE_LOCK_PROXIMITY_NEGATIVE: 164 return acquireProxNegativeSuspendBlocker(); 165 case WAKE_LOCK_PROXIMITY_DEBOUNCE: 166 return acquireProxDebounceSuspendBlocker(); 167 case WAKE_LOCK_STATE_CHANGED: 168 return acquireStateChangedSuspendBlocker(); 169 case WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE: 170 synchronized (mLock) { 171 return acquireOverrideDozeScreenStateSuspendBlockerLocked(); 172 } 173 case WAKE_LOCK_UNFINISHED_BUSINESS: 174 return acquireUnfinishedBusinessSuspendBlocker(); 175 default: 176 throw new RuntimeException("Invalid wakelock attempted to be acquired"); 177 } 178 } 179 releaseWakelockInternal(@AKE_LOCK_TYPE int wakelock)180 private boolean releaseWakelockInternal(@WAKE_LOCK_TYPE int wakelock) { 181 switch (wakelock) { 182 case WAKE_LOCK_PROXIMITY_POSITIVE: 183 return releaseProxPositiveSuspendBlocker(); 184 case WAKE_LOCK_PROXIMITY_NEGATIVE: 185 return releaseProxNegativeSuspendBlocker(); 186 case WAKE_LOCK_PROXIMITY_DEBOUNCE: 187 return releaseProxDebounceSuspendBlocker(); 188 case WAKE_LOCK_STATE_CHANGED: 189 return releaseStateChangedSuspendBlocker(); 190 case WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE: 191 synchronized (mLock) { 192 return releaseOverrideDozeScreenStateSuspendBlockerLocked(); 193 } 194 case WAKE_LOCK_UNFINISHED_BUSINESS: 195 return releaseUnfinishedBusinessSuspendBlocker(); 196 default: 197 throw new RuntimeException("Invalid wakelock attempted to be released"); 198 } 199 } 200 201 /** 202 * Acquires the proximity positive wakelock and notifies the PowerManagerService about the 203 * changes. 204 */ acquireProxPositiveSuspendBlocker()205 private boolean acquireProxPositiveSuspendBlocker() { 206 if (!mIsProximityPositiveAcquired) { 207 mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxPositive); 208 mIsProximityPositiveAcquired = true; 209 return true; 210 } 211 return false; 212 } 213 214 /** 215 * Acquires the state change wakelock and notifies the PowerManagerService about the changes. 216 */ acquireStateChangedSuspendBlocker()217 private boolean acquireStateChangedSuspendBlocker() { 218 // Grab a wake lock if we have change of the display state 219 if (!mOnStateChangedPending) { 220 if (DEBUG) { 221 Slog.d(mTag, "State Changed..."); 222 } 223 mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdOnStateChanged); 224 mOnStateChangedPending = true; 225 return true; 226 } 227 return false; 228 } 229 230 /** 231 * Releases the state change wakelock and notifies the PowerManagerService about the changes. 232 */ releaseStateChangedSuspendBlocker()233 private boolean releaseStateChangedSuspendBlocker() { 234 if (mOnStateChangedPending) { 235 mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdOnStateChanged); 236 mOnStateChangedPending = false; 237 return true; 238 } 239 return false; 240 } 241 242 /** 243 * Acquires the suspend blocker to override the doze screen state and notifies the 244 * PowerManagerService about the changes. Note that this utility is syncronized because a 245 * request to override the doze screen state can come from a non-power thread. 246 */ 247 @GuardedBy("mLock") acquireOverrideDozeScreenStateSuspendBlockerLocked()248 private boolean acquireOverrideDozeScreenStateSuspendBlockerLocked() { 249 // Grab a wake lock if we have unfinished business. 250 if (!mIsOverrideDozeScreenStateAcquired) { 251 if (DEBUG) { 252 Slog.d(mTag, "Acquiring suspend blocker to override the doze screen state..."); 253 } 254 mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerOverrideDozeScreenState); 255 mIsOverrideDozeScreenStateAcquired = true; 256 return true; 257 } 258 return false; 259 } 260 261 /** 262 * Releases the override doze screen state suspend blocker and notifies the PowerManagerService 263 * about the changes. 264 */ 265 @GuardedBy("mLock") releaseOverrideDozeScreenStateSuspendBlockerLocked()266 private boolean releaseOverrideDozeScreenStateSuspendBlockerLocked() { 267 if (mIsOverrideDozeScreenStateAcquired) { 268 if (DEBUG) { 269 Slog.d(mTag, "Finished overriding doze screen state..."); 270 } 271 mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerOverrideDozeScreenState); 272 mIsOverrideDozeScreenStateAcquired = false; 273 return true; 274 } 275 return false; 276 } 277 278 /** 279 * Acquires the unfinished business wakelock and notifies the PowerManagerService about the 280 * changes. 281 */ acquireUnfinishedBusinessSuspendBlocker()282 private boolean acquireUnfinishedBusinessSuspendBlocker() { 283 // Grab a wake lock if we have unfinished business. 284 if (!mUnfinishedBusiness) { 285 if (DEBUG) { 286 Slog.d(mTag, "Unfinished business..."); 287 } 288 mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdUnfinishedBusiness); 289 mUnfinishedBusiness = true; 290 return true; 291 } 292 return false; 293 } 294 295 /** 296 * Releases the unfinished business wakelock and notifies the PowerManagerService about the 297 * changes. 298 */ releaseUnfinishedBusinessSuspendBlocker()299 private boolean releaseUnfinishedBusinessSuspendBlocker() { 300 if (mUnfinishedBusiness) { 301 if (DEBUG) { 302 Slog.d(mTag, "Finished business..."); 303 } 304 mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdUnfinishedBusiness); 305 mUnfinishedBusiness = false; 306 return true; 307 } 308 return false; 309 } 310 311 /** 312 * Releases the proximity positive wakelock and notifies the PowerManagerService about the 313 * changes. 314 */ releaseProxPositiveSuspendBlocker()315 private boolean releaseProxPositiveSuspendBlocker() { 316 if (mIsProximityPositiveAcquired) { 317 mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxPositive); 318 mIsProximityPositiveAcquired = false; 319 return true; 320 } 321 return false; 322 } 323 324 /** 325 * Acquires the proximity negative wakelock and notifies the PowerManagerService about the 326 * changes. 327 */ acquireProxNegativeSuspendBlocker()328 private boolean acquireProxNegativeSuspendBlocker() { 329 if (!mIsProximityNegativeAcquired) { 330 mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxNegative); 331 mIsProximityNegativeAcquired = true; 332 return true; 333 } 334 return false; 335 } 336 337 /** 338 * Releases the proximity negative wakelock and notifies the PowerManagerService about the 339 * changes. 340 */ releaseProxNegativeSuspendBlocker()341 private boolean releaseProxNegativeSuspendBlocker() { 342 if (mIsProximityNegativeAcquired) { 343 mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxNegative); 344 mIsProximityNegativeAcquired = false; 345 return true; 346 } 347 return false; 348 } 349 350 /** 351 * Acquires the proximity debounce wakelock and notifies the PowerManagerService about the 352 * changes. 353 */ acquireProxDebounceSuspendBlocker()354 private boolean acquireProxDebounceSuspendBlocker() { 355 if (!mHasProximityDebounced) { 356 mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxDebounce); 357 mHasProximityDebounced = true; 358 return true; 359 } 360 return false; 361 } 362 363 /** 364 * Releases the proximity debounce wakelock and notifies the PowerManagerService about the 365 * changes. 366 */ releaseProxDebounceSuspendBlocker()367 private boolean releaseProxDebounceSuspendBlocker() { 368 if (mHasProximityDebounced) { 369 mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxDebounce); 370 mHasProximityDebounced = false; 371 return true; 372 } 373 return false; 374 } 375 376 /** 377 * Gets the Runnable to be executed when the proximity becomes positive. 378 */ getOnProximityPositiveRunnable()379 public Runnable getOnProximityPositiveRunnable() { 380 return () -> { 381 if (mIsProximityPositiveAcquired) { 382 mIsProximityPositiveAcquired = false; 383 mDisplayPowerCallbacks.onProximityPositive(); 384 mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxPositive); 385 } 386 }; 387 } 388 389 /** 390 * Gets the Runnable to be executed when the display state changes 391 */ 392 public Runnable getOnStateChangedRunnable() { 393 return () -> { 394 if (mOnStateChangedPending) { 395 mOnStateChangedPending = false; 396 mDisplayPowerCallbacks.onStateChanged(); 397 mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdOnStateChanged); 398 } 399 }; 400 } 401 402 /** 403 * Gets the Runnable to be executed when the proximity becomes negative. 404 */ 405 public Runnable getOnProximityNegativeRunnable() { 406 return () -> { 407 if (mIsProximityNegativeAcquired) { 408 mIsProximityNegativeAcquired = false; 409 mDisplayPowerCallbacks.onProximityNegative(); 410 mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxNegative); 411 } 412 }; 413 } 414 415 /** 416 * Dumps the current state of this 417 */ 418 public void dumpLocal(PrintWriter pw) { 419 pw.println("WakelockController State:"); 420 pw.println("-------------------------"); 421 pw.println(" mDisplayId=" + mDisplayId); 422 pw.println(" mUnfinishedBusiness=" + hasUnfinishedBusiness()); 423 pw.println(" mOnStateChangePending=" + isOnStateChangedPending()); 424 pw.println(" mOnProximityPositiveMessages=" + isProximityPositiveAcquired()); 425 pw.println(" mOnProximityNegativeMessages=" + isProximityNegativeAcquired()); 426 pw.println(" mIsOverrideDozeScreenStateAcquired=" + isOverrideDozeScreenStateAcquired()); 427 } 428 429 @VisibleForTesting 430 String getSuspendBlockerUnfinishedBusinessId() { 431 return mSuspendBlockerIdUnfinishedBusiness; 432 } 433 434 @VisibleForTesting 435 String getSuspendBlockerOnStateChangedId() { 436 return mSuspendBlockerIdOnStateChanged; 437 } 438 439 @VisibleForTesting 440 String getSuspendBlockerProxPositiveId() { 441 return mSuspendBlockerIdProxPositive; 442 } 443 444 @VisibleForTesting 445 String getSuspendBlockerProxNegativeId() { 446 return mSuspendBlockerIdProxNegative; 447 } 448 449 @VisibleForTesting 450 String getSuspendBlockerProxDebounceId() { 451 return mSuspendBlockerIdProxDebounce; 452 } 453 454 @VisibleForTesting 455 String getSuspendBlockerOverrideDozeScreenState() { 456 synchronized (mLock) { 457 return mSuspendBlockerOverrideDozeScreenState; 458 } 459 } 460 461 @VisibleForTesting 462 boolean hasUnfinishedBusiness() { 463 return mUnfinishedBusiness; 464 } 465 466 @VisibleForTesting 467 boolean isOnStateChangedPending() { 468 return mOnStateChangedPending; 469 } 470 471 @VisibleForTesting 472 boolean isProximityPositiveAcquired() { 473 return mIsProximityPositiveAcquired; 474 } 475 476 @VisibleForTesting 477 boolean isProximityNegativeAcquired() { 478 return mIsProximityNegativeAcquired; 479 } 480 481 @VisibleForTesting 482 boolean hasProximitySensorDebounced() { 483 return mHasProximityDebounced; 484 } 485 486 @VisibleForTesting 487 boolean isOverrideDozeScreenStateAcquired() { 488 synchronized (mLock) { 489 return mIsOverrideDozeScreenStateAcquired; 490 } 491 } 492 } 493