From c9424ac5e5b96e6c0d16d5ac79ee372c93a67070 Mon Sep 17 00:00:00 2001
From: Antony Sargent
Date: Wed, 8 Mar 2023 09:13:00 -0800
Subject: Improve PowerGroup event notification
When the default display group is asleep/dozing and some other display
in another group becomes awake, we were sending incorrect and
misleading information from PowerManagerService to
PhoneWindowManager. In particular, we were conflating the "global
wakefulness" with the wakefulness of the default display, which led to
problems like the default display waking up when it shouldn't and
Always On Display ceasing to work.
This CL refactors things to make the distinction more clear between
global wakefulness changes and specific display PowerGroup changes.
Bug: 255688811
Test: atest PowerManagerServiceTest
Change-Id: I809d5fcd8eaa61dc2d07b63a0ae3b5aa924faa1c
---
.../android/server/policy/PhoneWindowManager.java | 85 +++++++----
.../android/server/policy/WindowManagerPolicy.java | 84 ++++++++---
.../java/com/android/server/power/Notifier.java | 165 ++++++++++++++++-----
.../android/server/power/PowerManagerService.java | 23 ++-
.../server/power/PowerManagerServiceTest.java | 95 +++++++++---
.../server/policy/TestPhoneWindowManager.java | 4 +-
.../android/server/wm/TestWindowManagerPolicy.java | 23 ++-
7 files changed, 342 insertions(+), 137 deletions(-)
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 247a5c02452e..375f53be43b5 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1004,7 +1004,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return;
}
- final boolean interactive = Display.isOnState(mDefaultDisplay.getState());
+ final boolean interactive = mDefaultDisplayPolicy.isAwake();
Slog.d(TAG, "powerPress: eventTime=" + eventTime + " interactive=" + interactive
+ " count=" + count + " beganFromNonInteractive=" + beganFromNonInteractive
@@ -2201,8 +2201,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Match current screen state.
if (!mPowerManager.isInteractive()) {
- startedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
- finishedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+ startedGoingToSleep(Display.DEFAULT_DISPLAY_GROUP,
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+ finishedGoingToSleep(Display.DEFAULT_DISPLAY_GROUP,
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
}
mWindowManagerInternal.registerAppTransitionListener(new AppTransitionListener() {
@@ -4095,7 +4097,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// This could prevent some wrong state in multi-displays environment,
// the default display may turned off but interactive is true.
- final boolean isDefaultDisplayOn = Display.isOnState(mDefaultDisplay.getState());
+ final boolean isDefaultDisplayOn = mDefaultDisplayPolicy.isAwake();
final boolean interactiveAndOn = interactive && isDefaultDisplayOn;
if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
handleKeyGesture(event, interactiveAndOn);
@@ -4795,17 +4797,40 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
};
+ @Override
+ public void startedWakingUpGlobal(@WakeReason int reason) {
+
+ }
+
+ @Override
+ public void finishedWakingUpGlobal(@WakeReason int reason) {
+
+ }
+
+ @Override
+ public void startedGoingToSleepGlobal(@PowerManager.GoToSleepReason int reason) {
+ mDeviceGoingToSleep = true;
+ }
+
+ @Override
+ public void finishedGoingToSleepGlobal(@PowerManager.GoToSleepReason int reason) {
+ mDeviceGoingToSleep = false;
+ }
+
// Called on the PowerManager's Notifier thread.
@Override
- public void startedGoingToSleep(@PowerManager.GoToSleepReason int pmSleepReason) {
+ public void startedGoingToSleep(int displayGroupId,
+ @PowerManager.GoToSleepReason int pmSleepReason) {
if (DEBUG_WAKEUP) {
- Slog.i(TAG, "Started going to sleep... (why="
+ Slog.i(TAG, "Started going to sleep... (groupId=" + displayGroupId + " why="
+ WindowManagerPolicyConstants.offReasonToString(
WindowManagerPolicyConstants.translateSleepReasonToOffReason(
pmSleepReason)) + ")");
}
+ if (displayGroupId != Display.DEFAULT_DISPLAY_GROUP) {
+ return;
+ }
- mDeviceGoingToSleep = true;
mRequestedOrSleepingDefaultDisplay = true;
if (mKeyguardDelegate != null) {
@@ -4815,17 +4840,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Called on the PowerManager's Notifier thread.
@Override
- public void finishedGoingToSleep(@PowerManager.GoToSleepReason int pmSleepReason) {
+ public void finishedGoingToSleep(int displayGroupId,
+ @PowerManager.GoToSleepReason int pmSleepReason) {
+ if (displayGroupId != Display.DEFAULT_DISPLAY_GROUP) {
+ return;
+ }
EventLogTags.writeScreenToggled(0);
if (DEBUG_WAKEUP) {
- Slog.i(TAG, "Finished going to sleep... (why="
+ Slog.i(TAG, "Finished going to sleep... (groupId=" + displayGroupId + " why="
+ WindowManagerPolicyConstants.offReasonToString(
WindowManagerPolicyConstants.translateSleepReasonToOffReason(
pmSleepReason)) + ")");
}
MetricsLogger.histogram(mContext, "screen_timeout", mLockScreenTimeout / 1000);
- mDeviceGoingToSleep = false;
mRequestedOrSleepingDefaultDisplay = false;
mDefaultDisplayPolicy.setAwake(false);
@@ -4850,26 +4878,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// 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) {
- EventLogTags.writeScreenToggled(1);
+ public void startedWakingUp(int displayGroupId, @WakeReason int pmWakeReason) {
if (DEBUG_WAKEUP) {
- Slog.i(TAG, "Started waking up... (why="
+ Slog.i(TAG, "Started waking up... (groupId=" + displayGroupId + " why="
+ WindowManagerPolicyConstants.onReasonToString(
- WindowManagerPolicyConstants.translateWakeReasonToOnReason(
- pmWakeReason)) + ")");
+ WindowManagerPolicyConstants.translateWakeReasonToOnReason(
+ pmWakeReason)) + ")");
+ }
+ if (displayGroupId != Display.DEFAULT_DISPLAY_GROUP) {
+ return;
}
+ EventLogTags.writeScreenToggled(1);
+
mDefaultDisplayPolicy.setAwake(true);
@@ -4892,13 +4912,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Called on the PowerManager's Notifier thread.
@Override
- public void finishedWakingUp(@PowerManager.WakeReason int pmWakeReason) {
+ public void finishedWakingUp(int displayGroupId, @WakeReason int pmWakeReason) {
if (DEBUG_WAKEUP) {
- Slog.i(TAG, "Finished waking up... (why="
+ Slog.i(TAG, "Finished waking up... (groupId=" + displayGroupId + " why="
+ WindowManagerPolicyConstants.onReasonToString(
WindowManagerPolicyConstants.translateWakeReasonToOnReason(
pmWakeReason)) + ")");
}
+ if (displayGroupId != Display.DEFAULT_DISPLAY_GROUP) {
+ return;
+ }
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onFinishedWakingUp();
@@ -5378,8 +5401,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
mSideFpsEventHandler.onFingerprintSensorReady();
- startedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
- finishedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
+ startedWakingUp(Display.DEFAULT_DISPLAY_GROUP, PowerManager.WAKE_REASON_UNKNOWN);
+ finishedWakingUp(Display.DEFAULT_DISPLAY_GROUP, PowerManager.WAKE_REASON_UNKNOWN);
int defaultDisplayState = mDisplayManager.getDisplay(DEFAULT_DISPLAY).getState();
boolean defaultDisplayOn = defaultDisplayState == Display.STATE_ON;
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 5d558e9c1e2f..909d0195e0be 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -67,10 +67,12 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.companion.virtual.VirtualDevice;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.hardware.display.VirtualDisplay;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
@@ -761,51 +763,85 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
*/
void setAllowLockscreenWhenOn(int displayId, boolean allow);
+ /**
+ * Called when the global wakefulness is becoming awake.
+ *
+ * @param reason One of PowerManager.WAKE_REASON_*, detailing the reason for the change.
+ */
+ void startedWakingUpGlobal(@PowerManager.WakeReason int reason);
+
+ /**
+ * Called when the global wakefulness has finished becoming awake.
+ *
+ * @param reason One of PowerManager.WAKE_REASON_*, detailing the reason for the change.
+ */
+ void finishedWakingUpGlobal(@PowerManager.WakeReason int reason);
+
+ /**
+ * Called when the global wakefulness has started going to sleep.
+ *
+ * @param reason One of PowerManager.WAKE_REASON_*, detailing the reason for the change.
+ */
+ void startedGoingToSleepGlobal(@PowerManager.GoToSleepReason int reason);
+
+ /**
+ * Called when the global wakefulness has finished going to sleep.
+ *
+ * @param reason One of PowerManager.WAKE_REASON_*, detailing the reason for the change.
+ */
+ void finishedGoingToSleepGlobal(@PowerManager.GoToSleepReason int reason);
+
/**
* Called when the device has started waking up.
*
- * @param pmWakeReason One of PowerManager.WAKE_REASON_*, detailing the specific reason we're
- * waking up, such as WAKE_REASON_POWER_BUTTON or WAKE_REASON_GESTURE.
+ * @param displayGroupId The id of the display group that has started waking up. This will often
+ * be {@link Display#DEFAULT_DISPLAY_GROUP}, but it is possible for other
+ * display groups to exist, for example when there is a
+ * {@link VirtualDevice} with one or more {@link VirtualDisplay}s.
+ * @param pmWakeReason One of PowerManager.WAKE_REASON_*, detailing the specific reason this
+ * display group is waking up, such as WAKE_REASON_POWER_BUTTON or
+ * WAKE_REASON_GESTURE.
*/
- void startedWakingUp(@PowerManager.WakeReason int pmWakeReason);
+ void startedWakingUp(int displayGroupId, @PowerManager.WakeReason int pmWakeReason);
/**
* Called when the device has finished waking up.
*
- * @param pmWakeReason One of PowerManager.WAKE_REASON_*, detailing the specific reason we're
- * waking up, such as WAKE_REASON_POWER_BUTTON or WAKE_REASON_GESTURE.
+ * @param displayGroupId The id of the display group that has finished waking. This will often
+ * be {@link Display#DEFAULT_DISPLAY_GROUP}, but it is possible for other
+ * display groups to exist, for example when there is a
+ * {@link VirtualDevice} with one or more {@link VirtualDisplay}s.
+ * @param pmWakeReason One of PowerManager.WAKE_REASON_*, detailing the specific reason this
+ * display group is waking up, such as WAKE_REASON_POWER_BUTTON or
+ * WAKE_REASON_GESTURE.
*/
- void finishedWakingUp(@PowerManager.WakeReason int pmWakeReason);
+ void finishedWakingUp(int displayGroupId, @PowerManager.WakeReason int pmWakeReason);
/**
* Called when the device has started going to sleep.
*
+ * @param displayGroupId The id of the display group that has started going to sleep. This
+ * will often be {@link Display#DEFAULT_DISPLAY_GROUP}, but it is
+ * possible for other display groups to exist, for example when there is a
+ * {@link VirtualDevice} with one or more {@link VirtualDisplay}s.
* @param pmSleepReason One of PowerManager.GO_TO_SLEEP_REASON_*, detailing the specific reason
- * we're going to sleep, such as GO_TO_SLEEP_REASON_POWER_BUTTON or GO_TO_SLEEP_REASON_TIMEOUT.
+ * this display group is going to sleep, such as
+ * GO_TO_SLEEP_REASON_POWER_BUTTON or GO_TO_SLEEP_REASON_TIMEOUT.
*/
- public void startedGoingToSleep(@PowerManager.GoToSleepReason int pmSleepReason);
+ void startedGoingToSleep(int displayGroupId, @PowerManager.GoToSleepReason int pmSleepReason);
/**
* Called when the device has finished going to sleep.
*
+ * @param displayGroupId The id of the display group that has finished going to sleep. This
+ * will often be {@link Display#DEFAULT_DISPLAY_GROUP}, but it is
+ * possible for other display groups to exist, for example when there is a
+ * {@link VirtualDevice} with one or more {@link VirtualDisplay}s.
* @param pmSleepReason One of PowerManager.GO_TO_SLEEP_REASON_*, detailing the specific reason
- * we're going to sleep, such as GO_TO_SLEEP_REASON_POWER_BUTTON or GO_TO_SLEEP_REASON_TIMEOUT.
+ * we're going to sleep, such as GO_TO_SLEEP_REASON_POWER_BUTTON or
+ * GO_TO_SLEEP_REASON_TIMEOUT.
*/
- 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);
+ void finishedGoingToSleep(int displayGroupId, @PowerManager.GoToSleepReason int pmSleepReason);
/**
* Called when the display is about to turn on to show content.
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index d0ed9bfbb285..9bc0ee224ce0 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -51,6 +51,7 @@ import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.EventLog;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.WindowManagerPolicyConstants;
import com.android.internal.annotations.VisibleForTesting;
@@ -87,7 +88,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* tell the system when we go to sleep so that it can lock the keyguard if needed.
*
*/
-@VisibleForTesting
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
public class Notifier {
private static final String TAG = "PowerManagerNotifier";
@@ -150,14 +151,21 @@ public class Notifier {
// begins charging wirelessly
private final boolean mShowWirelessChargingAnimationConfig;
- // The current interactive state. This is set as soon as an interactive state
+ // Encapsulates interactivity information about a particular display group.
+ private static class Interactivity {
+ public boolean isInteractive = true;
+ public int changeReason;
+ public long changeStartTime; // In SystemClock.uptimeMillis()
+ public boolean isChanging;
+ }
+
+ private final SparseArray mInteractivityByGroupId = new SparseArray<>();
+
+ // The current global interactive state. This is set as soon as an interactive state
// transition begins so as to capture the reason that it happened. At some point
// this state will propagate to the pending state then eventually to the
// broadcasted state over the course of reporting the transition asynchronously.
- private boolean mInteractive = true;
- private int mInteractiveChangeReason;
- private long mInteractiveChangeStartTime; // In SystemClock.uptimeMillis()
- private boolean mInteractiveChanging;
+ private Interactivity mGlobalInteractivity = new Interactivity();
// The pending interactive state that we will eventually want to broadcast.
// This is designed so that we can collapse redundant sequences of awake/sleep
@@ -438,7 +446,8 @@ public class Notifier {
* which case it will assume that the state did not fully converge before the
* next transition began and will recover accordingly.
*/
- public void onWakefulnessChangeStarted(final int wakefulness, int reason, long eventTime) {
+ public void onGlobalWakefulnessChangeStarted(final int wakefulness, int reason,
+ long eventTime) {
final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
if (DEBUG) {
Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness
@@ -456,10 +465,10 @@ public class Notifier {
// Handle any early interactive state changes.
// Finish pending incomplete ones from a previous cycle.
- if (mInteractive != interactive) {
+ if (mGlobalInteractivity.isInteractive != interactive) {
// Finish up late behaviors if needed.
- if (mInteractiveChanging) {
- handleLateInteractiveChange();
+ if (mGlobalInteractivity.isChanging) {
+ handleLateGlobalInteractiveChange();
}
// Start input as soon as we start waking up or going to sleep.
@@ -475,11 +484,11 @@ public class Notifier {
FrameworkStatsLog.INTERACTIVE_STATE_CHANGED__STATE__OFF);
// Handle early behaviors.
- mInteractive = interactive;
- mInteractiveChangeReason = reason;
- mInteractiveChangeStartTime = eventTime;
- mInteractiveChanging = true;
- handleEarlyInteractiveChange();
+ mGlobalInteractivity.isInteractive = interactive;
+ mGlobalInteractivity.isChanging = true;
+ mGlobalInteractivity.changeReason = reason;
+ mGlobalInteractivity.changeStartTime = eventTime;
+ handleEarlyGlobalInteractiveChange();
}
}
@@ -490,10 +499,34 @@ public class Notifier {
if (DEBUG) {
Slog.d(TAG, "onWakefulnessChangeFinished");
}
+ for (int i = 0; i < mInteractivityByGroupId.size(); i++) {
+ int groupId = mInteractivityByGroupId.keyAt(i);
+ Interactivity interactivity = mInteractivityByGroupId.valueAt(i);
+ if (interactivity.isChanging) {
+ interactivity.isChanging = false;
+ handleLateInteractiveChange(groupId);
+ }
+ }
+ if (mGlobalInteractivity.isChanging) {
+ mGlobalInteractivity.isChanging = false;
+ handleLateGlobalInteractiveChange();
+ }
+ }
+
- if (mInteractiveChanging) {
- mInteractiveChanging = false;
- handleLateInteractiveChange();
+ private void handleEarlyInteractiveChange(int groupId) {
+ synchronized (mLock) {
+ Interactivity interactivity = mInteractivityByGroupId.get(groupId);
+ if (interactivity == null) {
+ Slog.e(TAG, "no Interactivity entry for groupId:" + groupId);
+ return;
+ }
+ final int changeReason = interactivity.changeReason;
+ if (interactivity.isInteractive) {
+ mHandler.post(() -> mPolicy.startedWakingUp(groupId, changeReason));
+ } else {
+ mHandler.post(() -> mPolicy.startedGoingToSleep(groupId, changeReason));
+ }
}
}
@@ -501,13 +534,13 @@ public class Notifier {
* Handle early interactive state changes such as getting applications or the lock
* screen running and ready for the user to see (such as when turning on the screen).
*/
- private void handleEarlyInteractiveChange() {
+ private void handleEarlyGlobalInteractiveChange() {
synchronized (mLock) {
- if (mInteractive) {
+ if (mGlobalInteractivity.isInteractive) {
// Waking up...
mHandler.post(() -> {
- mPolicy.startedWakingUp(mInteractiveChangeReason);
mDisplayManagerInternal.onEarlyInteractivityChange(true /*isInteractive*/);
+ mPolicy.startedWakingUpGlobal(mGlobalInteractivity.changeReason);
});
// Send interactive broadcast.
@@ -516,37 +549,36 @@ public class Notifier {
updatePendingBroadcastLocked();
} else {
// Going to sleep...
- // Tell the policy that we started going to sleep.
mHandler.post(() -> {
- mPolicy.startedGoingToSleep(mInteractiveChangeReason);
mDisplayManagerInternal.onEarlyInteractivityChange(false /*isInteractive*/);
+ mPolicy.startedGoingToSleepGlobal(mGlobalInteractivity.changeReason);
});
}
}
}
/**
- * Handle late interactive state changes once they are finished so that the system can
- * finish pending transitions (such as turning the screen off) before causing
- * applications to change state visibly.
+ * Handle late global interactive state changes. Also see
+ * {@link #handleLateInteractiveChange(int)}.
*/
- private void handleLateInteractiveChange() {
+ private void handleLateGlobalInteractiveChange() {
synchronized (mLock) {
final int interactiveChangeLatency =
- (int) (SystemClock.uptimeMillis() - mInteractiveChangeStartTime);
- if (mInteractive) {
+ (int) (SystemClock.uptimeMillis() - mGlobalInteractivity.changeStartTime);
+ if (mGlobalInteractivity.isInteractive) {
// Finished waking up...
mHandler.post(() -> {
LogMaker log = new LogMaker(MetricsEvent.SCREEN);
log.setType(MetricsEvent.TYPE_OPEN);
log.setSubtype(WindowManagerPolicyConstants.translateWakeReasonToOnReason(
- mInteractiveChangeReason));
+ mGlobalInteractivity.changeReason));
log.setLatency(interactiveChangeLatency);
- log.addTaggedData(
- MetricsEvent.FIELD_SCREEN_WAKE_REASON, mInteractiveChangeReason);
+ log.addTaggedData(MetricsEvent.FIELD_SCREEN_WAKE_REASON,
+ mGlobalInteractivity.changeReason);
MetricsLogger.action(log);
EventLogTags.writePowerScreenState(1, 0, 0, 0, interactiveChangeLatency);
- mPolicy.finishedWakingUp(mInteractiveChangeReason);
+
+ mPolicy.finishedWakingUpGlobal(mGlobalInteractivity.changeReason);
});
} else {
// Finished going to sleep...
@@ -563,18 +595,19 @@ public class Notifier {
// Tell the policy we finished going to sleep.
final int offReason = WindowManagerPolicyConstants.translateSleepReasonToOffReason(
- mInteractiveChangeReason);
+ mGlobalInteractivity.changeReason);
mHandler.post(() -> {
LogMaker log = new LogMaker(MetricsEvent.SCREEN);
log.setType(MetricsEvent.TYPE_CLOSE);
log.setSubtype(offReason);
log.setLatency(interactiveChangeLatency);
- log.addTaggedData(
- MetricsEvent.FIELD_SCREEN_SLEEP_REASON, mInteractiveChangeReason);
+ log.addTaggedData(MetricsEvent.FIELD_SCREEN_SLEEP_REASON,
+ mGlobalInteractivity.changeReason);
MetricsLogger.action(log);
EventLogTags.writePowerScreenState(
0, offReason, 0, 0, interactiveChangeLatency);
- mPolicy.finishedGoingToSleep(mInteractiveChangeReason);
+
+ mPolicy.finishedGoingToSleepGlobal(mGlobalInteractivity.changeReason);
});
// Send non-interactive broadcast.
@@ -585,13 +618,63 @@ public class Notifier {
}
}
+ /**
+ * Handle late interactive state changes once they are finished so that the system can
+ * finish pending transitions (such as turning the screen off) before causing
+ * applications to change state visibly.
+ */
+ private void handleLateInteractiveChange(int groupId) {
+ synchronized (mLock) {
+ Interactivity interactivity = mInteractivityByGroupId.get(groupId);
+ if (interactivity == null) {
+ Slog.e(TAG, "no Interactivity entry for groupId:" + groupId);
+ return;
+ }
+ final int changeReason = interactivity.changeReason;
+ if (interactivity.isInteractive) {
+ mHandler.post(() -> mPolicy.finishedWakingUp(groupId, changeReason));
+ } else {
+ mHandler.post(() -> mPolicy.finishedGoingToSleep(groupId, changeReason));
+ }
+ }
+ }
+
/**
* 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));
+ public void onGroupWakefulnessChangeStarted(int groupId, int wakefulness, int changeReason,
+ long eventTime) {
+ final boolean isInteractive = PowerManagerInternal.isInteractive(wakefulness);
+
+ boolean isNewGroup = false;
+ Interactivity interactivity = mInteractivityByGroupId.get(groupId);
+ if (interactivity == null) {
+ isNewGroup = true;
+ interactivity = new Interactivity();
+ mInteractivityByGroupId.put(groupId, interactivity);
+ }
+ if (isNewGroup || interactivity.isInteractive != isInteractive) {
+ // Finish up late behaviors if needed.
+ if (interactivity.isChanging) {
+ handleLateInteractiveChange(groupId);
+ }
+
+ // Handle early behaviors.
+ interactivity.isInteractive = isInteractive;
+ interactivity.changeReason = changeReason;
+ interactivity.changeStartTime = eventTime;
+ interactivity.isChanging = true;
+ handleEarlyInteractiveChange(groupId);
+ }
+ }
+
+ /**
+ * Called when a PowerGroup has been removed.
+ *
+ * @param groupId which group was removed
+ */
+ public void onGroupRemoved(int groupId) {
+ mInteractivityByGroupId.remove(groupId);
}
/**
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index e392c24026a7..9ff98be6f5cd 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -686,6 +686,8 @@ public final class PowerManagerService extends SystemService
@Override
public void onWakefulnessChangedLocked(int groupId, int wakefulness, long eventTime,
int reason, int uid, int opUid, String opPackageName, String details) {
+ mWakefulnessChanging = true;
+ mDirty |= DIRTY_WAKEFULNESS;
if (wakefulness == WAKEFULNESS_AWAKE) {
// Kick user activity to prevent newly awake group from timing out instantly.
// The dream may end without user activity if the dream app crashes / is updated,
@@ -696,9 +698,8 @@ public final class PowerManagerService extends SystemService
PowerManager.USER_ACTIVITY_EVENT_OTHER, flags, uid);
}
mDirty |= DIRTY_DISPLAY_GROUP_WAKEFULNESS;
+ mNotifier.onGroupWakefulnessChangeStarted(groupId, wakefulness, reason, eventTime);
updateGlobalWakefulnessLocked(eventTime, reason, uid, opUid, opPackageName, details);
- mNotifier.onPowerGroupWakefulnessChanged(groupId, wakefulness, reason,
- getGlobalWakefulnessLocked());
updatePowerStateLocked();
}
}
@@ -2152,7 +2153,7 @@ public final class PowerManagerService extends SystemService
mDozeStartInProgress &= (newWakefulness == WAKEFULNESS_DOZING);
if (mNotifier != null) {
- mNotifier.onWakefulnessChangeStarted(newWakefulness, reason, eventTime);
+ mNotifier.onGlobalWakefulnessChangeStarted(newWakefulness, reason, eventTime);
}
mAttentionDetector.onWakefulnessChangeStarted(newWakefulness);
@@ -2163,15 +2164,6 @@ public final class PowerManagerService extends SystemService
if (sQuiescent) {
mDirty |= DIRTY_QUIESCENT;
}
- PowerGroup defaultGroup = mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP);
- if (defaultGroup.getWakefulnessLocked() == WAKEFULNESS_DOZING) {
- // Workaround for b/187231320 where the AOD can get stuck in a "half on /
- // half off" state when a non-default-group VirtualDisplay causes the global
- // wakefulness to change to awake, even though the default display is
- // dozing. We set sandman summoned to restart dreaming to get it unstuck.
- // TODO(b/255688811) - fix this so that AOD never gets interrupted at all.
- defaultGroup.setSandmanSummonedLocked(true);
- }
break;
case WAKEFULNESS_ASLEEP:
@@ -2248,6 +2240,8 @@ public final class PowerManagerService extends SystemService
@GuardedBy("mLock")
void onPowerGroupEventLocked(int event, PowerGroup powerGroup) {
+ mWakefulnessChanging = true;
+ mDirty |= DIRTY_WAKEFULNESS;
final int groupId = powerGroup.getGroupId();
if (event == DisplayGroupPowerChangeListener.DISPLAY_GROUP_REMOVED) {
mPowerGroups.delete(groupId);
@@ -2260,6 +2254,11 @@ public final class PowerManagerService extends SystemService
// Kick user activity to prevent newly added group from timing out instantly.
userActivityNoUpdateLocked(powerGroup, mClock.uptimeMillis(),
PowerManager.USER_ACTIVITY_EVENT_OTHER, /* flags= */ 0, Process.SYSTEM_UID);
+ mNotifier.onGroupWakefulnessChangeStarted(groupId,
+ powerGroup.getWakefulnessLocked(), WAKE_REASON_DISPLAY_GROUP_ADDED,
+ mClock.uptimeMillis());
+ } else if (event == DisplayGroupPowerChangeListener.DISPLAY_GROUP_REMOVED) {
+ mNotifier.onGroupRemoved(groupId);
}
if (oldWakefulness != newWakefulness) {
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 21a11bc0e49e..52bf244e99fb 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -40,6 +40,7 @@ import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.atMost;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -1611,7 +1612,8 @@ public class PowerManagerServiceTest {
startSystem();
assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
- verify(mNotifierMock, never()).onWakefulnessChangeStarted(anyInt(), anyInt(), anyLong());
+ verify(mNotifierMock, never()).onGlobalWakefulnessChangeStarted(anyInt(), anyInt(),
+ anyLong());
}
@Test
@@ -1630,7 +1632,7 @@ public class PowerManagerServiceTest {
startSystem();
assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
- verify(mNotifierMock).onWakefulnessChangeStarted(eq(WAKEFULNESS_ASLEEP), anyInt(),
+ verify(mNotifierMock).onGlobalWakefulnessChangeStarted(eq(WAKEFULNESS_ASLEEP), anyInt(),
anyLong());
}
@@ -2112,7 +2114,7 @@ public class PowerManagerServiceTest {
}
@Test
- public void testMultiDisplay_defaultDozing_addNewDisplayDefaultGoesBackToDoze() {
+ public void testMultiDisplay_addNewDisplay_becomeGloballyAwakeButDefaultRemainsDozing() {
final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
final AtomicReference listener =
@@ -2142,6 +2144,7 @@ public class PowerManagerServiceTest {
assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
WAKEFULNESS_DOZING);
assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ verify(mDreamManagerInternalMock).stopDream(anyBoolean(), anyString());
verify(mDreamManagerInternalMock).startDream(eq(true), anyString());
listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
@@ -2152,7 +2155,10 @@ public class PowerManagerServiceTest {
WAKEFULNESS_AWAKE);
assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
WAKEFULNESS_DOZING);
- verify(mDreamManagerInternalMock, times(2)).startDream(eq(true), anyString());
+
+ // Make sure there were no additional calls to stopDream or startDream
+ verify(mDreamManagerInternalMock, atMost(1)).stopDream(anyBoolean(), anyString());
+ verify(mDreamManagerInternalMock, atMost(1)).startDream(eq(true), anyString());
}
@Test
@@ -2169,7 +2175,7 @@ public class PowerManagerServiceTest {
}
@Test
- public void testMultiDisplay_onlyOneDisplaySleeps_onWakefulnessChangedEventFires() {
+ public void testMultiDisplay_onlyOneDisplaySleeps_onWakefulnessChangedEventsFire() {
createService();
startSystem();
assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
@@ -2177,12 +2183,14 @@ public class PowerManagerServiceTest {
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));
+ verify(mNotifierMock).onGroupWakefulnessChangeStarted(eq(Display.DEFAULT_DISPLAY_GROUP),
+ eq(WAKEFULNESS_ASLEEP), eq(PowerManager.GO_TO_SLEEP_REASON_APPLICATION), anyLong());
+ verify(mNotifierMock).onGlobalWakefulnessChangeStarted(eq(WAKEFULNESS_ASLEEP),
+ eq(PowerManager.GO_TO_SLEEP_REASON_APPLICATION), anyLong());
}
@Test
- public void testMultiDisplay_bothDisplaysSleep_onWakefulnessChangedEventFiresCorrectly() {
+ public void testMultiDisplay_bothDisplaysSleep_onWakefulnessChangedEventsFireCorrectly() {
final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
final AtomicReference listener =
@@ -2201,10 +2209,10 @@ public class PowerManagerServiceTest {
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);
+ mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP, 0, 0,
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null);
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, 0, 0,
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null);
assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
@@ -2212,14 +2220,16 @@ public class PowerManagerServiceTest {
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));
+ verify(mNotifierMock).onGroupWakefulnessChangeStarted(eq(nonDefaultDisplayGroupId),
+ eq(WAKEFULNESS_ASLEEP), eq(PowerManager.GO_TO_SLEEP_REASON_APPLICATION), anyLong());
+ verify(mNotifierMock).onGroupWakefulnessChangeStarted(eq(Display.DEFAULT_DISPLAY_GROUP),
+ eq(WAKEFULNESS_ASLEEP), eq(PowerManager.GO_TO_SLEEP_REASON_APPLICATION), anyLong());
+ verify(mNotifierMock).onGlobalWakefulnessChangeStarted(eq(WAKEFULNESS_ASLEEP),
+ eq(PowerManager.GO_TO_SLEEP_REASON_APPLICATION), anyLong());
}
@Test
- public void testMultiDisplay_separateWakeStates_onWakefulnessChangedEventFiresCorrectly() {
+ public void testMultiDisplay_separateWakeStates_onWakefulnessChangedEventsFireCorrectly() {
final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
final AtomicReference listener =
@@ -2255,10 +2265,53 @@ public class PowerManagerServiceTest {
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());
+ verify(mNotifierMock).onGroupWakefulnessChangeStarted(eq(nonDefaultDisplayGroupId),
+ eq(WAKEFULNESS_AWAKE), eq(PowerManager.WAKE_REASON_DISPLAY_GROUP_ADDED), anyLong());
+ verify(mNotifierMock).onGroupWakefulnessChangeStarted(eq(Display.DEFAULT_DISPLAY_GROUP),
+ eq(WAKEFULNESS_ASLEEP), eq(PowerManager.GO_TO_SLEEP_REASON_APPLICATION), anyLong());
+ verify(mNotifierMock, never()).onGlobalWakefulnessChangeStarted(eq(WAKEFULNESS_ASLEEP),
+ anyInt(), anyLong());
+ }
+
+ @Test
+ public void testMultiDisplay_oneDisplayGroupChanges_globalDoesNotChange() {
+ 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();
+
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ long eventTime = mClock.now();
+ mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP, eventTime, 0,
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null);
+
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_ASLEEP);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ verify(mNotifierMock, never()).onGlobalWakefulnessChangeStarted(anyInt(), anyInt(),
+ anyLong());
+ verify(mNotifierMock, atMost(1)).onGroupWakefulnessChangeStarted(
+ eq(nonDefaultDisplayGroupId), eq(WAKEFULNESS_ASLEEP),
+ eq(PowerManager.GO_TO_SLEEP_REASON_APPLICATION), eq(eventTime));
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index 2665e197f91f..5636795520e9 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -233,8 +233,8 @@ class TestPhoneWindowManager {
doNothing().when(mPhoneWindowManager).updateSettings();
doNothing().when(mPhoneWindowManager).screenTurningOn(anyInt(), any());
doNothing().when(mPhoneWindowManager).screenTurnedOn(anyInt());
- doNothing().when(mPhoneWindowManager).startedWakingUp(anyInt());
- doNothing().when(mPhoneWindowManager).finishedWakingUp(anyInt());
+ doNothing().when(mPhoneWindowManager).startedWakingUp(anyInt(), anyInt());
+ doNothing().when(mPhoneWindowManager).finishedWakingUp(anyInt(), anyInt());
mPhoneWindowManager.init(new TestInjector(mContext, mWindowManagerFuncsImpl));
mPhoneWindowManager.systemReady();
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 2a2641edb637..1f7e3d9546eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -114,24 +114,35 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public void startedWakingUp(@WakeReason int wakeReason) {
+ public void startedWakingUpGlobal(@WakeReason int reason) {
}
@Override
- public void finishedWakingUp(@WakeReason int wakeReason) {
+ public void finishedWakingUpGlobal(@WakeReason int reason) {
}
@Override
- public void startedGoingToSleep(@GoToSleepReason int sleepReason) {
+ public void startedGoingToSleepGlobal(@GoToSleepReason int reason) {
}
@Override
- public void finishedGoingToSleep(@GoToSleepReason int sleepReason) {
+ public void finishedGoingToSleepGlobal(@GoToSleepReason int reason) {
}
@Override
- public void onPowerGroupWakefulnessChanged(int groupId, int wakefulness,
- @GoToSleepReason int pmSleepReason, int globalWakefulness) {
+ public void startedWakingUp(int displayGroupId, @WakeReason int wakeReason) {
+ }
+
+ @Override
+ public void finishedWakingUp(int displayGroupId, @WakeReason int wakeReason) {
+ }
+
+ @Override
+ public void startedGoingToSleep(int displayGroupId, @GoToSleepReason int sleepReason) {
+ }
+
+ @Override
+ public void finishedGoingToSleep(int displayGroupId, @GoToSleepReason int sleepReason) {
}
@Override
--
cgit v1.2.3-59-g8ed1b