summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Sean Stout <sstout@google.com> 2021-01-21 21:04:58 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-01-21 21:04:58 +0000
commit99170bffd3bcb3856754c79bf3dd5ae6bcf50158 (patch)
tree4a480561bad92f2019c15eca5cfd0bd1c259fd1a
parent3cc6d0b3741d91612532c6811e817531552283f0 (diff)
parente2f209d2600864c447362f7c71341c8e5564b41f (diff)
Merge "PM#goToSleep and PM#wakeUp only affects default display group"
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java63
-rw-r--r--core/java/android/os/PowerManager.java80
-rw-r--r--services/core/java/com/android/server/display/DisplayGroup.java34
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java125
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java11
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerState.java20
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplayMapper.java89
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java67
-rw-r--r--services/core/java/com/android/server/power/DisplayGroupPowerStateMapper.java280
-rw-r--r--services/core/java/com/android/server/power/DisplayPowerRequestMapper.java122
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java667
-rw-r--r--services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java121
12 files changed, 1186 insertions, 493 deletions
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 5a03adee4eab..421a07ba93e1 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -47,28 +47,40 @@ public abstract class DisplayManagerInternal {
* begins adjusting the power state to match what was requested.
* </p>
*
+ * @param groupId The identifier for the display group being requested to change power state
* @param request The requested power state.
- * @param waitForNegativeProximity If true, issues a request to wait for
+ * @param waitForNegativeProximity If {@code true}, issues a request to wait for
* negative proximity before turning the screen back on, assuming the screen
* was turned off by the proximity sensor.
- * @return True if display is ready, false if there are important changes that must
- * be made asynchronously (such as turning the screen on), in which case the caller
- * should grab a wake lock, watch for {@link DisplayPowerCallbacks#onStateChanged()}
- * then try the request again later until the state converges.
+ * @return {@code true} if display group is ready, {@code false} if there are important
+ * changes that must be made asynchronously (such as turning the screen on), in which case
+ * the caller should grab a wake lock, watch for {@link DisplayPowerCallbacks#onStateChanged}
+ * then try the request again later until the state converges. If the provided {@code groupId}
+ * cannot be found then {@code true} will be returned.
*/
- public abstract boolean requestPowerState(DisplayPowerRequest request,
+ public abstract boolean requestPowerState(int groupId, DisplayPowerRequest request,
boolean waitForNegativeProximity);
/**
- * Returns true if the proximity sensor screen-off function is available.
+ * Returns {@code true} if the proximity sensor screen-off function is available.
*/
public abstract boolean isProximitySensorAvailable();
/**
- * Returns the id of the {@link com.android.server.display.DisplayGroup} to which the provided
- * display belongs.
+ * Registers a display group listener which will be informed of the addition, removal, or change
+ * of display groups.
+ *
+ * @param listener The listener to register.
*/
- public abstract int getDisplayGroupId(int displayId);
+ public abstract void registerDisplayGroupListener(DisplayGroupListener listener);
+
+ /**
+ * Unregisters a display group listener which will be informed of the addition, removal, or
+ * change of display groups.
+ *
+ * @param listener The listener to unregister.
+ */
+ public abstract void unregisterDisplayGroupListener(DisplayGroupListener listener);
/**
* Screenshot for internal system-only use such as rotation, etc. This method includes
@@ -451,7 +463,7 @@ public abstract class DisplayManagerInternal {
void onStateChanged();
void onProximityPositive();
void onProximityNegative();
- void onDisplayStateChange(int state); // one of the Display state constants
+ void onDisplayStateChange(boolean allInactive, boolean allOff);
void acquireSuspendBlocker();
void releaseSuspendBlocker();
@@ -465,4 +477,33 @@ public abstract class DisplayManagerInternal {
public interface DisplayTransactionListener {
void onDisplayTransaction(Transaction t);
}
+
+ /**
+ * Called when there are changes to {@link com.android.server.display.DisplayGroup
+ * DisplayGroups}.
+ */
+ public interface DisplayGroupListener {
+ /**
+ * A new display group with the provided {@code groupId} was added.
+ * This is guaranteed to be called <i>before</i> any corresponding calls to
+ * {@link android.hardware.display.DisplayManager.DisplayListener} are made.
+ */
+ void onDisplayGroupAdded(int groupId);
+
+ /**
+ * The display group with the provided {@code groupId} was removed.
+ *
+ * This is guaranteed to be called <i>after</i> any corresponding calls to
+ * {@link android.hardware.display.DisplayManager.DisplayListener} are made.
+ */
+ void onDisplayGroupRemoved(int groupId);
+
+ /**
+ * The display group with the provided {@code groupId} has changed.
+ *
+ * This is guaranteed to be called <i>after</i> any corresponding calls to
+ * {@link android.hardware.display.DisplayManager.DisplayListener} are made.
+ */
+ void onDisplayGroupChanged(int groupId);
+ }
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index d11f3ce0d112..cbb3ba90fb03 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -416,9 +416,21 @@ public final class PowerManager {
public static final int GO_TO_SLEEP_REASON_QUIESCENT = 10;
/**
+ * Go to sleep reason code: The last powered on display group has been removed.
* @hide
*/
- public static final int GO_TO_SLEEP_REASON_MAX = GO_TO_SLEEP_REASON_QUIESCENT;
+ public static final int GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED = 11;
+
+ /**
+ * Go to sleep reason code: Every display group has been turned off.
+ * @hide
+ */
+ public static final int GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF = 12;
+
+ /**
+ * @hide
+ */
+ public static final int GO_TO_SLEEP_REASON_MAX = GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF;
/**
* @hide
@@ -435,6 +447,8 @@ public final class PowerManager {
case GO_TO_SLEEP_REASON_ACCESSIBILITY: return "accessibility";
case GO_TO_SLEEP_REASON_FORCE_SUSPEND: return "force_suspend";
case GO_TO_SLEEP_REASON_INATTENTIVE: return "inattentive";
+ case GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED: return "display_group_removed";
+ case GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF: return "display_groups_turned_off";
default: return Integer.toString(sleepReason);
}
}
@@ -521,6 +535,8 @@ public final class PowerManager {
WAKE_REASON_WAKE_KEY,
WAKE_REASON_WAKE_MOTION,
WAKE_REASON_HDMI,
+ WAKE_REASON_DISPLAY_GROUP_ADDED,
+ WAKE_REASON_DISPLAY_GROUP_TURNED_ON,
})
@Retention(RetentionPolicy.SOURCE)
public @interface WakeReason{}
@@ -608,6 +624,18 @@ public final class PowerManager {
public static final int WAKE_REASON_LID = 9;
/**
+ * Wake up reason code: Waking due to display group being added.
+ * @hide
+ */
+ public static final int WAKE_REASON_DISPLAY_GROUP_ADDED = 10;
+
+ /**
+ * Wake up reason code: Waking due to display group being powered on.
+ * @hide
+ */
+ public static final int WAKE_REASON_DISPLAY_GROUP_TURNED_ON = 11;
+
+ /**
* Convert the wake reason to a string for debugging purposes.
* @hide
*/
@@ -623,6 +651,8 @@ public final class PowerManager {
case WAKE_REASON_WAKE_MOTION: return "WAKE_REASON_WAKE_MOTION";
case WAKE_REASON_HDMI: return "WAKE_REASON_HDMI";
case WAKE_REASON_LID: return "WAKE_REASON_LID";
+ case WAKE_REASON_DISPLAY_GROUP_ADDED: return "WAKE_REASON_DISPLAY_GROUP_ADDED";
+ case WAKE_REASON_DISPLAY_GROUP_TURNED_ON: return "WAKE_REASON_DISPLAY_GROUP_TURNED_ON";
default: return Integer.toString(wakeReason);
}
}
@@ -1214,8 +1244,15 @@ public final class PowerManager {
}
}
- /**
- * Forces the device to go to sleep.
+ /**
+ * Forces the {@link com.android.server.display.DisplayGroup#DEFAULT default display group}
+ * to turn off.
+ *
+ * <p>If the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is
+ * turned on it will be turned off. If all displays are off as a result of this action the
+ * device will be put to sleep. If the {@link com.android.server.display.DisplayGroup#DEFAULT
+ * default display group} is already off then nothing will happen.
+ *
* <p>
* Overrides all the wake locks that are held.
* This is what happens when the power key is pressed to turn off the screen.
@@ -1238,7 +1275,14 @@ public final class PowerManager {
}
/**
- * Forces the device to go to sleep.
+ * Forces the {@link com.android.server.display.DisplayGroup#DEFAULT default display group}
+ * to turn off.
+ *
+ * <p>If the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is
+ * turned on it will be turned off. If all displays are off as a result of this action the
+ * device will be put to sleep. If the {@link com.android.server.display.DisplayGroup#DEFAULT
+ * default display group} is already off then nothing will happen.
+ *
* <p>
* Overrides all the wake locks that are held.
* This is what happens when the power key is pressed to turn off the screen.
@@ -1268,9 +1312,15 @@ public final class PowerManager {
}
/**
- * Forces the device to wake up from sleep.
+ * Forces the {@link com.android.server.display.DisplayGroup#DEFAULT default display group}
+ * to turn on.
+ *
+ * <p>If the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is
+ * turned off it will be turned on. Additionally, if the device is asleep it will be awoken. If
+ * the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is already
+ * on then nothing will happen.
+ *
* <p>
- * If the device is currently asleep, wakes it up, otherwise does nothing.
* This is what happens when the power key is pressed to turn on the screen.
* </p><p>
* Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
@@ -1293,9 +1343,15 @@ public final class PowerManager {
}
/**
- * Forces the device to wake up from sleep.
+ * Forces the {@link com.android.server.display.DisplayGroup#DEFAULT default display group}
+ * to turn on.
+ *
+ * <p>If the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is
+ * turned off it will be turned on. Additionally, if the device is asleep it will be awoken. If
+ * the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is already
+ * on then nothing will happen.
+ *
* <p>
- * If the device is currently asleep, wakes it up, otherwise does nothing.
* This is what happens when the power key is pressed to turn on the screen.
* </p><p>
* Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
@@ -1322,9 +1378,13 @@ public final class PowerManager {
}
/**
- * Forces the device to wake up from sleep.
+ * Forces the {@link android.view.Display#DEFAULT_DISPLAY default display} to turn on.
+ *
+ * <p>If the {@link android.view.Display#DEFAULT_DISPLAY default display} is turned off it will
+ * be turned on. Additionally, if the device is asleep it will be awoken. If the {@link
+ * android.view.Display#DEFAULT_DISPLAY default display} is already on then nothing will happen.
+ *
* <p>
- * If the device is currently asleep, wakes it up, otherwise does nothing.
* This is what happens when the power key is pressed to turn on the screen.
* </p><p>
* Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
diff --git a/services/core/java/com/android/server/display/DisplayGroup.java b/services/core/java/com/android/server/display/DisplayGroup.java
index 2ba875813734..1b5065ad89e4 100644
--- a/services/core/java/com/android/server/display/DisplayGroup.java
+++ b/services/core/java/com/android/server/display/DisplayGroup.java
@@ -21,7 +21,8 @@ import java.util.List;
/**
* Represents a collection of {@link LogicalDisplay}s which act in unison for certain behaviors and
- * operations.
+ * operations; particularly display-state.
+ *
* @hide
*/
public class DisplayGroup {
@@ -35,17 +36,44 @@ public class DisplayGroup {
mGroupId = groupId;
}
+ /** Returns the identifier for the Group. */
int getGroupId() {
return mGroupId;
}
- void addDisplay(LogicalDisplay display) {
+ /**
+ * Adds the provided {@code display} to the Group
+ *
+ * @param display the {@link LogicalDisplay} to add to the Group
+ */
+ void addDisplayLocked(LogicalDisplay display) {
if (!mDisplays.contains(display)) {
mDisplays.add(display);
}
}
- boolean removeDisplay(LogicalDisplay display) {
+ /**
+ * Removes the provided {@code display} from the Group.
+ *
+ * @param display The {@link LogicalDisplay} to remove from the Group.
+ * @return {@code true} if the {@code display} was removed; otherwise {@code false}
+ */
+ boolean removeDisplayLocked(LogicalDisplay display) {
return mDisplays.remove(display);
}
+
+ /** Returns {@code true} if there are no {@link LogicalDisplay LogicalDisplays} in the Group. */
+ boolean isEmptyLocked() {
+ return mDisplays.isEmpty();
+ }
+
+ /** Returns the number of {@link LogicalDisplay LogicalDisplays} in the Group. */
+ int getSizeLocked() {
+ return mDisplays.size();
+ }
+
+ /** Returns the ID of the {@link LogicalDisplay} at the provided {@code index}. */
+ int getIdLocked(int index) {
+ return mDisplays.get(index).getDisplayIdLocked();
+ }
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 55103ca6cd1c..bb4c9dda2195 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -57,6 +57,7 @@ import android.hardware.display.Curve;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayManagerInternal.DisplayGroupListener;
import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
import android.hardware.display.DisplayViewport;
import android.hardware.display.DisplayedContentSample;
@@ -190,6 +191,7 @@ public final class DisplayManagerService extends SystemService {
private static final int MSG_UPDATE_VIEWPORT = 5;
private static final int MSG_LOAD_BRIGHTNESS_CONFIGURATION = 6;
private static final int MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE = 7;
+ private static final int MSG_DELIVER_DISPLAY_GROUP_EVENT = 8;
private final Context mContext;
private final DisplayManagerHandler mHandler;
@@ -237,36 +239,54 @@ public final class DisplayManagerService extends SystemService {
private final CopyOnWriteArrayList<DisplayTransactionListener> mDisplayTransactionListeners =
new CopyOnWriteArrayList<DisplayTransactionListener>();
+ /** List of all display group listeners. */
+ private final CopyOnWriteArrayList<DisplayGroupListener> mDisplayGroupListeners =
+ new CopyOnWriteArrayList<>();
+
/** All {@link DisplayPowerController}s indexed by {@link LogicalDisplay} ID. */
private final SparseArray<DisplayPowerController> mDisplayPowerControllers =
new SparseArray<>();
/** {@link DisplayBlanker} used by all {@link DisplayPowerController}s. */
private final DisplayBlanker mDisplayBlanker = new DisplayBlanker() {
+ // Synchronized to avoid race conditions when updating multiple display states.
@Override
- public void requestDisplayState(int displayId, int state, float brightness) {
- // TODO (b/168210494): Stop applying default display state to all displays.
- if (displayId != Display.DEFAULT_DISPLAY) {
- return;
- }
- final int[] displayIds;
+ public synchronized void requestDisplayState(int displayId, int state, float brightness) {
+ boolean allInactive = true;
+ boolean allOff = true;
+ final boolean stateChanged;
synchronized (mSyncRoot) {
- displayIds = mLogicalDisplayMapper.getDisplayIdsLocked();
+ final int index = mDisplayStates.indexOfKey(displayId);
+ final int newState = mDisplayStates.valueAt(index);
+ stateChanged = index == -1 || state != newState;
+ if (stateChanged) {
+ final int size = mDisplayStates.size();
+ for (int i = 0; i < size; i++) {
+ final int displayState = i == index ? newState : state;
+ if (displayState != Display.STATE_OFF) {
+ allOff = false;
+ }
+ if (Display.isActiveState(displayState)) {
+ allInactive = false;
+ }
+ if (!allOff && !allInactive) {
+ break;
+ }
+ }
+ }
}
// The order of operations is important for legacy reasons.
if (state == Display.STATE_OFF) {
- for (int id : displayIds) {
- requestDisplayStateInternal(id, state, brightness);
- }
+ requestDisplayStateInternal(displayId, state, brightness);
}
- mDisplayPowerCallbacks.onDisplayStateChange(state);
+ if (stateChanged) {
+ mDisplayPowerCallbacks.onDisplayStateChange(allInactive, allOff);
+ }
if (state != Display.STATE_OFF) {
- for (int id : displayIds) {
- requestDisplayStateInternal(id, state, brightness);
- }
+ requestDisplayStateInternal(displayId, state, brightness);
}
}
};
@@ -1152,7 +1172,7 @@ public final class DisplayManagerService extends SystemService {
private void handleLogicalDisplayRemovedLocked(@NonNull LogicalDisplay display) {
final int displayId = display.getDisplayIdLocked();
- mDisplayPowerControllers.delete(displayId);
+ mDisplayPowerControllers.removeReturnOld(displayId).stop();
mDisplayStates.delete(displayId);
mDisplayBrightnesses.delete(displayId);
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
@@ -1669,6 +1689,11 @@ public final class DisplayManagerService extends SystemService {
mHandler.sendMessage(msg);
}
+ private void sendDisplayGroupEvent(int groupId, int event) {
+ Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_GROUP_EVENT, groupId, event);
+ mHandler.sendMessage(msg);
+ }
+
private void sendDisplayEventFrameRateOverrideLocked(int displayId) {
Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE,
displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
@@ -1713,6 +1738,35 @@ public final class DisplayManagerService extends SystemService {
mTempCallbacks.clear();
}
+ // Runs on Handler thread.
+ // Delivers display group event notifications to callbacks.
+ private void deliverDisplayGroupEvent(int groupId, int event) {
+ if (DEBUG) {
+ Slog.d(TAG, "Delivering display group event: groupId=" + groupId + ", event="
+ + event);
+ }
+
+ switch (event) {
+ case LogicalDisplayMapper.DISPLAY_GROUP_EVENT_ADDED:
+ for (DisplayGroupListener listener : mDisplayGroupListeners) {
+ listener.onDisplayGroupAdded(groupId);
+ }
+ break;
+
+ case LogicalDisplayMapper.DISPLAY_GROUP_EVENT_CHANGED:
+ for (DisplayGroupListener listener : mDisplayGroupListeners) {
+ listener.onDisplayGroupChanged(groupId);
+ }
+ break;
+
+ case LogicalDisplayMapper.DISPLAY_GROUP_EVENT_REMOVED:
+ for (DisplayGroupListener listener : mDisplayGroupListeners) {
+ listener.onDisplayGroupRemoved(groupId);
+ }
+ break;
+ }
+ }
+
private IMediaProjectionManager getProjectionService() {
if (mProjectionService == null) {
IBinder b = ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE);
@@ -1935,6 +1989,11 @@ public final class DisplayManagerService extends SystemService {
}
deliverDisplayEvent(msg.arg1, uids, msg.arg2);
break;
+
+ case MSG_DELIVER_DISPLAY_GROUP_EVENT:
+ deliverDisplayGroupEvent(msg.arg1, msg.arg2);
+ break;
+
}
}
}
@@ -1966,6 +2025,11 @@ public final class DisplayManagerService extends SystemService {
}
@Override
+ public void onDisplayGroupEventLocked(int groupId, int event) {
+ sendDisplayGroupEvent(groupId, event);
+ }
+
+ @Override
public void onTraversalRequested() {
synchronized (mSyncRoot) {
scheduleTraversalLocked(false);
@@ -2700,11 +2764,25 @@ public final class DisplayManagerService extends SystemService {
}
@Override
- public boolean requestPowerState(DisplayPowerRequest request,
+ public boolean requestPowerState(int groupId, DisplayPowerRequest request,
boolean waitForNegativeProximity) {
synchronized (mSyncRoot) {
- return mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY)
- .requestPowerState(request, waitForNegativeProximity);
+ final DisplayGroup displayGroup = mLogicalDisplayMapper.getDisplayGroupLocked(
+ groupId);
+ if (displayGroup == null) {
+ return true;
+ }
+
+ final int size = displayGroup.getSizeLocked();
+ boolean ready = true;
+ for (int i = 0; i < size; i++) {
+ final DisplayPowerController displayPowerController =
+ mDisplayPowerControllers.get(displayGroup.getIdLocked(i));
+ ready &= displayPowerController.requestPowerState(request,
+ waitForNegativeProximity);
+ }
+
+ return ready;
}
}
@@ -2717,10 +2795,13 @@ public final class DisplayManagerService extends SystemService {
}
@Override
- public int getDisplayGroupId(int displayId) {
- synchronized (mSyncRoot) {
- return mLogicalDisplayMapper.getDisplayGroupIdLocked(displayId);
- }
+ public void registerDisplayGroupListener(DisplayGroupListener listener) {
+ mDisplayGroupListeners.add(listener);
+ }
+
+ @Override
+ public void unregisterDisplayGroupListener(DisplayGroupListener listener) {
+ mDisplayGroupListeners.remove(listener);
}
@Override
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 811625b06cf0..5c795cdbddc6 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -683,6 +683,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// TODO: b/175821789 - Support high brightness on multiple (folding) displays
}
+ /**
+ * Unregisters all listeners and interrupts all running threads; halting future work.
+ *
+ * This method should be called when the DisplayPowerController is no longer in use; i.e. when
+ * the {@link #mDisplayId display} has been removed.
+ */
+ public void stop() {
+ mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
+ mPowerState.stop();
+ }
+
private void sendUpdatePowerState() {
synchronized (mLock) {
sendUpdatePowerStateLocked();
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 54f30a954c33..51ba065f601c 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -72,6 +72,8 @@ final class DisplayPowerState {
private Runnable mCleanListener;
+ private volatile boolean mStopped;
+
public DisplayPowerState(DisplayBlanker blanker, ColorFade colorFade, int displayId) {
mHandler = new Handler(true /*async*/);
mChoreographer = Choreographer.getInstance();
@@ -263,6 +265,18 @@ final class DisplayPowerState {
}
}
+ /**
+ * Interrupts all running threads; halting future work.
+ *
+ * This method should be called when the DisplayPowerState is no longer in use; i.e. when
+ * the {@link #mDisplayId display} has been removed.
+ */
+ public void stop() {
+ mHandler.removeCallbacksAndMessages(null);
+ mStopped = true;
+ mPhotonicModulator.interrupt();
+ }
+
public void dump(PrintWriter pw) {
pw.println();
pw.println("Display Power State:");
@@ -427,7 +441,11 @@ final class DisplayPowerState {
if (!stateChanged && !backlightChanged) {
try {
mLock.wait();
- } catch (InterruptedException ex) { }
+ } catch (InterruptedException ex) {
+ if (mStopped) {
+ return;
+ }
+ }
continue;
}
mActualState = state;
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index bb2fbed354aa..ecb837da458b 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -17,7 +17,6 @@
package com.android.server.display;
import android.content.Context;
-import android.os.Process;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.IndentingPrintWriter;
@@ -55,6 +54,10 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 4;
public static final int LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED = 5;
+ public static final int DISPLAY_GROUP_EVENT_ADDED = 1;
+ public static final int DISPLAY_GROUP_EVENT_CHANGED = 2;
+ public static final int DISPLAY_GROUP_EVENT_REMOVED = 3;
+
/**
* Temporary display info, used for comparing display configurations.
*/
@@ -99,7 +102,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
private int mNextNonDefaultGroupId = DisplayGroup.DEFAULT + 1;
/** A mapping from logical display id to display group. */
- private final SparseArray<DisplayGroup> mDisplayGroups = new SparseArray<>();
+ private final SparseArray<DisplayGroup> mDisplayIdToGroupMap = new SparseArray<>();
private final DisplayDeviceRepository mDisplayDeviceRepo;
private final Listener mListener;
@@ -154,10 +157,6 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
return null;
}
- public int[] getDisplayIdsLocked() {
- return getDisplayIdsLocked(Process.SYSTEM_UID);
- }
-
public int[] getDisplayIdsLocked(int callingUid) {
final int count = mLogicalDisplays.size();
int[] displayIds = new int[count];
@@ -182,13 +181,16 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
}
}
- public int getDisplayGroupIdLocked(int displayId) {
- final DisplayGroup displayGroup = mDisplayGroups.get(displayId);
- if (displayGroup != null) {
- return displayGroup.getGroupId();
+ public DisplayGroup getDisplayGroupLocked(int groupId) {
+ final int size = mDisplayIdToGroupMap.size();
+ for (int i = 0; i < size; i++) {
+ final DisplayGroup displayGroup = mDisplayIdToGroupMap.valueAt(i);
+ if (displayGroup.getGroupId() == groupId) {
+ return displayGroup;
+ }
}
- return -1;
+ return null;
}
public void dumpLocked(PrintWriter pw) {
@@ -325,17 +327,31 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
mLogicalDisplays.put(displayId, display);
final DisplayGroup displayGroup;
- if (isDefault || (deviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0) {
+ final boolean addNewDisplayGroup =
+ isDefault || (deviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0;
+ if (addNewDisplayGroup) {
final int groupId = assignDisplayGroupIdLocked(isDefault);
displayGroup = new DisplayGroup(groupId);
} else {
- displayGroup = mDisplayGroups.get(Display.DEFAULT_DISPLAY);
+ displayGroup = mDisplayIdToGroupMap.get(Display.DEFAULT_DISPLAY);
+ }
+ displayGroup.addDisplayLocked(display);
+ mDisplayIdToGroupMap.append(displayId, displayGroup);
+
+ if (addNewDisplayGroup) {
+ // Group added events happen before Logical Display added events.
+ mListener.onDisplayGroupEventLocked(displayGroup.getGroupId(),
+ LogicalDisplayMapper.DISPLAY_GROUP_EVENT_ADDED);
}
- displayGroup.addDisplay(display);
- mDisplayGroups.append(displayId, displayGroup);
mListener.onLogicalDisplayEventLocked(display,
LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED);
+
+ if (!addNewDisplayGroup) {
+ // Group changed events happen after Logical Display added events.
+ mListener.onDisplayGroupEventLocked(displayGroup.getGroupId(),
+ LogicalDisplayMapper.DISPLAY_GROUP_EVENT_CHANGED);
+ }
}
/**
@@ -352,31 +368,45 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
DisplayEventReceiver.FrameRateOverride[] frameRatesOverrides =
display.getFrameRateOverrides();
display.updateLocked(mDisplayDeviceRepo);
+ final DisplayGroup changedDisplayGroup;
if (!display.isValidLocked()) {
mLogicalDisplays.removeAt(i);
- mDisplayGroups.removeReturnOld(displayId).removeDisplay(display);
+ final DisplayGroup displayGroup = mDisplayIdToGroupMap.removeReturnOld(displayId);
+ displayGroup.removeDisplayLocked(display);
mListener.onLogicalDisplayEventLocked(display,
LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED);
+
+ changedDisplayGroup = displayGroup;
} else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
final int flags = display.getDisplayInfoLocked().flags;
- final DisplayGroup defaultDisplayGroup = mDisplayGroups.get(
+ final DisplayGroup defaultDisplayGroup = mDisplayIdToGroupMap.get(
Display.DEFAULT_DISPLAY);
if ((flags & Display.FLAG_OWN_DISPLAY_GROUP) != 0) {
// The display should have its own DisplayGroup.
- if (defaultDisplayGroup.removeDisplay(display)) {
+ if (defaultDisplayGroup.removeDisplayLocked(display)) {
final int groupId = assignDisplayGroupIdLocked(false);
final DisplayGroup displayGroup = new DisplayGroup(groupId);
- displayGroup.addDisplay(display);
- mDisplayGroups.append(display.getDisplayIdLocked(), displayGroup);
+ displayGroup.addDisplayLocked(display);
+ mDisplayIdToGroupMap.append(display.getDisplayIdLocked(), displayGroup);
+ mListener.onDisplayGroupEventLocked(displayGroup.getGroupId(),
+ LogicalDisplayMapper.DISPLAY_GROUP_EVENT_ADDED);
+ changedDisplayGroup = defaultDisplayGroup;
+ } else {
+ changedDisplayGroup = null;
}
} else {
// The display should be a part of the default DisplayGroup.
- final DisplayGroup displayGroup = mDisplayGroups.get(displayId);
+ final DisplayGroup displayGroup = mDisplayIdToGroupMap.get(displayId);
if (displayGroup != defaultDisplayGroup) {
- displayGroup.removeDisplay(display);
- defaultDisplayGroup.addDisplay(display);
- mDisplayGroups.put(displayId, defaultDisplayGroup);
+ displayGroup.removeDisplayLocked(display);
+ defaultDisplayGroup.addDisplayLocked(display);
+ mListener.onDisplayGroupEventLocked(displayGroup.getGroupId(),
+ LogicalDisplayMapper.DISPLAY_GROUP_EVENT_CHANGED);
+ mDisplayIdToGroupMap.put(displayId, defaultDisplayGroup);
+ changedDisplayGroup = displayGroup;
+ } else {
+ changedDisplayGroup = null;
}
}
@@ -388,6 +418,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
} else if (!display.getPendingFrameRateOverrideUids().isEmpty()) {
mListener.onLogicalDisplayEventLocked(display,
LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);
+ changedDisplayGroup = null;
} else {
// While applications shouldn't know nor care about the non-overridden info, we
// still need to let WindowManager know so it can update its own internal state for
@@ -397,6 +428,15 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
mListener.onLogicalDisplayEventLocked(display,
LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_CHANGED);
}
+ changedDisplayGroup = null;
+ }
+
+ // CHANGED and REMOVED DisplayGroup events should always fire after Display events.
+ if (changedDisplayGroup != null) {
+ final int event = changedDisplayGroup.isEmptyLocked()
+ ? LogicalDisplayMapper.DISPLAY_GROUP_EVENT_REMOVED
+ : LogicalDisplayMapper.DISPLAY_GROUP_EVENT_CHANGED;
+ mListener.onDisplayGroupEventLocked(changedDisplayGroup.getGroupId(), event);
}
}
}
@@ -432,6 +472,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
public interface Listener {
void onLogicalDisplayEventLocked(LogicalDisplay display, int event);
+ void onDisplayGroupEventLocked(int groupId, int event);
void onTraversalRequested();
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4c344c519089..69484b1e961d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -447,8 +447,25 @@ public class PhoneWindowManager implements WindowManagerPolicy {
volatile int mPowerKeyPressCounter;
volatile boolean mEndCallKeyHandled;
volatile boolean mCameraGestureTriggeredDuringGoingToSleep;
- volatile boolean mGoingToSleep;
- volatile boolean mRequestedOrGoingToSleep;
+
+ /**
+ * {@code true} if the device is entering a low-power state; {@code false otherwise}.
+ *
+ * <p>This differs from {@link #mRequestedOrSleepingDefaultDisplay} which tracks the power state
+ * of the {@link #mDefaultDisplay default display} versus the power state of the entire device.
+ */
+ volatile boolean mDeviceGoingToSleep;
+
+ /**
+ * {@code true} if the {@link #mDefaultDisplay default display} is entering or was requested to
+ * enter a low-power state; {@code false otherwise}.
+ *
+ * <p>This differs from {@link #mDeviceGoingToSleep} which tracks the power state of the entire
+ * device versus the power state of the {@link #mDefaultDisplay default display}.
+ */
+ // TODO(b/178103325): Track sleep/requested sleep for every display.
+ volatile boolean mRequestedOrSleepingDefaultDisplay;
+
volatile boolean mRecentsVisible;
volatile boolean mNavBarVirtualKeyHapticFeedbackEnabled = true;
volatile boolean mPictureInPictureVisible;
@@ -916,7 +933,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (gestureService != null) {
gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,
mTmpBoolean);
- if (mTmpBoolean.value && mRequestedOrGoingToSleep) {
+ if (mTmpBoolean.value && mRequestedOrSleepingDefaultDisplay) {
mCameraGestureTriggeredDuringGoingToSleep = true;
}
}
@@ -1063,13 +1080,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case SHORT_PRESS_POWER_NOTHING:
break;
case SHORT_PRESS_POWER_GO_TO_SLEEP:
- goToSleepFromPowerButton(eventTime, 0);
+ sleepDefaultDisplayFromPowerButton(eventTime, 0);
break;
case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP:
- goToSleepFromPowerButton(eventTime, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+ sleepDefaultDisplayFromPowerButton(eventTime,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
break;
case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
- if (goToSleepFromPowerButton(eventTime,
+ if (sleepDefaultDisplayFromPowerButton(eventTime,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE)) {
launchHomeFromHotKey(DEFAULT_DISPLAY);
}
@@ -1097,11 +1115,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
/**
- * Sends the device to sleep as a result of a power button press.
+ * Sends the default display to sleep as a result of a power button press.
*
- * @return True if the was device was sent to sleep, false if sleep was suppressed.
+ * @return True if the device was sent to sleep, false if the device did not sleep.
*/
- private boolean goToSleepFromPowerButton(long eventTime, int flags) {
+ private boolean sleepDefaultDisplayFromPowerButton(long eventTime, int flags) {
// Before we actually go to sleep, we check the last wakeup reason.
// If the device very recently woke up from a gesture (like user lifting their device)
// then ignore the sleep instruction. This is because users have developed
@@ -1121,12 +1139,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, flags);
+ sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, flags);
return true;
}
- private void goToSleep(long eventTime, int reason, int flags) {
- mRequestedOrGoingToSleep = true;
+ private void sleepDefaultDisplay(long eventTime, int reason, int flags) {
+ mRequestedOrSleepingDefaultDisplay = true;
mPowerManager.goToSleep(eventTime, reason, flags);
}
@@ -1163,7 +1181,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Settings.Global.THEATER_MODE_ON, 1);
if (mGoToSleepOnButtonPressTheaterMode && interactive) {
- goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+ sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
+ 0);
}
}
break;
@@ -1271,7 +1290,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case SHORT_PRESS_SLEEP_GO_TO_SLEEP:
case SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME:
Slog.i(TAG, "sleepRelease() calling goToSleep(GO_TO_SLEEP_REASON_SLEEP_BUTTON)");
- goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
+ sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
break;
}
}
@@ -3686,7 +3705,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
if ((mEndcallBehavior
& Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
- goToSleep(event.getEventTime(),
+ sleepDefaultDisplay(event.getEventTime(),
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
isWakeKey = false;
}
@@ -3729,10 +3748,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Any activity on the power button stops the accessibility shortcut
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
+ final boolean isDefaultDisplayOn = Display.isOnState(mDefaultDisplay.getState());
+ final boolean interactiveAndOn = interactive && isDefaultDisplayOn;
if (down) {
- interceptPowerKeyDown(event, interactive);
+ interceptPowerKeyDown(event, interactiveAndOn);
} else {
- interceptPowerKeyUp(event, interactive, canceled);
+ interceptPowerKeyUp(event, interactiveAndOn, canceled);
}
break;
}
@@ -4242,8 +4263,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pmSleepReason)) + ")");
}
- mGoingToSleep = true;
- mRequestedOrGoingToSleep = true;
+ mDeviceGoingToSleep = true;
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onStartedGoingToSleep(pmSleepReason);
@@ -4262,8 +4282,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
MetricsLogger.histogram(mContext, "screen_timeout", mLockScreenTimeout / 1000);
- mGoingToSleep = false;
- mRequestedOrGoingToSleep = false;
+ mDeviceGoingToSleep = false;
mDefaultDisplayPolicy.setAwake(false);
// We must get this work done here because the power manager will drop
@@ -4413,6 +4432,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turned off...");
+ mRequestedOrSleepingDefaultDisplay = false;
updateScreenOffSleepToken(true);
mDefaultDisplayPolicy.screenTurnedOff();
synchronized (mLock) {
@@ -4479,6 +4499,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return;
}
+ mRequestedOrSleepingDefaultDisplay = true;
mWindowManagerFuncs.screenTurningOff(screenOffListener);
synchronized (mLock) {
if (mKeyguardDelegate != null) {
@@ -4564,7 +4585,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public boolean okToAnimate() {
- return mDefaultDisplayPolicy.isAwake() && !mGoingToSleep;
+ return mDefaultDisplayPolicy.isAwake() && !mDeviceGoingToSleep;
}
/** {@inheritDoc} */
@@ -4940,7 +4961,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mWindowManagerFuncs.lockDeviceNow();
break;
case LID_BEHAVIOR_SLEEP:
- goToSleep(SystemClock.uptimeMillis(),
+ sleepDefaultDisplay(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
break;
diff --git a/services/core/java/com/android/server/power/DisplayGroupPowerStateMapper.java b/services/core/java/com/android/server/power/DisplayGroupPowerStateMapper.java
new file mode 100644
index 000000000000..8ebeea3be48f
--- /dev/null
+++ b/services/core/java/com/android/server/power/DisplayGroupPowerStateMapper.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2020 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.power;
+
+import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
+import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
+
+import static com.android.server.power.DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener.DISPLAY_GROUP_ADDED;
+import static com.android.server.power.DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener.DISPLAY_GROUP_CHANGED;
+import static com.android.server.power.DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener.DISPLAY_GROUP_REMOVED;
+
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+import android.os.Handler;
+import android.os.PowerManagerInternal;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.display.DisplayGroup;
+
+/**
+ * Responsible for creating {@link DisplayPowerRequest}s and associating them with
+ * {@link com.android.server.display.DisplayGroup}s.
+ *
+ * Each {@link com.android.server.display.DisplayGroup} has a single {@link DisplayPowerRequest}
+ * which is used to request power state changes to every display in the group.
+ */
+public class DisplayGroupPowerStateMapper {
+
+ private static final String TAG = "DisplayPowerRequestMapper";
+
+ /** Lock obtained from {@link PowerManagerService}. */
+ private final Object mLock;
+
+ /** Listener to inform of changes to display groups. */
+ private final DisplayGroupPowerChangeListener mListener;
+
+ /** A mapping from DisplayGroup Id to DisplayGroup information. */
+ @GuardedBy("mLock")
+ private final SparseArray<DisplayGroupInfo> mDisplayGroupInfos = new SparseArray<>();
+
+ /** A cached array of DisplayGroup Ids. */
+ @GuardedBy("mLock")
+ private int[] mDisplayGroupIds;
+
+ private final DisplayManagerInternal.DisplayGroupListener mDisplayGroupListener =
+ new DisplayManagerInternal.DisplayGroupListener() {
+ @Override
+ public void onDisplayGroupAdded(int groupId) {
+ synchronized (mLock) {
+ if (mDisplayGroupInfos.contains(groupId)) {
+ Slog.e(TAG, "Tried to add already existing group:" + groupId);
+ return;
+ }
+ // For now, only the default group supports sandman.
+ final boolean supportsSandman = groupId == DisplayGroup.DEFAULT;
+ final DisplayGroupInfo displayGroupInfo = new DisplayGroupInfo(
+ new DisplayPowerRequest(),
+ getGlobalWakefulnessLocked(), /* ready= */ false,
+ supportsSandman);
+ mDisplayGroupInfos.append(groupId, displayGroupInfo);
+ mDisplayGroupIds = ArrayUtils.appendInt(mDisplayGroupIds, groupId);
+ mListener.onDisplayGroupEventLocked(DISPLAY_GROUP_ADDED, groupId);
+ }
+ }
+
+ @Override
+ public void onDisplayGroupRemoved(int groupId) {
+ synchronized (mLock) {
+ if (!mDisplayGroupInfos.contains(groupId)) {
+ Slog.e(TAG, "Tried to remove non-existent group:" + groupId);
+ return;
+ }
+ mDisplayGroupInfos.delete(groupId);
+ mDisplayGroupIds = ArrayUtils.removeInt(mDisplayGroupIds, groupId);
+ mListener.onDisplayGroupEventLocked(DISPLAY_GROUP_REMOVED, groupId);
+ }
+ }
+
+ @Override
+ public void onDisplayGroupChanged(int groupId) {
+ synchronized (mLock) {
+ mListener.onDisplayGroupEventLocked(DISPLAY_GROUP_CHANGED, groupId);
+ }
+ }
+ };
+
+ DisplayGroupPowerStateMapper(Object lock, DisplayManagerInternal displayManagerInternal,
+ DisplayGroupPowerChangeListener listener) {
+ mLock = lock;
+ mListener = listener;
+ displayManagerInternal.registerDisplayGroupListener(mDisplayGroupListener);
+
+ final DisplayGroupInfo displayGroupInfo = new DisplayGroupInfo(
+ new DisplayPowerRequest(), WAKEFULNESS_AWAKE, /* ready= */
+ false, /* supportsSandman= */ true);
+ mDisplayGroupInfos.append(DisplayGroup.DEFAULT, displayGroupInfo);
+ mDisplayGroupIds = new int[]{DisplayGroup.DEFAULT};
+ }
+
+ DisplayPowerRequest getPowerRequestLocked(int groupId) {
+ return mDisplayGroupInfos.get(groupId).displayPowerRequest;
+ }
+
+ int[] getDisplayGroupIdsLocked() {
+ return mDisplayGroupIds;
+ }
+
+ int getWakefulnessLocked(int groupId) {
+ return mDisplayGroupInfos.get(groupId).wakefulness;
+ }
+
+ void setLastPowerOnTimeLocked(int groupId, long eventTime) {
+ mDisplayGroupInfos.get(groupId).lastPowerOnTime = eventTime;
+ }
+
+ long getLastPowerOnTimeLocked(int groupId) {
+ return mDisplayGroupInfos.get(groupId).lastPowerOnTime;
+ }
+
+ /**
+ * Returns the amalgamated wakefulness of all {@link DisplayGroup DisplayGroups}.
+ *
+ * <p>This will be the highest wakeful state of all {@link DisplayGroup DisplayGroups}; ordered
+ * from highest to lowest:
+ * <ol>
+ * <li>{@link PowerManagerInternal#WAKEFULNESS_AWAKE}
+ * <li>{@link PowerManagerInternal#WAKEFULNESS_DREAMING}
+ * <li>{@link PowerManagerInternal#WAKEFULNESS_DOZING}
+ * <li>{@link PowerManagerInternal#WAKEFULNESS_ASLEEP}
+ * </ol>
+ */
+ int getGlobalWakefulnessLocked() {
+ final int size = mDisplayGroupInfos.size();
+ int deviceWakefulness = WAKEFULNESS_ASLEEP;
+ for (int i = 0; i < size; i++) {
+ final int wakefulness = mDisplayGroupInfos.valueAt(i).wakefulness;
+ if (wakefulness == WAKEFULNESS_AWAKE) {
+ return WAKEFULNESS_AWAKE;
+ } else if (wakefulness == WAKEFULNESS_DREAMING
+ && (deviceWakefulness == WAKEFULNESS_ASLEEP
+ || deviceWakefulness == WAKEFULNESS_DOZING)) {
+ deviceWakefulness = WAKEFULNESS_DREAMING;
+ } else if (wakefulness == WAKEFULNESS_DOZING
+ && deviceWakefulness == WAKEFULNESS_ASLEEP) {
+ deviceWakefulness = WAKEFULNESS_DOZING;
+ }
+ }
+
+ return deviceWakefulness;
+ }
+
+ /**
+ * Sets the {@code wakefulness} value for the {@link DisplayGroup} specified by the provided
+ * {@code groupId}.
+ *
+ * @return {@code true} if the wakefulness value was changed; {@code false} otherwise.
+ */
+ boolean setWakefulnessLocked(int groupId, int wakefulness) {
+ final DisplayGroupInfo displayGroupInfo = mDisplayGroupInfos.get(groupId);
+ if (displayGroupInfo.wakefulness != wakefulness) {
+ displayGroupInfo.wakefulness = wakefulness;
+ return true;
+ }
+
+ return false;
+ }
+
+ boolean isSandmanSummoned(int groupId) {
+ return mDisplayGroupInfos.get(groupId).sandmanSummoned;
+ }
+
+ boolean isSandmanSupported(int groupId) {
+ return mDisplayGroupInfos.get(groupId).supportsSandman;
+ }
+
+ /**
+ * Sets whether or not the sandman is summoned for the given {@code groupId}.
+ *
+ * @param groupId Signifies the DisplayGroup for which to summon or unsummon the
+ * sandman.
+ * @param sandmanSummoned {@code true} to summon the sandman; {@code false} to unsummon.
+ */
+ void setSandmanSummoned(int groupId, boolean sandmanSummoned) {
+ final DisplayGroupInfo displayGroupInfo = mDisplayGroupInfos.get(groupId);
+ displayGroupInfo.sandmanSummoned = displayGroupInfo.supportsSandman && sandmanSummoned;
+ }
+
+ /**
+ * Returns {@code true} if every display in the specified group has its requested state matching
+ * its actual state.
+ *
+ * @param groupId The identifier for the display group to check for readiness.
+ */
+ boolean isReady(int groupId) {
+ return mDisplayGroupInfos.get(groupId).ready;
+ }
+
+ /** Returns {@code true} if every display has its requested state matching its actual state. */
+ boolean areAllDisplaysReadyLocked() {
+ final int size = mDisplayGroupInfos.size();
+ for (int i = 0; i < size; i++) {
+ if (!mDisplayGroupInfos.valueAt(i).ready) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Sets whether the displays specified by the provided {@code groupId} are all ready.
+ *
+ * <p>A display is ready if its reported
+ * {@link DisplayManagerInternal.DisplayPowerCallbacks#onStateChanged() actual state} matches
+ * its {@link DisplayManagerInternal#requestPowerState requested state}.
+ *
+ * @param groupId The identifier for the display group.
+ * @param ready {@code true} if every display in the group is ready; otherwise {@code false}.
+ * @return {@code true} if the ready state changed; otherwise {@code false}.
+ */
+ boolean setDisplayGroupReadyLocked(int groupId, boolean ready) {
+ final DisplayGroupInfo displayGroupInfo = mDisplayGroupInfos.get(groupId);
+ if (displayGroupInfo.ready != ready) {
+ displayGroupInfo.ready = ready;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Interface through which an interested party may be informed of {@link DisplayGroup} events.
+ */
+ interface DisplayGroupPowerChangeListener {
+ int DISPLAY_GROUP_ADDED = 0;
+ int DISPLAY_GROUP_REMOVED = 1;
+ int DISPLAY_GROUP_CHANGED = 2;
+
+ void onDisplayGroupEventLocked(int event, int groupId);
+ }
+
+ private static final class DisplayGroupInfo {
+ final DisplayPowerRequest displayPowerRequest;
+ int wakefulness;
+ boolean ready;
+ long lastPowerOnTime;
+ boolean sandmanSummoned;
+
+ /** {@code true} if this DisplayGroup supports dreaming; otherwise {@code false}. */
+ boolean supportsSandman;
+
+ DisplayGroupInfo(DisplayPowerRequest displayPowerRequest, int wakefulness, boolean ready,
+ boolean supportsSandman) {
+ this.displayPowerRequest = displayPowerRequest;
+ this.wakefulness = wakefulness;
+ this.ready = ready;
+ this.supportsSandman = supportsSandman;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/power/DisplayPowerRequestMapper.java b/services/core/java/com/android/server/power/DisplayPowerRequestMapper.java
deleted file mode 100644
index 6477552eb550..000000000000
--- a/services/core/java/com/android/server/power/DisplayPowerRequestMapper.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2020 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.power;
-
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManagerInternal;
-import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
-import android.os.Handler;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.view.Display;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.server.display.DisplayGroup;
-
-/**
- * Responsible for creating {@link DisplayPowerRequest}s and associating them with
- * {@link com.android.server.display.DisplayGroup}s.
- *
- * Each {@link com.android.server.display.DisplayGroup} has a single {@link DisplayPowerRequest}
- * which is used to request power state changes to every display in the group.
- */
-class DisplayPowerRequestMapper {
-
- private final Object mLock = new Object();
-
- /** A mapping from LogicalDisplay Id to DisplayGroup Id. */
- @GuardedBy("mLock")
- private final SparseIntArray mDisplayGroupIds = new SparseIntArray();
-
- /** A mapping from DisplayGroup Id to DisplayPowerRequest. */
- @GuardedBy("mLock")
- private final SparseArray<DisplayPowerRequest> mDisplayPowerRequests = new SparseArray<>();
-
- private final DisplayManagerInternal mDisplayManagerInternal;
-
- private final DisplayManager.DisplayListener mDisplayListener =
- new DisplayManager.DisplayListener() {
-
- @Override
- public void onDisplayAdded(int displayId) {
- synchronized (mLock) {
- if (mDisplayGroupIds.indexOfKey(displayId) >= 0) {
- return;
- }
- final int displayGroupId = mDisplayManagerInternal.getDisplayGroupId(
- displayId);
- if (!mDisplayPowerRequests.contains(displayGroupId)) {
- // A new DisplayGroup was created; create a new DisplayPowerRequest.
- mDisplayPowerRequests.append(displayGroupId, new DisplayPowerRequest());
- }
- mDisplayGroupIds.append(displayId, displayGroupId);
- }
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- synchronized (mLock) {
- final int index = mDisplayGroupIds.indexOfKey(displayId);
- if (index < 0) {
- return;
- }
- final int displayGroupId = mDisplayGroupIds.valueAt(index);
- mDisplayGroupIds.removeAt(index);
-
- if (mDisplayGroupIds.indexOfValue(displayGroupId) < 0) {
- // The DisplayGroup no longer exists; delete the DisplayPowerRequest.
- mDisplayPowerRequests.delete(displayGroupId);
- }
- }
- }
-
- @Override
- public void onDisplayChanged(int displayId) {
- synchronized (mLock) {
- final int newDisplayGroupId = mDisplayManagerInternal.getDisplayGroupId(
- displayId);
- final int oldDisplayGroupId = mDisplayGroupIds.get(displayId);
-
- if (!mDisplayPowerRequests.contains(newDisplayGroupId)) {
- // A new DisplayGroup was created; create a new DisplayPowerRequest.
- mDisplayPowerRequests.append(newDisplayGroupId,
- new DisplayPowerRequest());
- }
- mDisplayGroupIds.put(displayId, newDisplayGroupId);
-
- if (mDisplayGroupIds.indexOfValue(oldDisplayGroupId) < 0) {
- // The DisplayGroup no longer exists; delete the DisplayPowerRequest.
- mDisplayPowerRequests.delete(oldDisplayGroupId);
- }
- }
- }
- };
-
- DisplayPowerRequestMapper(DisplayManager displayManager,
- DisplayManagerInternal displayManagerInternal, Handler handler) {
- mDisplayManagerInternal = displayManagerInternal;
- displayManager.registerDisplayListener(mDisplayListener, handler);
- mDisplayPowerRequests.append(DisplayGroup.DEFAULT, new DisplayPowerRequest());
- mDisplayGroupIds.append(Display.DEFAULT_DISPLAY, DisplayGroup.DEFAULT);
- }
-
- DisplayPowerRequest get(int displayId) {
- synchronized (mLock) {
- return mDisplayPowerRequests.get(mDisplayGroupIds.get(displayId));
- }
- }
-}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 084dc32e8ad7..f14ff3cc3268 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -18,6 +18,10 @@ package com.android.server.power;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT;
+import static android.os.PowerManager.GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED;
+import static android.os.PowerManager.GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF;
+import static android.os.PowerManager.WAKE_REASON_DISPLAY_GROUP_ADDED;
+import static android.os.PowerManager.WAKE_REASON_DISPLAY_GROUP_TURNED_ON;
import static android.os.PowerManagerInternal.MODE_DEVICE_IDLE;
import static android.os.PowerManagerInternal.MODE_DISPLAY_INACTIVE;
import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
@@ -42,7 +46,6 @@ import android.database.ContentObserver;
import android.hardware.SensorManager;
import android.hardware.SystemSensorManager;
import android.hardware.display.AmbientDisplayConfiguration;
-import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.hardware.power.Boost;
@@ -107,6 +110,7 @@ import com.android.server.UiThread;
import com.android.server.UserspaceRebootLogger;
import com.android.server.Watchdog;
import com.android.server.am.BatteryStatsService;
+import com.android.server.display.DisplayGroup;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight;
import com.android.server.policy.WindowManagerPolicy;
@@ -176,6 +180,8 @@ public final class PowerManagerService extends SystemService
private static final int DIRTY_VR_MODE_CHANGED = 1 << 13;
// Dirty bit: attentive timer may have timed out
private static final int DIRTY_ATTENTIVE = 1 << 14;
+ // Dirty bit: display group power state has changed
+ private static final int DIRTY_DISPLAY_GROUP_POWER_UPDATED = 1 << 15;
// Summarizes the state of all active wakelocks.
private static final int WAKE_LOCK_CPU = 1 << 0;
@@ -297,10 +303,6 @@ public final class PowerManagerService extends SystemService
private int mWakefulnessRaw;
private boolean mWakefulnessChanging;
- // True if the sandman has just been summoned for the first time since entering the
- // dreaming or dozing state. Indicates whether a new dream should begin.
- private boolean mSandmanSummoned;
-
// True if MSG_SANDMAN has been scheduled.
private boolean mSandmanScheduled;
@@ -351,11 +353,7 @@ public final class PowerManagerService extends SystemService
// Manages the desired power state of displays. The actual state may lag behind the
// requested because it is updated asynchronously by the display power controller.
- private DisplayPowerRequestMapper mDisplayPowerRequestMapper;
-
- // True if the display power state has been fully applied, which means the display
- // is actually on or actually off or whatever was requested.
- private boolean mDisplayReady;
+ private DisplayGroupPowerStateMapper mDisplayGroupPowerStateMapper;
// The suspend blocker used to keep the CPU alive when an application has acquired
// a wake lock.
@@ -625,6 +623,39 @@ public final class PowerManagerService extends SystemService
// but the DreamService has not yet been told to start (it's an async process).
private boolean mDozeStartInProgress;
+ private final class DisplayGroupPowerChangeListener implements
+ DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener {
+ @Override
+ public void onDisplayGroupEventLocked(int event, int groupId) {
+ final int oldWakefulness = getWakefulnessLocked();
+ final int newWakefulness = mDisplayGroupPowerStateMapper.getGlobalWakefulnessLocked();
+ if (oldWakefulness != newWakefulness) {
+ final int reason;
+ switch (newWakefulness) {
+ case WAKEFULNESS_AWAKE:
+ reason = event == DISPLAY_GROUP_ADDED ? WAKE_REASON_DISPLAY_GROUP_ADDED
+ : WAKE_REASON_DISPLAY_GROUP_TURNED_ON;
+ break;
+ case WAKEFULNESS_DOZING:
+ reason = event == DISPLAY_GROUP_REMOVED
+ ? GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED
+ : GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF;
+ break;
+ default:
+ reason = 0;
+ }
+
+ setGlobalWakefulnessLocked(
+ mDisplayGroupPowerStateMapper.getGlobalWakefulnessLocked(),
+ mClock.uptimeMillis(), reason, Process.SYSTEM_UID, Process.SYSTEM_UID,
+ mContext.getOpPackageName(), "groupId: " + groupId);
+ }
+
+ mDirty |= DIRTY_DISPLAY_GROUP_POWER_UPDATED;
+ updatePowerStateLocked();
+ }
+ }
+
private final class ForegroundProfileObserver extends SynchronousUserSwitchObserver {
@Override
public void onUserSwitching(@UserIdInt int newUserId) throws RemoteException {
@@ -868,6 +899,12 @@ public final class PowerManagerService extends SystemService
void invalidateIsInteractiveCaches() {
PowerManager.invalidateIsInteractiveCaches();
}
+
+ DisplayGroupPowerStateMapper createDisplayPowerRequestMapper(Object lock,
+ DisplayManagerInternal displayManagerInternal,
+ DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener listener) {
+ return new DisplayGroupPowerStateMapper(lock, displayManagerInternal, listener);
+ }
}
final Constants mConstants;
@@ -1037,7 +1074,7 @@ public final class PowerManagerService extends SystemService
now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
if (sQuiescent) {
- goToSleepNoUpdateLocked(mClock.uptimeMillis(),
+ sleepDisplayGroupNoUpdateLocked(DisplayGroup.DEFAULT, mClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_QUIESCENT,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
}
@@ -1055,8 +1092,8 @@ public final class PowerManagerService extends SystemService
mPolicy = getLocalService(WindowManagerPolicy.class);
mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);
mAttentionDetector.systemReady(mContext);
- mDisplayPowerRequestMapper = new DisplayPowerRequestMapper(mContext.getSystemService(
- DisplayManager.class), mDisplayManagerInternal, mHandler);
+ mDisplayGroupPowerStateMapper = mInjector.createDisplayPowerRequestMapper(mLock,
+ mDisplayManagerInternal, new DisplayGroupPowerChangeListener());
SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
@@ -1373,9 +1410,11 @@ public final class PowerManagerService extends SystemService
opPackageName = wakeLock.mPackageName;
opUid = wakeLock.mOwnerUid;
}
- wakeUpNoUpdateLocked(mClock.uptimeMillis(),
- PowerManager.WAKE_REASON_APPLICATION, wakeLock.mTag,
- opUid, opPackageName, opUid);
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ wakeDisplayGroupNoUpdateLocked(id, mClock.uptimeMillis(),
+ PowerManager.WAKE_REASON_APPLICATION, wakeLock.mTag,
+ opUid, opPackageName, opUid);
+ }
}
}
@@ -1664,74 +1703,69 @@ public final class PowerManagerService extends SystemService
}
}
- private void wakeUpInternal(long eventTime, @WakeReason int reason, String details, int uid,
- String opPackageName, int opUid) {
+ private void wakeDisplayGroup(int groupId, long eventTime, @WakeReason int reason,
+ String details, int uid, String opPackageName, int opUid) {
synchronized (mLock) {
- if (wakeUpNoUpdateLocked(eventTime, reason, details, uid, opPackageName, opUid)) {
+ if (wakeDisplayGroupNoUpdateLocked(groupId, eventTime, reason, details, uid,
+ opPackageName, opUid)) {
updatePowerStateLocked();
}
}
}
- private boolean wakeUpNoUpdateLocked(long eventTime, @WakeReason int reason, String details,
- int reasonUid, String opPackageName, int opUid) {
+ private boolean wakeDisplayGroupNoUpdateLocked(int groupId, long eventTime,
+ @WakeReason int reason, String details, int uid, String opPackageName, int opUid) {
if (DEBUG_SPEW) {
- Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid);
+ Slog.d(TAG, "wakeDisplayGroupNoUpdateLocked: eventTime=" + eventTime
+ +", groupId=" + groupId + ", uid=" + uid);
}
- if (eventTime < mLastSleepTime || getWakefulnessLocked() == WAKEFULNESS_AWAKE
- || mForceSuspendActive || !mSystemReady) {
+ if (eventTime < mLastSleepTime || mForceSuspendActive || !mSystemReady) {
return false;
}
- Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);
+ final int currentState = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
+ if (currentState == WAKEFULNESS_AWAKE) {
+ return false;
+ }
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "powerOnDisplay");
try {
- Slog.i(TAG, "Waking up from "
- + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
- + " (uid=" + reasonUid
+ Slog.i(TAG, "Powering on display group from"
+ + PowerManagerInternal.wakefulnessToString(currentState)
+ + " (groupId=" + groupId
+ + ", uid=" + uid
+ ", reason=" + PowerManager.wakeReasonToString(reason)
+ ", details=" + details
+ ")...");
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, groupId);
- mLastWakeTime = eventTime;
- mLastWakeReason = reason;
- setWakefulnessLocked(WAKEFULNESS_AWAKE, reason, eventTime);
-
- mNotifier.onWakeUp(reason, details, reasonUid, opPackageName, opUid);
- userActivityNoUpdateLocked(
- eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
-
- if (sQuiescent) {
- mDirty |= DIRTY_QUIESCENT;
- }
+ setWakefulnessLocked(groupId, WAKEFULNESS_AWAKE, eventTime, uid, reason, opUid,
+ opPackageName, details);
+ mDisplayGroupPowerStateMapper.setLastPowerOnTimeLocked(groupId, eventTime);
+ mDirty |= DIRTY_DISPLAY_GROUP_POWER_UPDATED;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
+
return true;
}
- private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
+ private void sleepDisplayGroup(int groupId, long eventTime, int reason, int flags,
+ int uid) {
synchronized (mLock) {
- if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
+ if (sleepDisplayGroupNoUpdateLocked(groupId, eventTime, reason, flags, uid)) {
updatePowerStateLocked();
}
}
}
- /**
- * Puts the system in doze.
- *
- * This method is called goToSleep for historical reasons but actually attempts to DOZE,
- * and only tucks itself in to SLEEP if requested with the flag
- * {@link PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE}.
- */
- @SuppressWarnings("deprecation")
- private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
+ private boolean sleepDisplayGroupNoUpdateLocked(int groupId, long eventTime, int reason,
+ int flags, int uid) {
if (DEBUG_SPEW) {
- Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime
- + ", reason=" + reason + ", flags=" + flags + ", uid=" + uid);
+ Slog.d(TAG, "powerOffDisplayGroupNoUpdateLocked: eventTime=" + eventTime
+ + ", groupId=" + groupId + ", reason=" + reason + ", flags=" + flags
+ + ", uid=" + uid);
}
if (eventTime < mLastWakeTime
@@ -1742,55 +1776,44 @@ public final class PowerManagerService extends SystemService
return false;
}
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep");
+ final int wakefulness = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
+ if (!PowerManagerInternal.isInteractive(wakefulness)) {
+ return false;
+ }
+
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "powerOffDisplay");
try {
reason = Math.min(PowerManager.GO_TO_SLEEP_REASON_MAX,
Math.max(reason, PowerManager.GO_TO_SLEEP_REASON_MIN));
- Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason)
- + " (uid " + uid + ")...");
-
- mLastSleepTime = eventTime;
- mLastSleepReason = reason;
- mSandmanSummoned = true;
- mDozeStartInProgress = true;
- setWakefulnessLocked(WAKEFULNESS_DOZING, reason, eventTime);
+ Slog.i(TAG, "Powering off display group due to "
+ + PowerManager.sleepReasonToString(reason) + " (groupId= " + groupId
+ + ", uid= " + uid + ")...");
- // Report the number of wake locks that will be cleared by going to sleep.
- int numWakeLocksCleared = 0;
- final int numWakeLocks = mWakeLocks.size();
- for (int i = 0; i < numWakeLocks; i++) {
- final WakeLock wakeLock = mWakeLocks.get(i);
- switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
- case PowerManager.FULL_WAKE_LOCK:
- case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
- case PowerManager.SCREEN_DIM_WAKE_LOCK:
- numWakeLocksCleared += 1;
- break;
- }
- }
- EventLogTags.writePowerSleepRequested(numWakeLocksCleared);
-
- // Skip dozing if requested.
+ mDisplayGroupPowerStateMapper.setSandmanSummoned(groupId, true);
+ setWakefulnessLocked(groupId, WAKEFULNESS_DOZING, eventTime, uid, reason,
+ /* opUid= */ 0, /* opPackageName= */ null, /* details= */ null);
if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
- reallyGoToSleepNoUpdateLocked(eventTime, uid);
+ reallySleepDisplayGroupNoUpdateLocked(groupId, eventTime, uid);
}
+ mDirty |= DIRTY_DISPLAY_GROUP_POWER_UPDATED;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
- private void napInternal(long eventTime, int uid) {
+ private void dreamDisplayGroup(int groupId, long eventTime, int uid) {
synchronized (mLock) {
- if (napNoUpdateLocked(eventTime, uid)) {
+ if (dreamDisplayGroupNoUpdateLocked(groupId, eventTime, uid)) {
updatePowerStateLocked();
}
}
}
- private boolean napNoUpdateLocked(long eventTime, int uid) {
+ private boolean dreamDisplayGroupNoUpdateLocked(int groupId, long eventTime, int uid) {
if (DEBUG_SPEW) {
- Slog.d(TAG, "napNoUpdateLocked: eventTime=" + eventTime + ", uid=" + uid);
+ Slog.d(TAG, "dreamDisplayGroupNoUpdateLocked: eventTime=" + eventTime
+ + ", uid=" + uid);
}
if (eventTime < mLastWakeTime || getWakefulnessLocked() != WAKEFULNESS_AWAKE
@@ -1798,36 +1821,42 @@ public final class PowerManagerService extends SystemService
return false;
}
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "nap");
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "napDisplayGroup");
try {
- Slog.i(TAG, "Nap time (uid " + uid +")...");
+ Slog.i(TAG, "Napping display group (groupId=" + groupId + ", uid=" + uid + ")...");
+
+ mDisplayGroupPowerStateMapper.setSandmanSummoned(groupId, true);
+ setWakefulnessLocked(groupId, WAKEFULNESS_DREAMING, eventTime, uid, /* reason= */
+ 0, /* opUid= */ 0, /* opPackageName= */ null, /* details= */ null);
+ mDirty |= DIRTY_DISPLAY_GROUP_POWER_UPDATED;
- mSandmanSummoned = true;
- setWakefulnessLocked(WAKEFULNESS_DREAMING, 0, eventTime);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
- // Done dozing, drop everything and go to sleep.
- private boolean reallyGoToSleepNoUpdateLocked(long eventTime, int uid) {
+ private boolean reallySleepDisplayGroupNoUpdateLocked(int groupId, long eventTime, int uid) {
if (DEBUG_SPEW) {
- Slog.d(TAG, "reallyGoToSleepNoUpdateLocked: eventTime=" + eventTime
+ Slog.d(TAG, "reallySleepDisplayGroupNoUpdateLocked: eventTime=" + eventTime
+ ", uid=" + uid);
}
if (eventTime < mLastWakeTime || getWakefulnessLocked() == WAKEFULNESS_ASLEEP
- || !mBootCompleted || !mSystemReady) {
+ || !mBootCompleted || !mSystemReady
+ || mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId)
+ == WAKEFULNESS_ASLEEP) {
return false;
}
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "reallyGoToSleep");
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "reallySleepDisplayGroup");
try {
- Slog.i(TAG, "Sleeping (uid " + uid +")...");
+ Slog.i(TAG, "Sleeping display group (groupId=" + groupId + ", uid=" + uid +")...");
- setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
- eventTime);
+ setWakefulnessLocked(groupId, WAKEFULNESS_ASLEEP, eventTime, uid,
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, /* opUid= */ 0,
+ /* opPackageName= */ null, /* details= */ null);
+ mDirty |= DIRTY_DISPLAY_GROUP_POWER_UPDATED;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
@@ -1835,8 +1864,62 @@ public final class PowerManagerService extends SystemService
}
@VisibleForTesting
- void setWakefulnessLocked(int wakefulness, int reason, long eventTime) {
- if (getWakefulnessLocked() != wakefulness) {
+ void setWakefulnessLocked(int groupId, int wakefulness, long eventTime, int uid, int reason,
+ int opUid, String opPackageName, String details) {
+ if (mDisplayGroupPowerStateMapper.setWakefulnessLocked(groupId, wakefulness)) {
+ setGlobalWakefulnessLocked(mDisplayGroupPowerStateMapper.getGlobalWakefulnessLocked(),
+ eventTime, reason, uid, opUid, opPackageName, details);
+ }
+ }
+
+ private void setGlobalWakefulnessLocked(int wakefulness, long eventTime, int reason, int uid,
+ int opUid, String opPackageName, String details) {
+ if (getWakefulnessLocked() == wakefulness) {
+ return;
+ }
+
+ // Phase 1: Handle pre-wakefulness change bookkeeping.
+ final String traceMethodName;
+ switch (wakefulness) {
+ case WAKEFULNESS_ASLEEP:
+ traceMethodName = "reallyGoToSleep";
+ Slog.i(TAG, "Sleeping (uid " + uid + ")...");
+ break;
+
+ case WAKEFULNESS_AWAKE:
+ traceMethodName = "wakeUp";
+ Slog.i(TAG, "Waking up from "
+ + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
+ + " (uid=" + uid
+ + ", reason=" + PowerManager.wakeReasonToString(reason)
+ + ", details=" + details
+ + ")...");
+ mLastWakeTime = eventTime;
+ mLastWakeReason = reason;
+ break;
+
+ case WAKEFULNESS_DREAMING:
+ traceMethodName = "nap";
+ Slog.i(TAG, "Nap time (uid " + uid + ")...");
+ break;
+
+ case WAKEFULNESS_DOZING:
+ traceMethodName = "goToSleep";
+ Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason)
+ + " (uid " + uid + ")...");
+
+ mLastSleepTime = eventTime;
+ mLastSleepReason = reason;
+ mDozeStartInProgress = true;
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unexpected wakefulness: " + wakefulness);
+ }
+
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, traceMethodName);
+ try {
+ // Phase 2: Handle wakefulness change and bookkeeping.
// Under lock, invalidate before set ensures caches won't return stale values.
mInjector.invalidateIsInteractiveCaches();
mWakefulnessRaw = wakefulness;
@@ -1850,6 +1933,37 @@ public final class PowerManagerService extends SystemService
mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
}
mAttentionDetector.onWakefulnessChangeStarted(wakefulness);
+
+ // Phase 3: Handle post-wakefulness change bookkeeping.
+ switch (wakefulness) {
+ case WAKEFULNESS_AWAKE:
+ mNotifier.onWakeUp(reason, details, uid, opPackageName, opUid);
+ userActivityNoUpdateLocked(
+ eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
+ if (sQuiescent) {
+ mDirty |= DIRTY_QUIESCENT;
+ }
+ break;
+
+ case WAKEFULNESS_DOZING:
+ // Report the number of wake locks that will be cleared by going to sleep.
+ int numWakeLocksCleared = 0;
+ final int numWakeLocks = mWakeLocks.size();
+ for (int i = 0; i < numWakeLocks; i++) {
+ final WakeLock wakeLock = mWakeLocks.get(i);
+ switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
+ case PowerManager.FULL_WAKE_LOCK:
+ case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
+ case PowerManager.SCREEN_DIM_WAKE_LOCK:
+ numWakeLocksCleared += 1;
+ break;
+ }
+ }
+ EventLogTags.writePowerSleepRequested(numWakeLocksCleared);
+ break;
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
@@ -1872,7 +1986,7 @@ public final class PowerManagerService extends SystemService
}
private void finishWakefulnessChangeIfNeededLocked() {
- if (mWakefulnessChanging && mDisplayReady) {
+ if (mWakefulnessChanging && mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) {
if (getWakefulnessLocked() == WAKEFULNESS_DOZING
&& (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) {
return; // wait until dream has enabled dozing
@@ -1884,13 +1998,6 @@ public final class PowerManagerService extends SystemService
|| getWakefulnessLocked() == WAKEFULNESS_ASLEEP) {
logSleepTimeoutRecapturedLocked();
}
- if (getWakefulnessLocked() == WAKEFULNESS_AWAKE) {
- Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);
- final int latencyMs = (int) (mClock.uptimeMillis() - mLastWakeTime);
- if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) {
- Slog.w(TAG, "Screen on took " + latencyMs + " ms");
- }
- }
mWakefulnessChanging = false;
mNotifier.onWakefulnessChangeFinished();
}
@@ -1989,7 +2096,6 @@ public final class PowerManagerService extends SystemService
if ((dirty & DIRTY_BATTERY_STATE) != 0) {
final boolean wasPowered = mIsPowered;
final int oldPlugType = mPlugType;
- final boolean oldLevelLow = mBatteryLevelLow;
mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
mPlugType = mBatteryManagerInternal.getPlugType();
mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
@@ -2018,7 +2124,8 @@ public final class PowerManagerService extends SystemService
final long now = mClock.uptimeMillis();
if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,
dockedOnWirelessCharger)) {
- wakeUpNoUpdateLocked(now, PowerManager.WAKE_REASON_PLUGGED_IN,
+ wakeDisplayGroupNoUpdateLocked(DisplayGroup.DEFAULT, now,
+ PowerManager.WAKE_REASON_PLUGGED_IN,
"android.server.power:PLUGGED:" + mIsPowered, Process.SYSTEM_UID,
mContext.getOpPackageName(), Process.SYSTEM_UID);
}
@@ -2300,7 +2407,8 @@ public final class PowerManagerService extends SystemService
nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
if (now < nextTimeout) {
final DisplayPowerRequest displayPowerRequest =
- mDisplayPowerRequestMapper.get(Display.DEFAULT_DISPLAY);
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(
+ DisplayGroup.DEFAULT);
if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT
|| displayPowerRequest.policy == DisplayPowerRequest.POLICY_VR) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
@@ -2555,13 +2663,23 @@ public final class PowerManagerService extends SystemService
}
final long time = mClock.uptimeMillis();
if (isAttentiveTimeoutExpired(time)) {
- changed = goToSleepNoUpdateLocked(time, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
- PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
+ // TODO (b/175764389): Support per-display timeouts.
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ changed = sleepDisplayGroupNoUpdateLocked(id, time,
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
+ }
} else if (shouldNapAtBedTimeLocked()) {
- changed = napNoUpdateLocked(time, Process.SYSTEM_UID);
+ // TODO (b/175764389): Support per-display timeouts.
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ changed = dreamDisplayGroupNoUpdateLocked(id, time, Process.SYSTEM_UID);
+ }
} else {
- changed = goToSleepNoUpdateLocked(time,
- PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
+ // TODO (b/175764389): Support per-display timeouts.
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ changed = sleepDisplayGroupNoUpdateLocked(id, time,
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
+ }
}
}
}
@@ -2644,7 +2762,7 @@ public final class PowerManagerService extends SystemService
| DIRTY_STAY_ON
| DIRTY_PROXIMITY_POSITIVE
| DIRTY_BATTERY_STATE)) != 0 || displayBecameReady) {
- if (mDisplayReady) {
+ if (mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) {
scheduleSandmanLocked();
}
}
@@ -2659,6 +2777,14 @@ public final class PowerManagerService extends SystemService
}
}
+ private void handleSandman() {
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ if (mDisplayGroupPowerStateMapper.isSandmanSupported(id)) {
+ handleSandman(id);
+ }
+ }
+ }
+
/**
* Called when the device enters or exits a dreaming or dozing state.
*
@@ -2666,16 +2792,18 @@ public final class PowerManagerService extends SystemService
* the dream and we don't want to hold our lock while doing so. There is a risk that
* the device will wake or go to sleep in the meantime so we have to handle that case.
*/
- private void handleSandman() { // runs on handler thread
+ private void handleSandman(int groupId) { // runs on handler thread
// Handle preconditions.
final boolean startDreaming;
final int wakefulness;
synchronized (mLock) {
mSandmanScheduled = false;
+ // TODO (b/175764708): Support per-display doze.
wakefulness = getWakefulnessLocked();
- if (mSandmanSummoned && mDisplayReady) {
- startDreaming = canDreamLocked() || canDozeLocked();
- mSandmanSummoned = false;
+ if (mDisplayGroupPowerStateMapper.isSandmanSummoned(groupId)
+ && mDisplayGroupPowerStateMapper.isReady(groupId)) {
+ startDreaming = canDreamLocked(groupId) || canDozeLocked();
+ mDisplayGroupPowerStateMapper.setSandmanSummoned(groupId, false);
} else {
startDreaming = false;
}
@@ -2714,14 +2842,15 @@ public final class PowerManagerService extends SystemService
// If preconditions changed, wait for the next iteration to determine
// whether the dream should continue (or be restarted).
- if (mSandmanSummoned || getWakefulnessLocked() != wakefulness) {
+ if (mDisplayGroupPowerStateMapper.isSandmanSummoned(groupId)
+ || mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId) != wakefulness) {
return; // wait for next cycle
}
// Determine whether the dream should continue.
long now = mClock.uptimeMillis();
if (wakefulness == WAKEFULNESS_DREAMING) {
- if (isDreaming && canDreamLocked()) {
+ if (isDreaming && canDreamLocked(groupId)) {
if (mDreamsBatteryLevelDrainCutoffConfig >= 0
&& mBatteryLevel < mBatteryLevelWhenDreamStarted
- mDreamsBatteryLevelDrainCutoffConfig
@@ -2741,16 +2870,13 @@ public final class PowerManagerService extends SystemService
// Dream has ended or will be stopped. Update the power state.
if (isItBedTimeYetLocked()) {
- int flags = 0;
- if (isAttentiveTimeoutExpired(now)) {
- flags |= PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE;
- }
- goToSleepNoUpdateLocked(now, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, flags,
- Process.SYSTEM_UID);
+ final int flags = isAttentiveTimeoutExpired(now)
+ ? PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE : 0;
+ sleepDisplayGroupNoUpdateLocked(groupId, now,
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, flags, Process.SYSTEM_UID);
updatePowerStateLocked();
} else {
- wakeUpNoUpdateLocked(now,
- PowerManager.WAKE_REASON_UNKNOWN,
+ wakeDisplayGroupNoUpdateLocked(groupId, now, PowerManager.WAKE_REASON_UNKNOWN,
"android.server.power:DREAM_FINISHED", Process.SYSTEM_UID,
mContext.getOpPackageName(), Process.SYSTEM_UID);
updatePowerStateLocked();
@@ -2761,7 +2887,7 @@ public final class PowerManagerService extends SystemService
}
// Doze has ended or will be stopped. Update the power state.
- reallyGoToSleepNoUpdateLocked(now, Process.SYSTEM_UID);
+ reallySleepDisplayGroupNoUpdateLocked(groupId, now, Process.SYSTEM_UID);
updatePowerStateLocked();
}
}
@@ -2773,11 +2899,11 @@ public final class PowerManagerService extends SystemService
}
/**
- * Returns true if the device is allowed to dream in its current state.
+ * Returns true if the {@code groupId} is allowed to dream in its current state.
*/
- private boolean canDreamLocked() {
+ private boolean canDreamLocked(int groupId) {
final DisplayPowerRequest displayPowerRequest =
- mDisplayPowerRequestMapper.get(Display.DEFAULT_DISPLAY);
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(groupId);
if (getWakefulnessLocked() != WAKEFULNESS_DREAMING
|| !mDreamsSupportedConfig
|| !mDreamsEnabledSetting
@@ -2815,91 +2941,113 @@ public final class PowerManagerService extends SystemService
/**
* Updates the display power state asynchronously.
- * When the update is finished, mDisplayReady will be set to true. The display
- * controller posts a message to tell us when the actual display power state
+ * When the update is finished, the ready state of the displays will be updated. The display
+ * controllers post a message to tell us when the actual display power state
* has been updated so we come back here to double-check and finish up.
*
* This function recalculates the display power state each time.
*
- * @return True if the display became ready.
+ * @return {@code true} if all displays became ready; {@code false} otherwise
*/
private boolean updateDisplayPowerStateLocked(int dirty) {
- final boolean oldDisplayReady = mDisplayReady;
+ final boolean oldDisplayReady = mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked();
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
| DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
| DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_VR_MODE_CHANGED |
- DIRTY_QUIESCENT)) != 0) {
+ DIRTY_QUIESCENT | DIRTY_DISPLAY_GROUP_POWER_UPDATED)) != 0) {
if ((dirty & DIRTY_QUIESCENT) != 0) {
sQuiescent = false;
}
- final DisplayPowerRequest displayPowerRequest = mDisplayPowerRequestMapper.get(
- Display.DEFAULT_DISPLAY);
- displayPowerRequest.policy = getDesiredScreenPolicyLocked();
-
- // Determine appropriate screen brightness and auto-brightness adjustments.
- final boolean autoBrightness;
- final float screenBrightnessOverride;
- if (!mBootCompleted) {
- // Keep the brightness steady during boot. This requires the
- // bootloader brightness and the default brightness to be identical.
- autoBrightness = false;
- screenBrightnessOverride = mScreenBrightnessDefault;
- } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
- autoBrightness = false;
- screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager;
- } else {
- autoBrightness = (mScreenBrightnessModeSetting ==
- Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
- screenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
- }
+ for (final int groupId : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ final DisplayPowerRequest displayPowerRequest =
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(groupId);
+ displayPowerRequest.policy = getDesiredScreenPolicyLocked(groupId);
+
+ // Determine appropriate screen brightness and auto-brightness adjustments.
+ final boolean autoBrightness;
+ final float screenBrightnessOverride;
+ if (!mBootCompleted) {
+ // Keep the brightness steady during boot. This requires the
+ // bootloader brightness and the default brightness to be identical.
+ autoBrightness = false;
+ screenBrightnessOverride = mScreenBrightnessDefault;
+ } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
+ autoBrightness = false;
+ screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager;
+ } else {
+ autoBrightness = (mScreenBrightnessModeSetting ==
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+ screenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ }
- // Update display power request.
- displayPowerRequest.screenBrightnessOverride = screenBrightnessOverride;
- displayPowerRequest.useAutoBrightness = autoBrightness;
- displayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
- displayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();
+ // Update display power request.
+ displayPowerRequest.screenBrightnessOverride = screenBrightnessOverride;
+ displayPowerRequest.useAutoBrightness = autoBrightness;
+ displayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
+ displayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();
- updatePowerRequestFromBatterySaverPolicy(displayPowerRequest);
+ updatePowerRequestFromBatterySaverPolicy(displayPowerRequest);
- if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
- displayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
- if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0
- && !mDrawWakeLockOverrideFromSidekick) {
- if (displayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) {
- displayPowerRequest.dozeScreenState = Display.STATE_DOZE;
+ if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
+ displayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
+ if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0
+ && !mDrawWakeLockOverrideFromSidekick) {
+ if (displayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) {
+ displayPowerRequest.dozeScreenState = Display.STATE_DOZE;
+ }
+ if (displayPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND) {
+ displayPowerRequest.dozeScreenState = Display.STATE_ON;
+ }
}
- if (displayPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND) {
- displayPowerRequest.dozeScreenState = Display.STATE_ON;
+ displayPowerRequest.dozeScreenBrightness =
+ mDozeScreenBrightnessOverrideFromDreamManagerFloat;
+ } else {
+ displayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN;
+ displayPowerRequest.dozeScreenBrightness =
+ PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ }
+
+ final boolean ready = mDisplayManagerInternal.requestPowerState(groupId,
+ displayPowerRequest, mRequestWaitForNegativeProximity);
+
+ if (DEBUG_SPEW) {
+ Slog.d(TAG, "updateDisplayPowerStateLocked: displayReady=" + ready
+ + ", groupId=" + groupId
+ + ", policy=" + displayPowerRequest.policy
+ + ", mWakefulness="
+ + mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId)
+ + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
+ + ", mUserActivitySummary=0x" + Integer.toHexString(
+ mUserActivitySummary)
+ + ", mBootCompleted=" + mBootCompleted
+ + ", screenBrightnessOverride="
+ + displayPowerRequest.screenBrightnessOverride
+ + ", useAutoBrightness=" + displayPowerRequest.useAutoBrightness
+ + ", mScreenBrightnessBoostInProgress="
+ + mScreenBrightnessBoostInProgress
+ + ", mIsVrModeEnabled= " + mIsVrModeEnabled
+ + ", sQuiescent=" + sQuiescent);
+ }
+
+ final boolean displayReadyStateChanged =
+ mDisplayGroupPowerStateMapper.setDisplayGroupReadyLocked(groupId, ready);
+ if (ready && displayReadyStateChanged
+ && mDisplayGroupPowerStateMapper.getWakefulnessLocked(
+ groupId) == WAKEFULNESS_AWAKE) {
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, groupId);
+ final int latencyMs = (int) (mClock.uptimeMillis()
+ - mDisplayGroupPowerStateMapper.getLastPowerOnTimeLocked(groupId));
+ if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) {
+ Slog.w(TAG, "Screen on took " + latencyMs + " ms");
}
}
- displayPowerRequest.dozeScreenBrightness =
- mDozeScreenBrightnessOverrideFromDreamManagerFloat;
- } else {
- displayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN;
- displayPowerRequest.dozeScreenBrightness =
- PowerManager.BRIGHTNESS_INVALID_FLOAT;
}
- mDisplayReady = mDisplayManagerInternal.requestPowerState(displayPowerRequest,
- mRequestWaitForNegativeProximity);
mRequestWaitForNegativeProximity = false;
- if (DEBUG_SPEW) {
- Slog.d(TAG, "updateDisplayPowerStateLocked: mDisplayReady=" + mDisplayReady
- + ", policy=" + displayPowerRequest.policy
- + ", mWakefulness=" + getWakefulnessLocked()
- + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
- + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
- + ", mBootCompleted=" + mBootCompleted
- + ", screenBrightnessOverride=" + screenBrightnessOverride
- + ", useAutoBrightness=" + autoBrightness
- + ", mScreenBrightnessBoostInProgress=" + mScreenBrightnessBoostInProgress
- + ", mIsVrModeEnabled= " + mIsVrModeEnabled
- + ", sQuiescent=" + sQuiescent);
- }
}
- return mDisplayReady && !oldDisplayReady;
+ return mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked() && !oldDisplayReady;
}
private void updateScreenBrightnessBoostLocked(int dirty) {
@@ -2933,12 +3081,11 @@ public final class PowerManagerService extends SystemService
}
@VisibleForTesting
- int getDesiredScreenPolicyLocked() {
- if (getWakefulnessLocked() == WAKEFULNESS_ASLEEP || sQuiescent) {
+ int getDesiredScreenPolicyLocked(int groupId) {
+ final int wakefulness = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
+ if (wakefulness == WAKEFULNESS_ASLEEP || sQuiescent) {
return DisplayPowerRequest.POLICY_OFF;
- }
-
- if (getWakefulnessLocked() == WAKEFULNESS_DOZING) {
+ } else if (wakefulness == WAKEFULNESS_DOZING) {
if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
return DisplayPowerRequest.POLICY_DOZE;
}
@@ -2968,7 +3115,6 @@ public final class PowerManagerService extends SystemService
private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks =
new DisplayManagerInternal.DisplayPowerCallbacks() {
- private int mDisplayState = Display.STATE_UNKNOWN;
@Override
public void onStateChanged() {
@@ -2999,29 +3145,25 @@ public final class PowerManagerService extends SystemService
}
@Override
- public void onDisplayStateChange(int state) {
+ public void onDisplayStateChange(boolean allInactive, boolean allOff) {
// This method is only needed to support legacy display blanking behavior
// where the display's power state is coupled to suspend or to the power HAL.
// The order of operations matters here.
synchronized (mLock) {
- if (mDisplayState != state) {
- mDisplayState = state;
- setPowerModeInternal(MODE_DISPLAY_INACTIVE,
- !Display.isActiveState(state));
- if (state == Display.STATE_OFF) {
- if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
- setHalInteractiveModeLocked(false);
- }
- if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
- setHalAutoSuspendModeLocked(true);
- }
- } else {
- if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
- setHalAutoSuspendModeLocked(false);
- }
- if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
- setHalInteractiveModeLocked(true);
- }
+ setPowerModeInternal(MODE_DISPLAY_INACTIVE, allInactive);
+ if (allOff) {
+ if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+ setHalInteractiveModeLocked(false);
+ }
+ if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+ setHalAutoSuspendModeLocked(true);
+ }
+ } else {
+ if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+ setHalAutoSuspendModeLocked(false);
+ }
+ if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+ setHalInteractiveModeLocked(true);
}
}
}
@@ -3036,13 +3178,6 @@ public final class PowerManagerService extends SystemService
public void releaseSuspendBlocker() {
mDisplaySuspendBlocker.release();
}
-
- @Override
- public String toString() {
- synchronized (this) {
- return "state=" + Display.stateToString(mDisplayState);
- }
- }
};
private boolean shouldUseProximitySensorLocked() {
@@ -3058,9 +3193,13 @@ public final class PowerManagerService extends SystemService
final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
final boolean autoSuspend = !needDisplaySuspendBlocker;
- final DisplayPowerRequest displayPowerRequest = mDisplayPowerRequestMapper.get(
- Display.DEFAULT_DISPLAY);
- final boolean interactive = displayPowerRequest.isBrightOrDim();
+ final DisplayPowerRequest displayPowerRequest =
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(DisplayGroup.DEFAULT);
+ final int[] groupIds = mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked();
+ boolean interactive = false;
+ for (int id : groupIds) {
+ interactive |= mDisplayGroupPowerStateMapper.getPowerRequestLocked(id).isBrightOrDim();
+ }
// Disable auto-suspend if needed.
// FIXME We should consider just leaving auto-suspend enabled forever since
@@ -3090,7 +3229,7 @@ public final class PowerManagerService extends SystemService
// until the display is actually ready so that all transitions have
// completed. This is probably a good sign that things have gotten
// too tangled over here...
- if (interactive || mDisplayReady) {
+ if (interactive || mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) {
setHalInteractiveModeLocked(interactive);
}
}
@@ -3116,29 +3255,10 @@ public final class PowerManagerService extends SystemService
* We do so if the screen is on or is in transition between states.
*/
private boolean needDisplaySuspendBlockerLocked() {
- if (!mDisplayReady) {
+ if (!mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) {
return true;
}
- final DisplayPowerRequest displayPowerRequest = mDisplayPowerRequestMapper.get(
- Display.DEFAULT_DISPLAY);
- if (displayPowerRequest.isBrightOrDim()) {
- // If we asked for the screen to be on but it is off due to the proximity
- // sensor then we may suspend but only if the configuration allows it.
- // On some hardware it may not be safe to suspend because the proximity
- // sensor may not be correctly configured as a wake-up source.
- if (!displayPowerRequest.useProximitySensor || !mProximityPositive
- || !mSuspendWhenScreenOffDueToProximityConfig) {
- return true;
- }
- }
- if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE
- && displayPowerRequest.dozeScreenState == Display.STATE_ON) {
- // Although we are in DOZE and would normally allow the device to suspend,
- // the doze service has explicitly requested the display to remain in the ON
- // state which means we should hold the display suspend blocker.
- return true;
- }
if (mScreenBrightnessBoostInProgress) {
return true;
}
@@ -3152,6 +3272,30 @@ public final class PowerManagerService extends SystemService
return true;
}
+ final int[] groupIds = mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked();
+ for (int id : groupIds) {
+ final DisplayPowerRequest displayPowerRequest =
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(id);
+ if (displayPowerRequest.isBrightOrDim()) {
+ // If we asked for the screen to be on but it is off due to the proximity
+ // sensor then we may suspend but only if the configuration allows it.
+ // On some hardware it may not be safe to suspend because the proximity
+ // sensor may not be correctly configured as a wake-up source.
+ if (!displayPowerRequest.useProximitySensor || !mProximityPositive
+ || !mSuspendWhenScreenOffDueToProximityConfig) {
+ return true;
+ }
+ }
+
+ if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE
+ && displayPowerRequest.dozeScreenState == Display.STATE_ON) {
+ // Although we are in DOZE and would normally allow the device to suspend,
+ // the doze service has explicitly requested the display to remain in the ON
+ // state which means we should hold the display suspend blocker.
+ return true;
+ }
+ }
+
// Let the system suspend if the screen is off or dozing.
return false;
}
@@ -3685,9 +3829,15 @@ public final class PowerManagerService extends SystemService
synchronized (mLock) {
mForceSuspendActive = true;
// Place the system in an non-interactive state
- goToSleepInternal(mClock.uptimeMillis(),
- PowerManager.GO_TO_SLEEP_REASON_FORCE_SUSPEND,
- PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, uid);
+ boolean updatePowerState = false;
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ updatePowerState |= sleepDisplayGroupNoUpdateLocked(id, mClock.uptimeMillis(),
+ PowerManager.GO_TO_SLEEP_REASON_FORCE_SUSPEND,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, uid);
+ }
+ if (updatePowerState) {
+ updatePowerStateLocked();
+ }
// Disable all the partial wake locks as well
updateWakeLockDisabledStatesLocked();
@@ -3827,7 +3977,6 @@ public final class PowerManagerService extends SystemService
pw.println(" mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary));
pw.println(" mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
pw.println(" mSandmanScheduled=" + mSandmanScheduled);
- pw.println(" mSandmanSummoned=" + mSandmanSummoned);
pw.println(" mBatteryLevelLow=" + mBatteryLevelLow);
pw.println(" mLightDeviceIdleMode=" + mLightDeviceIdleMode);
pw.println(" mDeviceIdleMode=" + mDeviceIdleMode);
@@ -3845,7 +3994,6 @@ public final class PowerManagerService extends SystemService
+ TimeUtils.formatUptime(mLastScreenBrightnessBoostTime));
pw.println(" mScreenBrightnessBoostInProgress="
+ mScreenBrightnessBoostInProgress);
- pw.println(" mDisplayReady=" + mDisplayReady);
pw.println(" mHoldingWakeLockSuspendBlocker=" + mHoldingWakeLockSuspendBlocker);
pw.println(" mHoldingDisplaySuspendBlocker=" + mHoldingDisplaySuspendBlocker);
@@ -4080,7 +4228,6 @@ public final class PowerManagerService extends SystemService
PowerManagerServiceDumpProto.IS_REQUEST_WAIT_FOR_NEGATIVE_PROXIMITY,
mRequestWaitForNegativeProximity);
proto.write(PowerManagerServiceDumpProto.IS_SANDMAN_SCHEDULED, mSandmanScheduled);
- proto.write(PowerManagerServiceDumpProto.IS_SANDMAN_SUMMONED, mSandmanSummoned);
proto.write(PowerManagerServiceDumpProto.IS_BATTERY_LEVEL_LOW, mBatteryLevelLow);
proto.write(PowerManagerServiceDumpProto.IS_LIGHT_DEVICE_IDLE_MODE, mLightDeviceIdleMode);
proto.write(PowerManagerServiceDumpProto.IS_DEVICE_IDLE_MODE, mDeviceIdleMode);
@@ -4107,7 +4254,6 @@ public final class PowerManagerService extends SystemService
proto.write(
PowerManagerServiceDumpProto.IS_SCREEN_BRIGHTNESS_BOOST_IN_PROGRESS,
mScreenBrightnessBoostInProgress);
- proto.write(PowerManagerServiceDumpProto.IS_DISPLAY_READY, mDisplayReady);
proto.write(
PowerManagerServiceDumpProto.IS_HOLDING_WAKE_LOCK_SUSPEND_BLOCKER,
mHoldingWakeLockSuspendBlocker);
@@ -4921,7 +5067,8 @@ public final class PowerManagerService extends SystemService
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
- wakeUpInternal(eventTime, reason, details, uid, opPackageName, uid);
+ wakeDisplayGroup(DisplayGroup.DEFAULT, eventTime, reason, details, uid,
+ opPackageName, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -4939,7 +5086,7 @@ public final class PowerManagerService extends SystemService
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
- goToSleepInternal(eventTime, reason, flags, uid);
+ sleepDisplayGroup(DisplayGroup.DEFAULT, eventTime, reason, flags, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -4957,7 +5104,7 @@ public final class PowerManagerService extends SystemService
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
- napInternal(eventTime, uid);
+ dreamDisplayGroup(DisplayGroup.DEFAULT, eventTime, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -5590,7 +5737,7 @@ public final class PowerManagerService extends SystemService
// also tells us that we're not already ignoring the proximity sensor.
final DisplayPowerRequest displayPowerRequest =
- mDisplayPowerRequestMapper.get(Display.DEFAULT_DISPLAY);
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(DisplayGroup.DEFAULT);
if (displayPowerRequest.useProximitySensor && mProximityPositive) {
mDisplayManagerInternal.ignoreProximitySensorUntilChanged();
return true;
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 7f35511236f7..f07197cf77f6 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -77,6 +77,7 @@ import com.android.internal.app.IBatteryStats;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.display.DisplayGroup;
import com.android.server.lights.LightsManager;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.power.PowerManagerService.BatteryReceiver;
@@ -97,9 +98,12 @@ import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Tests for {@link com.android.server.power.PowerManagerService}.
@@ -178,7 +182,8 @@ public class PowerManagerServiceTest {
.thenReturn(mPowerSaveState);
when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(false);
when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(false);
- when(mDisplayManagerInternalMock.requestPowerState(any(), anyBoolean())).thenReturn(true);
+ when(mDisplayManagerInternalMock.requestPowerState(anyInt(), any(),
+ anyBoolean())).thenReturn(true);
when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), anyString())).thenReturn("");
when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(true);
@@ -399,30 +404,33 @@ public class PowerManagerServiceTest {
@Test
public void testGetDesiredScreenPolicy_WithVR() throws Exception {
createService();
+ mService.systemReady(null);
// Brighten up the screen
- mService.setWakefulnessLocked(WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_UNKNOWN, 0);
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ mService.setWakefulnessLocked(DisplayGroup.DEFAULT, WAKEFULNESS_AWAKE, 0, 0, 0, 0, null,
+ null);
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_BRIGHT);
// Move to VR
mService.setVrModeEnabled(true);
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_VR);
// Then take a nap
- mService.setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
- 0);
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ mService.setWakefulnessLocked(DisplayGroup.DEFAULT, WAKEFULNESS_ASLEEP, 0, 0, 0, 0, null,
+ null);
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_OFF);
// Wake up to VR
- mService.setWakefulnessLocked(WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_UNKNOWN, 0);
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ mService.setWakefulnessLocked(DisplayGroup.DEFAULT, WAKEFULNESS_AWAKE, 0, 0, 0, 0, null,
+ null);
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_VR);
// And back to normal
mService.setVrModeEnabled(false);
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_BRIGHT);
}
@@ -673,8 +681,9 @@ public class PowerManagerServiceTest {
}
@Test
- public void testForceSuspend_forceSuspendFailurePropogated() {
+ public void testForceSuspend_forceSuspendFailurePropagated() throws Exception {
createService();
+ startSystem();
when(mNativeWrapperMock.nativeForceSuspend()).thenReturn(false);
assertThat(mService.getBinderServiceInstance().forceSuspend()).isFalse();
}
@@ -838,7 +847,7 @@ public class PowerManagerServiceTest {
createService();
startSystem();
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_BRIGHT);
}
@@ -857,11 +866,8 @@ public class PowerManagerServiceTest {
public void testQuiescentBoot_DesiredScreenPolicyShouldBeOff() throws Exception {
when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), any())).thenReturn("1");
createService();
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
- DisplayPowerRequest.POLICY_OFF);
-
startSystem();
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_OFF);
}
@@ -871,7 +877,7 @@ public class PowerManagerServiceTest {
createService();
startSystem();
forceAwake();
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_BRIGHT);
}
@@ -1143,4 +1149,85 @@ public class PowerManagerServiceTest {
assertFalse(
mService.getBinderServiceInstance().setPowerModeChecked(Mode.INTERACTIVE, false));
}
+
+ @Test
+ public void testMultiDisplay_wakefulnessUpdates() throws Exception {
+ final int nonDefaultDisplayGroupId = DisplayGroup.DEFAULT + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+
+ createService();
+ startSystem();
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(DisplayGroup.DEFAULT, WAKEFULNESS_ASLEEP, 0, 0, 0, 0, null,
+ null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+
+ mService.setWakefulnessLocked(DisplayGroup.DEFAULT, WAKEFULNESS_AWAKE, 0, 0, 0, 0, null,
+ null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ @Test
+ public void testMultiDisplay_addDisplayGroup_preservesWakefulness() throws Exception {
+ final int nonDefaultDisplayGroupId = DisplayGroup.DEFAULT + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+
+ createService();
+ startSystem();
+
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(DisplayGroup.DEFAULT, WAKEFULNESS_ASLEEP, 0, 0, 0, 0, null,
+ null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ }
+
+ @Test
+ public void testMultiDisplay_removeDisplayGroup_updatesWakefulness() throws Exception {
+ final int nonDefaultDisplayGroupId = DisplayGroup.DEFAULT + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+
+ createService();
+ startSystem();
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(DisplayGroup.DEFAULT, WAKEFULNESS_ASLEEP, 0, 0, 0, 0, null,
+ null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ listener.get().onDisplayGroupRemoved(nonDefaultDisplayGroupId);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+
+ mService.setWakefulnessLocked(DisplayGroup.DEFAULT, WAKEFULNESS_AWAKE, 0, 0, 0, 0, null,
+ null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
}