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