| /* |
| * Copyright (C) 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server.display; |
| |
| import android.annotation.IntDef; |
| import android.hardware.display.DisplayManagerInternal; |
| import android.util.Slog; |
| |
| import com.android.internal.annotations.VisibleForTesting; |
| |
| import java.io.PrintWriter; |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| |
| /** |
| * A utility class to acquire/release suspend blockers and manage appropriate states around it. |
| * It is also a channel to asynchronously update the PowerManagerService about the changes in the |
| * display states as needed. |
| */ |
| public final class WakelockController { |
| public static final int WAKE_LOCK_PROXIMITY_POSITIVE = 1; |
| public static final int WAKE_LOCK_PROXIMITY_NEGATIVE = 2; |
| public static final int WAKE_LOCK_PROXIMITY_DEBOUNCE = 3; |
| public static final int WAKE_LOCK_STATE_CHANGED = 4; |
| public static final int WAKE_LOCK_UNFINISHED_BUSINESS = 5; |
| |
| @VisibleForTesting |
| static final int WAKE_LOCK_MAX = WAKE_LOCK_UNFINISHED_BUSINESS; |
| |
| private static final boolean DEBUG = false; |
| |
| @IntDef(flag = true, prefix = "WAKE_LOCK_", value = { |
| WAKE_LOCK_PROXIMITY_POSITIVE, |
| WAKE_LOCK_PROXIMITY_NEGATIVE, |
| WAKE_LOCK_PROXIMITY_DEBOUNCE, |
| WAKE_LOCK_STATE_CHANGED, |
| WAKE_LOCK_UNFINISHED_BUSINESS |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface WAKE_LOCK_TYPE { |
| } |
| |
| // Asynchronous callbacks into the power manager service. |
| // Only invoked from the handler thread while no locks are held. |
| private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks; |
| |
| // Identifiers for suspend blocker acquisition requests |
| private final String mSuspendBlockerIdUnfinishedBusiness; |
| private final String mSuspendBlockerIdOnStateChanged; |
| private final String mSuspendBlockerIdProxPositive; |
| private final String mSuspendBlockerIdProxNegative; |
| private final String mSuspendBlockerIdProxDebounce; |
| |
| // True if we have unfinished business and are holding a suspend-blocker. |
| private boolean mUnfinishedBusiness; |
| |
| // True if we have have debounced the proximity change impact and are holding a suspend-blocker. |
| private boolean mHasProximityDebounced; |
| |
| // The ID of the LogicalDisplay tied to this. |
| private final int mDisplayId; |
| private final String mTag; |
| |
| // When true, it implies a wakelock is being held to guarantee the update happens before we |
| // collapse into suspend and so needs to be cleaned up if the thread is exiting. |
| // Should only be accessed on the Handler thread of the class managing the Display states |
| // (i.e. DisplayPowerController2). |
| private boolean mOnStateChangedPending; |
| |
| // When true, it implies that a positive proximity wakelock is currently held. Used to keep |
| // track if suspend blocker acquisitions is pending when shutting down the |
| // DisplayPowerController2. Should only be accessed on the Handler thread of the class |
| // managing the Display states (i.e. DisplayPowerController2). |
| private boolean mIsProximityPositiveAcquired; |
| |
| // When true, it implies that a negative proximity wakelock is currently held. Used to keep |
| // track if suspend blocker acquisitions is pending when shutting down the |
| // DisplayPowerController2. Should only be accessed on the Handler thread of the class |
| // managing the Display states (i.e. DisplayPowerController2). |
| private boolean mIsProximityNegativeAcquired; |
| |
| /** |
| * The constructor of WakelockController. Manages the initialization of all the local entities |
| * needed for its appropriate functioning. |
| */ |
| public WakelockController(int displayId, |
| DisplayManagerInternal.DisplayPowerCallbacks callbacks) { |
| mDisplayId = displayId; |
| mTag = "WakelockController[" + mDisplayId + "]"; |
| mDisplayPowerCallbacks = callbacks; |
| mSuspendBlockerIdUnfinishedBusiness = "[" + displayId + "]unfinished business"; |
| mSuspendBlockerIdOnStateChanged = "[" + displayId + "]on state changed"; |
| mSuspendBlockerIdProxPositive = "[" + displayId + "]prox positive"; |
| mSuspendBlockerIdProxNegative = "[" + displayId + "]prox negative"; |
| mSuspendBlockerIdProxDebounce = "[" + displayId + "]prox debounce"; |
| } |
| |
| /** |
| * A utility to acquire a wakelock |
| * |
| * @param wakelock The type of Wakelock to be acquired |
| * @return True of the wakelock is successfully acquired. False if it is already acquired |
| */ |
| public boolean acquireWakelock(@WAKE_LOCK_TYPE int wakelock) { |
| return acquireWakelockInternal(wakelock); |
| } |
| |
| /** |
| * A utility to release a wakelock |
| * |
| * @param wakelock The type of Wakelock to be released |
| * @return True of an acquired wakelock is successfully released. False if it is already |
| * acquired |
| */ |
| public boolean releaseWakelock(@WAKE_LOCK_TYPE int wakelock) { |
| return releaseWakelockInternal(wakelock); |
| } |
| |
| /** |
| * A utility to release all the wakelock acquired by the system |
| */ |
| public void releaseAll() { |
| for (int i = WAKE_LOCK_PROXIMITY_POSITIVE; i <= WAKE_LOCK_MAX; i++) { |
| releaseWakelockInternal(i); |
| } |
| } |
| |
| private boolean acquireWakelockInternal(@WAKE_LOCK_TYPE int wakelock) { |
| switch (wakelock) { |
| case WAKE_LOCK_PROXIMITY_POSITIVE: |
| return acquireProxPositiveSuspendBlocker(); |
| case WAKE_LOCK_PROXIMITY_NEGATIVE: |
| return acquireProxNegativeSuspendBlocker(); |
| case WAKE_LOCK_PROXIMITY_DEBOUNCE: |
| return acquireProxDebounceSuspendBlocker(); |
| case WAKE_LOCK_STATE_CHANGED: |
| return acquireStateChangedSuspendBlocker(); |
| case WAKE_LOCK_UNFINISHED_BUSINESS: |
| return acquireUnfinishedBusinessSuspendBlocker(); |
| default: |
| throw new RuntimeException("Invalid wakelock attempted to be acquired"); |
| } |
| } |
| |
| private boolean releaseWakelockInternal(@WAKE_LOCK_TYPE int wakelock) { |
| switch (wakelock) { |
| case WAKE_LOCK_PROXIMITY_POSITIVE: |
| return releaseProxPositiveSuspendBlocker(); |
| case WAKE_LOCK_PROXIMITY_NEGATIVE: |
| return releaseProxNegativeSuspendBlocker(); |
| case WAKE_LOCK_PROXIMITY_DEBOUNCE: |
| return releaseProxDebounceSuspendBlocker(); |
| case WAKE_LOCK_STATE_CHANGED: |
| return releaseStateChangedSuspendBlocker(); |
| case WAKE_LOCK_UNFINISHED_BUSINESS: |
| return releaseUnfinishedBusinessSuspendBlocker(); |
| default: |
| throw new RuntimeException("Invalid wakelock attempted to be released"); |
| } |
| } |
| |
| /** |
| * Acquires the proximity positive wakelock and notifies the PowerManagerService about the |
| * changes. |
| */ |
| private boolean acquireProxPositiveSuspendBlocker() { |
| if (!mIsProximityPositiveAcquired) { |
| mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxPositive); |
| mIsProximityPositiveAcquired = true; |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Acquires the state change wakelock and notifies the PowerManagerService about the changes. |
| */ |
| private boolean acquireStateChangedSuspendBlocker() { |
| // Grab a wake lock if we have change of the display state |
| if (!mOnStateChangedPending) { |
| if (DEBUG) { |
| Slog.d(mTag, "State Changed..."); |
| } |
| mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdOnStateChanged); |
| mOnStateChangedPending = true; |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Releases the state change wakelock and notifies the PowerManagerService about the changes. |
| */ |
| private boolean releaseStateChangedSuspendBlocker() { |
| if (mOnStateChangedPending) { |
| mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdOnStateChanged); |
| mOnStateChangedPending = false; |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Acquires the unfinished business wakelock and notifies the PowerManagerService about the |
| * changes. |
| */ |
| private boolean acquireUnfinishedBusinessSuspendBlocker() { |
| // Grab a wake lock if we have unfinished business. |
| if (!mUnfinishedBusiness) { |
| if (DEBUG) { |
| Slog.d(mTag, "Unfinished business..."); |
| } |
| mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdUnfinishedBusiness); |
| mUnfinishedBusiness = true; |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Releases the unfinished business wakelock and notifies the PowerManagerService about the |
| * changes. |
| */ |
| private boolean releaseUnfinishedBusinessSuspendBlocker() { |
| if (mUnfinishedBusiness) { |
| if (DEBUG) { |
| Slog.d(mTag, "Finished business..."); |
| } |
| mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdUnfinishedBusiness); |
| mUnfinishedBusiness = false; |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Releases the proximity positive wakelock and notifies the PowerManagerService about the |
| * changes. |
| */ |
| private boolean releaseProxPositiveSuspendBlocker() { |
| if (mIsProximityPositiveAcquired) { |
| mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxPositive); |
| mIsProximityPositiveAcquired = false; |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Acquires the proximity negative wakelock and notifies the PowerManagerService about the |
| * changes. |
| */ |
| private boolean acquireProxNegativeSuspendBlocker() { |
| if (!mIsProximityNegativeAcquired) { |
| mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxNegative); |
| mIsProximityNegativeAcquired = true; |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Releases the proximity negative wakelock and notifies the PowerManagerService about the |
| * changes. |
| */ |
| private boolean releaseProxNegativeSuspendBlocker() { |
| if (mIsProximityNegativeAcquired) { |
| mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxNegative); |
| mIsProximityNegativeAcquired = false; |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Acquires the proximity debounce wakelock and notifies the PowerManagerService about the |
| * changes. |
| */ |
| private boolean acquireProxDebounceSuspendBlocker() { |
| if (!mHasProximityDebounced) { |
| mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxDebounce); |
| mHasProximityDebounced = true; |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Releases the proximity debounce wakelock and notifies the PowerManagerService about the |
| * changes. |
| */ |
| private boolean releaseProxDebounceSuspendBlocker() { |
| if (mHasProximityDebounced) { |
| mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxDebounce); |
| mHasProximityDebounced = false; |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Gets the Runnable to be executed when the proximity becomes positive. |
| */ |
| public Runnable getOnProximityPositiveRunnable() { |
| return () -> { |
| if (mIsProximityPositiveAcquired) { |
| mIsProximityPositiveAcquired = false; |
| mDisplayPowerCallbacks.onProximityPositive(); |
| mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxPositive); |
| } |
| }; |
| } |
| |
| /** |
| * Gets the Runnable to be executed when the display state changes |
| */ |
| public Runnable getOnStateChangedRunnable() { |
| return () -> { |
| if (mOnStateChangedPending) { |
| mOnStateChangedPending = false; |
| mDisplayPowerCallbacks.onStateChanged(); |
| mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdOnStateChanged); |
| } |
| }; |
| } |
| |
| /** |
| * Gets the Runnable to be executed when the proximity becomes negative. |
| */ |
| public Runnable getOnProximityNegativeRunnable() { |
| return () -> { |
| if (mIsProximityNegativeAcquired) { |
| mIsProximityNegativeAcquired = false; |
| mDisplayPowerCallbacks.onProximityNegative(); |
| mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxNegative); |
| } |
| }; |
| } |
| |
| /** |
| * Dumps the current state of this |
| */ |
| public void dumpLocal(PrintWriter pw) { |
| pw.println("WakelockController State:"); |
| pw.println(" mDisplayId=" + mDisplayId); |
| pw.println(" mUnfinishedBusiness=" + hasUnfinishedBusiness()); |
| pw.println(" mOnStateChangePending=" + isOnStateChangedPending()); |
| pw.println(" mOnProximityPositiveMessages=" + isProximityPositiveAcquired()); |
| pw.println(" mOnProximityNegativeMessages=" + isProximityNegativeAcquired()); |
| } |
| |
| @VisibleForTesting |
| String getSuspendBlockerUnfinishedBusinessId() { |
| return mSuspendBlockerIdUnfinishedBusiness; |
| } |
| |
| @VisibleForTesting |
| String getSuspendBlockerOnStateChangedId() { |
| return mSuspendBlockerIdOnStateChanged; |
| } |
| |
| @VisibleForTesting |
| String getSuspendBlockerProxPositiveId() { |
| return mSuspendBlockerIdProxPositive; |
| } |
| |
| @VisibleForTesting |
| String getSuspendBlockerProxNegativeId() { |
| return mSuspendBlockerIdProxNegative; |
| } |
| |
| @VisibleForTesting |
| String getSuspendBlockerProxDebounceId() { |
| return mSuspendBlockerIdProxDebounce; |
| } |
| |
| @VisibleForTesting |
| boolean hasUnfinishedBusiness() { |
| return mUnfinishedBusiness; |
| } |
| |
| @VisibleForTesting |
| boolean isOnStateChangedPending() { |
| return mOnStateChangedPending; |
| } |
| |
| @VisibleForTesting |
| boolean isProximityPositiveAcquired() { |
| return mIsProximityPositiveAcquired; |
| } |
| |
| @VisibleForTesting |
| boolean isProximityNegativeAcquired() { |
| return mIsProximityNegativeAcquired; |
| } |
| |
| @VisibleForTesting |
| boolean hasProximitySensorDebounced() { |
| return mHasProximityDebounced; |
| } |
| } |