From 4d9ded03693011fbe23dc6caee97925258992f9b Mon Sep 17 00:00:00 2001 From: Antony Sargent Date: Tue, 25 Jan 2022 23:53:57 -0800 Subject: [PATCH] Lock default display when it sleeps independent of global wakefulness When dealing with multiple PowerGroups, we calculate the global wakefulness as the highest of any individual group. In the case where a non-default PowerGroup (e.g. for a VirtualDisplay) is awake and the default PowerGroup transitions from awake to asleep, we need to let the PhoneWindowManager know so it can tell Keyguard to lock the default display. Fixes: 208229988 Test: atest PowerManagerServiceTest Change-Id: Ib0fc4fdc30ca6f111e3c9d428a45bab5d403ad15 --- .../server/policy/PhoneWindowManager.java | 12 +++ .../server/policy/WindowManagerPolicy.java | 14 +++ .../com/android/server/power/Notifier.java | 9 ++ .../server/power/PowerManagerService.java | 2 + .../server/power/PowerManagerServiceTest.java | 93 +++++++++++++++++++ .../server/wm/TestWindowManagerPolicy.java | 5 + 6 files changed, 135 insertions(+) diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 999428a5f35b3..b142141898331 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -4524,6 +4524,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { mCameraGestureTriggered = false; } + // Called on the PowerManager's Notifier thread. + @Override + public void onPowerGroupWakefulnessChanged(int groupId, int wakefulness, + @PowerManager.GoToSleepReason int pmSleepReason, int globalWakefulness) { + if (wakefulness != globalWakefulness + && wakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE + && groupId == Display.DEFAULT_DISPLAY_GROUP + && mKeyguardDelegate != null) { + mKeyguardDelegate.doKeyguardTimeout(null); + } + } + // Called on the PowerManager's Notifier thread. @Override public void startedWakingUp(@PowerManager.WakeReason int pmWakeReason) { diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 4571cf3952870..7ca09ab5154f4 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -772,6 +772,20 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { */ public void finishedGoingToSleep(@PowerManager.GoToSleepReason int pmSleepReason); + /** + * Called when a particular PowerGroup has changed wakefulness. + * + * @param groupId The id of the PowerGroup. + * @param wakefulness One of PowerManagerInternal.WAKEFULNESS_* indicating the wake state for + * the group + * @param pmSleepReason One of PowerManager.GO_TO_SLEEP_REASON_*, detailing the reason this + * group is going to sleep. + * @param globalWakefulness The global wakefulness, which may or may not match that of this + * group. One of PowerManagerInternal.WAKEFULNESS_* + */ + void onPowerGroupWakefulnessChanged(int groupId, int wakefulness, + @PowerManager.GoToSleepReason int pmSleepReason, int globalWakefulness); + /** * Called when the display is about to turn on to show content. * When waking up, this method will be called once after the call to wakingUp(). diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 77d63100032ce..aede4b1e2f5d2 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -552,6 +552,15 @@ public class Notifier { } } + /** + * Called when an individual PowerGroup changes wakefulness. + */ + public void onPowerGroupWakefulnessChanged(int groupId, int groupWakefulness, int changeReason, + int globalWakefulness) { + mHandler.post(() -> mPolicy.onPowerGroupWakefulnessChanged(groupId, groupWakefulness, + changeReason, globalWakefulness)); + } + /** * Called when there has been user activity. */ diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index c04d6082877ae..57f13829b557e 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -674,6 +674,8 @@ public final class PowerManagerService extends SystemService } mDirty |= DIRTY_DISPLAY_GROUP_WAKEFULNESS; updateGlobalWakefulnessLocked(eventTime, reason, uid, opUid, opPackageName, details); + mNotifier.onPowerGroupWakefulnessChanged(groupId, wakefulness, reason, + getGlobalWakefulnessLocked()); updatePowerStateLocked(); } } diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java index 89450ffbc11d3..9f5e79db84c89 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -1696,6 +1696,99 @@ public class PowerManagerServiceTest { assertThat(mService.getLocalServiceInstance().getLastWakeup()).isEqualTo(initialWakeData); } + @Test + public void testMultiDisplay_onlyOneDisplaySleeps_onWakefulnessChangedEventFires() { + createService(); + startSystem(); + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); + forceSleep(); + assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo( + WAKEFULNESS_ASLEEP); + + verify(mNotifierMock).onPowerGroupWakefulnessChanged(eq(Display.DEFAULT_DISPLAY_GROUP), + eq(WAKEFULNESS_ASLEEP), anyInt(), eq(WAKEFULNESS_ASLEEP)); + } + + @Test + public void testMultiDisplay_bothDisplaysSleep_onWakefulnessChangedEventFiresCorrectly() { + final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1; + final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1; + final AtomicReference listener = + new AtomicReference<>(); + doAnswer((Answer) invocation -> { + listener.set(invocation.getArgument(0)); + return null; + }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any()); + final DisplayInfo info = new DisplayInfo(); + info.displayGroupId = nonDefaultDisplayGroupId; + when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info); + + createService(); + startSystem(); + + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); + listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId); + + mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP, 0, 0, 0, 0, + null, null); + mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, 0, 0, 0, 0, + null, null); + + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo( + WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo( + WAKEFULNESS_ASLEEP); + + verify(mNotifierMock).onPowerGroupWakefulnessChanged(eq(nonDefaultDisplayGroupId), + eq(WAKEFULNESS_ASLEEP), anyInt(), eq(WAKEFULNESS_AWAKE)); + verify(mNotifierMock).onPowerGroupWakefulnessChanged(eq(Display.DEFAULT_DISPLAY_GROUP), + eq(WAKEFULNESS_ASLEEP), anyInt(), eq(WAKEFULNESS_ASLEEP)); + } + + @Test + public void testMultiDisplay_separateWakeStates_onWakefulnessChangedEventFiresCorrectly() { + final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1; + final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1; + final AtomicReference listener = + new AtomicReference<>(); + doAnswer((Answer) invocation -> { + listener.set(invocation.getArgument(0)); + return null; + }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any()); + final DisplayInfo info = new DisplayInfo(); + info.displayGroupId = nonDefaultDisplayGroupId; + when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info); + + createService(); + startSystem(); + + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); + listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId); + + final String pkg = mContextSpy.getOpPackageName(); + final Binder token = new Binder(); + final String tag = + "testMultiDisplay_separateWakeStates_onWakefulnessChangedEventFiresCorrectly"; + mService.getBinderServiceInstance().acquireWakeLock(token, + PowerManager.SCREEN_BRIGHT_WAKE_LOCK, tag, pkg, + null /* workSource */, null /* historyTag */, nonDefaultDisplay, null); + + forceSleep(); + + // The wakelock should have kept the second display awake, and we should notify that the + // default display went to sleep. + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); + assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo( + WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo( + WAKEFULNESS_AWAKE); + verify(mNotifierMock).onPowerGroupWakefulnessChanged(eq(Display.DEFAULT_DISPLAY_GROUP), + eq(WAKEFULNESS_ASLEEP), anyInt(), eq(WAKEFULNESS_AWAKE)); + verify(mNotifierMock, never()).onPowerGroupWakefulnessChanged( + eq(nonDefaultDisplayGroupId), anyInt(), anyInt(), anyInt()); + } + @Test public void testGetFullPowerSavePolicy_returnsStateMachineResult() { createService(); diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index f570005f99ccd..ea98b6b17e838 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -130,6 +130,11 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { public void finishedGoingToSleep(@GoToSleepReason int sleepReason) { } + @Override + public void onPowerGroupWakefulnessChanged(int groupId, int wakefulness, + @GoToSleepReason int pmSleepReason, int globalWakefulness) { + } + @Override public void screenTurningOn(int displayId, ScreenOnListener screenOnListener) { }