summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java52
-rw-r--r--services/core/java/com/android/server/display/WakelockController.java73
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java11
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/WakelockControllerTest.java24
4 files changed, 124 insertions, 36 deletions
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 8b21d98045dd..800155d4305e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -790,15 +790,27 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
@Override
public void overrideDozeScreenState(int displayState, @Display.StateReason int reason) {
Slog.i(TAG, "New offload doze override: " + Display.stateToString(displayState));
- mHandler.postAtTime(() -> {
- if (mDisplayOffloadSession == null
- || !(DisplayOffloadSession.isSupportedOffloadState(displayState)
- || displayState == Display.STATE_UNKNOWN)) {
- return;
+ if (mDisplayOffloadSession != null
+ && DisplayOffloadSession.isSupportedOffloadState(displayState)
+ && displayState != Display.STATE_UNKNOWN) {
+ if (mFlags.isOffloadDozeOverrideHoldsWakelockEnabled()) {
+ boolean acquired = mWakelockController.acquireWakelock(
+ WakelockController.WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE);
+ if (!acquired) {
+ Slog.i(TAG, "A request to override the doze screen state is already "
+ + "under process");
+ return;
+ }
}
- mDisplayStateController.overrideDozeScreenState(displayState, reason);
- updatePowerState();
- }, mClock.uptimeMillis());
+ mHandler.postAtTime(() -> {
+ mDisplayStateController.overrideDozeScreenState(displayState, reason);
+ updatePowerState();
+ if (mFlags.isOffloadDozeOverrideHoldsWakelockEnabled()) {
+ mWakelockController.releaseWakelock(
+ WakelockController.WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE);
+ }
+ }, mClock.uptimeMillis());
+ }
}
@Override
@@ -1325,30 +1337,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
initialize(readyToUpdateDisplayState() ? state : Display.STATE_UNKNOWN);
}
- if (mFlags.isOffloadDozeOverrideHoldsWakelockEnabled()) {
- // Sometimes, a display-state change can come without an associated PowerRequest,
- // as with DisplayOffload. For those cases, we have to make sure to also mark the
- // display as "not ready" so that we can inform power-manager when the state-change is
- // complete.
- if (mPowerState.getScreenState() != state) {
- final boolean wasReady;
- synchronized (mLock) {
- wasReady = mDisplayReadyLocked;
- mDisplayReadyLocked = false;
- mustNotify = true;
- }
-
- if (wasReady) {
- // If we went from ready to not-ready from the state-change (instead of a
- // PowerRequest) there's a good chance that nothing is keeping PowerManager
- // from suspending. Grab the unfinished business suspend blocker to keep the
- // device awake until the display-state change goes into effect.
- mWakelockController.acquireWakelock(
- WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS);
- }
- }
- }
-
// Animate the screen state change unless already animating.
// The transition may be deferred, so after this point we will use the
// actual state instead of the desired one.
diff --git a/services/core/java/com/android/server/display/WakelockController.java b/services/core/java/com/android/server/display/WakelockController.java
index 7bc797125b0e..5b0229cbb393 100644
--- a/services/core/java/com/android/server/display/WakelockController.java
+++ b/services/core/java/com/android/server/display/WakelockController.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.hardware.display.DisplayManagerInternal;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.utils.DebugUtils;
@@ -37,7 +38,8 @@ public final class WakelockController {
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;
+ public static final int WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE = 5;
+ public static final int WAKE_LOCK_UNFINISHED_BUSINESS = 6;
@VisibleForTesting
static final int WAKE_LOCK_MAX = WAKE_LOCK_UNFINISHED_BUSINESS;
@@ -53,18 +55,23 @@ public final class WakelockController {
WAKE_LOCK_PROXIMITY_NEGATIVE,
WAKE_LOCK_PROXIMITY_DEBOUNCE,
WAKE_LOCK_STATE_CHANGED,
+ WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE,
WAKE_LOCK_UNFINISHED_BUSINESS
})
@Retention(RetentionPolicy.SOURCE)
public @interface WAKE_LOCK_TYPE {
}
+ private final Object mLock = new Object();
+
// 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;
+ @GuardedBy("mLock")
+ private final String mSuspendBlockerOverrideDozeScreenState;
private final String mSuspendBlockerIdOnStateChanged;
private final String mSuspendBlockerIdProxPositive;
private final String mSuspendBlockerIdProxNegative;
@@ -73,6 +80,10 @@ public final class WakelockController {
// True if we have unfinished business and are holding a suspend-blocker.
private boolean mUnfinishedBusiness;
+ // True if we have are holding a suspend-blocker to override the doze screen state.
+ @GuardedBy("mLock")
+ private boolean mIsOverrideDozeScreenStateAcquired;
+
// True if we have have debounced the proximity change impact and are holding a suspend-blocker.
private boolean mHasProximityDebounced;
@@ -108,6 +119,7 @@ public final class WakelockController {
mTag = TAG + "[" + mDisplayId + "]";
mDisplayPowerCallbacks = callbacks;
mSuspendBlockerIdUnfinishedBusiness = "[" + displayId + "]unfinished business";
+ mSuspendBlockerOverrideDozeScreenState = "[" + displayId + "]override doze screen state";
mSuspendBlockerIdOnStateChanged = "[" + displayId + "]on state changed";
mSuspendBlockerIdProxPositive = "[" + displayId + "]prox positive";
mSuspendBlockerIdProxNegative = "[" + displayId + "]prox negative";
@@ -154,6 +166,10 @@ public final class WakelockController {
return acquireProxDebounceSuspendBlocker();
case WAKE_LOCK_STATE_CHANGED:
return acquireStateChangedSuspendBlocker();
+ case WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE:
+ synchronized (mLock) {
+ return acquireOverrideDozeScreenStateSuspendBlockerLocked();
+ }
case WAKE_LOCK_UNFINISHED_BUSINESS:
return acquireUnfinishedBusinessSuspendBlocker();
default:
@@ -171,6 +187,10 @@ public final class WakelockController {
return releaseProxDebounceSuspendBlocker();
case WAKE_LOCK_STATE_CHANGED:
return releaseStateChangedSuspendBlocker();
+ case WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE:
+ synchronized (mLock) {
+ return releaseOverrideDozeScreenStateSuspendBlockerLocked();
+ }
case WAKE_LOCK_UNFINISHED_BUSINESS:
return releaseUnfinishedBusinessSuspendBlocker();
default:
@@ -220,6 +240,42 @@ public final class WakelockController {
}
/**
+ * Acquires the suspend blocker to override the doze screen state and notifies the
+ * PowerManagerService about the changes. Note that this utility is syncronized because a
+ * request to override the doze screen state can come from a non-power thread.
+ */
+ @GuardedBy("mLock")
+ private boolean acquireOverrideDozeScreenStateSuspendBlockerLocked() {
+ // Grab a wake lock if we have unfinished business.
+ if (!mIsOverrideDozeScreenStateAcquired) {
+ if (DEBUG) {
+ Slog.d(mTag, "Acquiring suspend blocker to override the doze screen state...");
+ }
+ mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerOverrideDozeScreenState);
+ mIsOverrideDozeScreenStateAcquired = true;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Releases the override doze screen state suspend blocker and notifies the PowerManagerService
+ * about the changes.
+ */
+ @GuardedBy("mLock")
+ private boolean releaseOverrideDozeScreenStateSuspendBlockerLocked() {
+ if (mIsOverrideDozeScreenStateAcquired) {
+ if (DEBUG) {
+ Slog.d(mTag, "Finished overriding doze screen state...");
+ }
+ mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerOverrideDozeScreenState);
+ mIsOverrideDozeScreenStateAcquired = false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Acquires the unfinished business wakelock and notifies the PowerManagerService about the
* changes.
*/
@@ -366,6 +422,7 @@ public final class WakelockController {
pw.println(" mOnStateChangePending=" + isOnStateChangedPending());
pw.println(" mOnProximityPositiveMessages=" + isProximityPositiveAcquired());
pw.println(" mOnProximityNegativeMessages=" + isProximityNegativeAcquired());
+ pw.println(" mIsOverrideDozeScreenStateAcquired=" + isOverrideDozeScreenStateAcquired());
}
@VisibleForTesting
@@ -394,6 +451,13 @@ public final class WakelockController {
}
@VisibleForTesting
+ String getSuspendBlockerOverrideDozeScreenState() {
+ synchronized (mLock) {
+ return mSuspendBlockerOverrideDozeScreenState;
+ }
+ }
+
+ @VisibleForTesting
boolean hasUnfinishedBusiness() {
return mUnfinishedBusiness;
}
@@ -417,4 +481,11 @@ public final class WakelockController {
boolean hasProximitySensorDebounced() {
return mHasProximityDebounced;
}
+
+ @VisibleForTesting
+ boolean isOverrideDozeScreenStateAcquired() {
+ synchronized (mLock) {
+ return mIsOverrideDozeScreenStateAcquired;
+ }
+ }
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index 8ed38a6d0cad..a7c8d314bcc2 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1589,16 +1589,21 @@ public final class DisplayPowerControllerTest {
advanceTime(1); // Run updatePowerState
reset(mHolder.wakelockController);
+ when(mHolder.wakelockController
+ .acquireWakelock(WakelockController.WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE))
+ .thenReturn(true);
mHolder.dpc.overrideDozeScreenState(
supportedTargetState, Display.STATE_REASON_DEFAULT_POLICY);
- advanceTime(1); // Run updatePowerState
// Should get a wakelock to notify powermanager
- verify(mHolder.wakelockController, atLeastOnce()).acquireWakelock(
- eq(WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS));
+ verify(mHolder.wakelockController).acquireWakelock(
+ eq(WakelockController.WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE));
+ advanceTime(1); // Run updatePowerState
verify(mHolder.displayPowerState)
.setScreenState(supportedTargetState, Display.STATE_REASON_DEFAULT_POLICY);
+ verify(mHolder.wakelockController).releaseWakelock(
+ eq(WakelockController.WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE));
}
@Test
diff --git a/services/tests/displayservicetests/src/com/android/server/display/WakelockControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/WakelockControllerTest.java
index c23d4b19cd3a..019b70ef1424 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/WakelockControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/WakelockControllerTest.java
@@ -64,6 +64,8 @@ public final class WakelockControllerTest {
"[" + DISPLAY_ID + "]prox negative");
assertEquals(mWakelockController.getSuspendBlockerProxDebounceId(),
"[" + DISPLAY_ID + "]prox debounce");
+ assertEquals(mWakelockController.getSuspendBlockerOverrideDozeScreenState(),
+ "[" + DISPLAY_ID + "]override doze screen state");
}
@Test
@@ -162,6 +164,28 @@ public final class WakelockControllerTest {
}
@Test
+ public void acquireOverrideDozeScreenStateSuspendBlocker() throws Exception {
+ // Acquire the suspend blocker
+ verifyWakelockAcquisitionAndReaquisition(WakelockController
+ .WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE,
+ () -> mWakelockController.isOverrideDozeScreenStateAcquired());
+
+ // Verify acquire happened only once
+ verify(mDisplayPowerCallbacks, times(1))
+ .acquireSuspendBlocker(mWakelockController
+ .getSuspendBlockerOverrideDozeScreenState());
+
+ // Release the suspend blocker
+ verifyWakelockReleaseAndRerelease(WakelockController.WAKE_LOCK_OVERRIDE_DOZE_SCREEN_STATE,
+ () -> mWakelockController.isOverrideDozeScreenStateAcquired());
+
+ // Verify suspend blocker was released only once
+ verify(mDisplayPowerCallbacks, times(1))
+ .releaseSuspendBlocker(mWakelockController
+ .getSuspendBlockerOverrideDozeScreenState());
+ }
+
+ @Test
public void proximityPositiveRunnableWorksAsExpected() {
// Acquire the suspend blocker twice
assertTrue(mWakelockController.acquireWakelock(