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