• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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