Add display committed state to DisplayInfo

This adds the committed state to the display.
The `state` is used to set the correct power state (e.g. turning display on/off), however there was no way to know when this power state change finished. This new "committedState" aims to fulfill this gap.

DisplayListeners receives a `onDisplayChanged` callback whenever the power state change is fully committed, and can get this information from DisplayInfo.

This will be used in a follow up cl to improve unfold latency performances.

Bug: 223808403
Bug: 220690092
Bug: 197515205
Test: atest LocalDisplayAdapterTest && manual
Change-Id: Ia2fbab768b696c59578d974c88157ee3c8f3ddde
This commit is contained in:
Nicolo' Mazzucato
2022-03-10 16:43:27 +00:00
parent 783abde2ab
commit 07c6ebdd97
7 changed files with 114 additions and 3 deletions

View File

@@ -41,6 +41,7 @@ import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.os.Trace;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import android.util.SparseArray; import android.util.SparseArray;
@@ -987,7 +988,8 @@ public final class DisplayManagerGlobal {
@Override @Override
public void onDisplayEvent(int displayId, @DisplayEvent int event) { public void onDisplayEvent(int displayId, @DisplayEvent int event) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event); Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + eventToString(
event));
} }
handleDisplayEvent(displayId, event); handleDisplayEvent(displayId, event);
} }
@@ -1021,6 +1023,12 @@ public final class DisplayManagerGlobal {
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
if (DEBUG) {
Trace.beginSection(
"DisplayListenerDelegate(" + eventToString(msg.what)
+ ", display=" + msg.arg1
+ ", listener=" + mListener.getClass() + ")");
}
switch (msg.what) { switch (msg.what) {
case EVENT_DISPLAY_ADDED: case EVENT_DISPLAY_ADDED:
if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) { if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) {
@@ -1047,6 +1055,9 @@ public final class DisplayManagerGlobal {
} }
break; break;
} }
if (DEBUG) {
Trace.endSection();
}
} }
} }
@@ -1150,4 +1161,18 @@ public final class DisplayManagerGlobal {
updateCallbackIfNeededLocked(); updateCallbackIfNeededLocked();
} }
} }
private static String eventToString(@DisplayEvent int event) {
switch (event) {
case EVENT_DISPLAY_ADDED:
return "ADDED";
case EVENT_DISPLAY_CHANGED:
return "CHANGED";
case EVENT_DISPLAY_REMOVED:
return "REMOVED";
case EVENT_DISPLAY_BRIGHTNESS_CHANGED:
return "BRIGHTNESS_CHANGED";
}
return "UNKNOWN";
}
} }

View File

@@ -1615,6 +1615,21 @@ public final class Display {
} }
} }
/**
* Returns the committed state of the display.
*
* @return The latest committed display state, such as {@link #STATE_ON}. The display state
* {@link Display#getState()} is set as committed only after power state changes finish.
*
* @hide
*/
public int getCommittedState() {
synchronized (mLock) {
updateDisplayInfoLocked();
return mIsValid ? mDisplayInfo.committedState : STATE_UNKNOWN;
}
}
/** /**
* Returns true if the specified UID has access to this display. * Returns true if the specified UID has access to this display.
* @hide * @hide

View File

@@ -252,6 +252,12 @@ public final class DisplayInfo implements Parcelable {
*/ */
public int state; public int state;
/**
* The current committed state of the display. For example, this becomes
* {@link android.view.Display#STATE_ON} only after the power state ON is fully committed.
*/
public int committedState;
/** /**
* The UID of the application that owns this display, or zero if it is owned by the system. * The UID of the application that owns this display, or zero if it is owned by the system.
* <p> * <p>
@@ -387,6 +393,7 @@ public final class DisplayInfo implements Parcelable {
&& appVsyncOffsetNanos == other.appVsyncOffsetNanos && appVsyncOffsetNanos == other.appVsyncOffsetNanos
&& presentationDeadlineNanos == other.presentationDeadlineNanos && presentationDeadlineNanos == other.presentationDeadlineNanos
&& state == other.state && state == other.state
&& committedState == other.committedState
&& ownerUid == other.ownerUid && ownerUid == other.ownerUid
&& Objects.equals(ownerPackageName, other.ownerPackageName) && Objects.equals(ownerPackageName, other.ownerPackageName)
&& removeMode == other.removeMode && removeMode == other.removeMode
@@ -439,6 +446,7 @@ public final class DisplayInfo implements Parcelable {
appVsyncOffsetNanos = other.appVsyncOffsetNanos; appVsyncOffsetNanos = other.appVsyncOffsetNanos;
presentationDeadlineNanos = other.presentationDeadlineNanos; presentationDeadlineNanos = other.presentationDeadlineNanos;
state = other.state; state = other.state;
committedState = other.committedState;
ownerUid = other.ownerUid; ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName; ownerPackageName = other.ownerPackageName;
removeMode = other.removeMode; removeMode = other.removeMode;
@@ -491,6 +499,7 @@ public final class DisplayInfo implements Parcelable {
appVsyncOffsetNanos = source.readLong(); appVsyncOffsetNanos = source.readLong();
presentationDeadlineNanos = source.readLong(); presentationDeadlineNanos = source.readLong();
state = source.readInt(); state = source.readInt();
committedState = source.readInt();
ownerUid = source.readInt(); ownerUid = source.readInt();
ownerPackageName = source.readString8(); ownerPackageName = source.readString8();
uniqueId = source.readString8(); uniqueId = source.readString8();
@@ -548,6 +557,7 @@ public final class DisplayInfo implements Parcelable {
dest.writeLong(appVsyncOffsetNanos); dest.writeLong(appVsyncOffsetNanos);
dest.writeLong(presentationDeadlineNanos); dest.writeLong(presentationDeadlineNanos);
dest.writeInt(state); dest.writeInt(state);
dest.writeInt(committedState);
dest.writeInt(ownerUid); dest.writeInt(ownerUid);
dest.writeString8(ownerPackageName); dest.writeString8(ownerPackageName);
dest.writeString8(uniqueId); dest.writeString8(uniqueId);
@@ -772,6 +782,8 @@ public final class DisplayInfo implements Parcelable {
sb.append(rotation); sb.append(rotation);
sb.append(", state "); sb.append(", state ");
sb.append(Display.stateToString(state)); sb.append(Display.stateToString(state));
sb.append(", committedState ");
sb.append(Display.stateToString(committedState));
if (Process.myUid() != Process.SYSTEM_UID) { if (Process.myUid() != Process.SYSTEM_UID) {
sb.append("}"); sb.append("}");

View File

@@ -173,7 +173,7 @@ final class DisplayDeviceInfo {
public static final int TOUCH_VIRTUAL = 3; public static final int TOUCH_VIRTUAL = 3;
/** /**
* Diff result: The {@link #state} fields differ. * Diff result: The {@link #state} or {@link #committedState} fields differ.
*/ */
public static final int DIFF_STATE = 1 << 0; public static final int DIFF_STATE = 1 << 0;
@@ -334,6 +334,13 @@ final class DisplayDeviceInfo {
*/ */
public int state = Display.STATE_ON; public int state = Display.STATE_ON;
/**
* Display committed state.
*
* This matches {@link DisplayDeviceInfo#state} only after the power state change finishes.
*/
public int committedState = Display.STATE_UNKNOWN;
/** /**
* The UID of the application that owns this display, or zero if it is owned by the system. * The UID of the application that owns this display, or zero if it is owned by the system.
* <p> * <p>
@@ -387,7 +394,7 @@ final class DisplayDeviceInfo {
*/ */
public int diff(DisplayDeviceInfo other) { public int diff(DisplayDeviceInfo other) {
int diff = 0; int diff = 0;
if (state != other.state) { if (state != other.state || committedState != other.committedState) {
diff |= DIFF_STATE; diff |= DIFF_STATE;
} }
if (colorMode != other.colorMode) { if (colorMode != other.colorMode) {
@@ -461,6 +468,7 @@ final class DisplayDeviceInfo {
address = other.address; address = other.address;
deviceProductInfo = other.deviceProductInfo; deviceProductInfo = other.deviceProductInfo;
state = other.state; state = other.state;
committedState = other.committedState;
ownerUid = other.ownerUid; ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName; ownerPackageName = other.ownerPackageName;
frameRateOverrides = other.frameRateOverrides; frameRateOverrides = other.frameRateOverrides;
@@ -501,6 +509,7 @@ final class DisplayDeviceInfo {
} }
sb.append(", deviceProductInfo ").append(deviceProductInfo); sb.append(", deviceProductInfo ").append(deviceProductInfo);
sb.append(", state ").append(Display.stateToString(state)); sb.append(", state ").append(Display.stateToString(state));
sb.append(", committedState ").append(Display.stateToString(committedState));
if (ownerUid != 0 || ownerPackageName != null) { if (ownerUid != 0 || ownerPackageName != null) {
sb.append(", owner ").append(ownerPackageName); sb.append(", owner ").append(ownerPackageName);
sb.append(" (uid ").append(ownerUid).append(")"); sb.append(" (uid ").append(ownerUid).append(")");

View File

@@ -191,6 +191,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private DisplayDeviceInfo mInfo; private DisplayDeviceInfo mInfo;
private boolean mHavePendingChanges; private boolean mHavePendingChanges;
private int mState = Display.STATE_UNKNOWN; private int mState = Display.STATE_UNKNOWN;
private int mCommittedState = Display.STATE_UNKNOWN;
// This is only set in the runnable returned from requestDisplayStateLocked. // This is only set in the runnable returned from requestDisplayStateLocked.
private float mBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT; private float mBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
private float mSdrBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT; private float mSdrBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
@@ -632,6 +634,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mInfo.appVsyncOffsetNanos = mActiveSfDisplayMode.appVsyncOffsetNanos; mInfo.appVsyncOffsetNanos = mActiveSfDisplayMode.appVsyncOffsetNanos;
mInfo.presentationDeadlineNanos = mActiveSfDisplayMode.presentationDeadlineNanos; mInfo.presentationDeadlineNanos = mActiveSfDisplayMode.presentationDeadlineNanos;
mInfo.state = mState; mInfo.state = mState;
mInfo.committedState = mCommittedState;
mInfo.uniqueId = getUniqueId(); mInfo.uniqueId = getUniqueId();
final DisplayAddress.Physical physicalAddress = final DisplayAddress.Physical physicalAddress =
DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId); DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId);
@@ -812,6 +815,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
} finally { } finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER); Trace.traceEnd(Trace.TRACE_TAG_POWER);
} }
setCommittedState(state);
// If we're entering a suspended (but not OFF) power state and we // If we're entering a suspended (but not OFF) power state and we
// have a sidekick available, tell it now that it can take control. // have a sidekick available, tell it now that it can take control.
if (Display.isSuspendedState(state) && state != Display.STATE_OFF if (Display.isSuspendedState(state) && state != Display.STATE_OFF
@@ -826,6 +830,16 @@ final class LocalDisplayAdapter extends DisplayAdapter {
} }
} }
private void setCommittedState(int state) {
// After the display state is set, let's update the committed state.
getHandler().post(() -> {
synchronized (getSyncRoot()) {
mCommittedState = state;
updateDeviceInfoLocked();
}
});
}
private void setDisplayBrightness(float brightnessState, private void setDisplayBrightness(float brightnessState,
float sdrBrightnessState) { float sdrBrightnessState) {
// brightnessState includes invalid, off and full range. // brightnessState includes invalid, off and full range.
@@ -1091,6 +1105,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
pw.println("mDefaultModeId=" + mDefaultModeId); pw.println("mDefaultModeId=" + mDefaultModeId);
pw.println("mUserPreferredModeId=" + mUserPreferredModeId); pw.println("mUserPreferredModeId=" + mUserPreferredModeId);
pw.println("mState=" + Display.stateToString(mState)); pw.println("mState=" + Display.stateToString(mState));
pw.println("mCommittedState=" + Display.stateToString(mCommittedState));
pw.println("mBrightnessState=" + mBrightnessState); pw.println("mBrightnessState=" + mBrightnessState);
pw.println("mBacklightAdapter=" + mBacklightAdapter); pw.println("mBacklightAdapter=" + mBacklightAdapter);
pw.println("mAllmSupported=" + mAllmSupported); pw.println("mAllmSupported=" + mAllmSupported);

View File

@@ -413,6 +413,7 @@ final class LogicalDisplay {
mBaseDisplayInfo.appVsyncOffsetNanos = deviceInfo.appVsyncOffsetNanos; mBaseDisplayInfo.appVsyncOffsetNanos = deviceInfo.appVsyncOffsetNanos;
mBaseDisplayInfo.presentationDeadlineNanos = deviceInfo.presentationDeadlineNanos; mBaseDisplayInfo.presentationDeadlineNanos = deviceInfo.presentationDeadlineNanos;
mBaseDisplayInfo.state = deviceInfo.state; mBaseDisplayInfo.state = deviceInfo.state;
mBaseDisplayInfo.committedState = deviceInfo.committedState;
mBaseDisplayInfo.smallestNominalAppWidth = maskedWidth; mBaseDisplayInfo.smallestNominalAppWidth = maskedWidth;
mBaseDisplayInfo.smallestNominalAppHeight = maskedHeight; mBaseDisplayInfo.smallestNominalAppHeight = maskedHeight;
mBaseDisplayInfo.largestNominalAppWidth = maskedWidth; mBaseDisplayInfo.largestNominalAppWidth = maskedWidth;

View File

@@ -556,6 +556,40 @@ public class LocalDisplayAdapterTest {
assertThat(displayDeviceInfo.allmSupported).isFalse(); assertThat(displayDeviceInfo.allmSupported).isFalse();
} }
@Test
public void testAfterDisplayStateChanges_committedSetAfterState() throws Exception {
FakeDisplay display = new FakeDisplay(PORT_A);
setUpDisplay(display);
updateAvailableDisplays();
mAdapter.registerLocked();
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
assertThat(mListener.addedDisplays.size()).isEqualTo(1);
DisplayDevice displayDevice = mListener.addedDisplays.get(0);
// Turn off.
Runnable changeStateRunnable = displayDevice.requestDisplayStateLocked(Display.STATE_OFF, 0,
0);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
assertThat(mListener.changedDisplays.size()).isEqualTo(1);
mListener.changedDisplays.clear();
assertThat(displayDevice.getDisplayDeviceInfoLocked().state).isEqualTo(Display.STATE_OFF);
assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState).isNotEqualTo(
Display.STATE_OFF);
verify(mSurfaceControlProxy, never()).setDisplayPowerMode(display.token, Display.STATE_OFF);
// Execute powerstate change.
changeStateRunnable.run();
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
// Verify that committed triggered a new change event and is set correctly.
verify(mSurfaceControlProxy, never()).setDisplayPowerMode(display.token, Display.STATE_OFF);
assertThat(mListener.changedDisplays.size()).isEqualTo(1);
assertThat(displayDevice.getDisplayDeviceInfoLocked().state).isEqualTo(Display.STATE_OFF);
assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState).isEqualTo(
Display.STATE_OFF);
}
@Test @Test
public void testAfterDisplayChange_GameContentTypeSupportIsUpdated() throws Exception { public void testAfterDisplayChange_GameContentTypeSupportIsUpdated() throws Exception {
FakeDisplay display = new FakeDisplay(PORT_A); FakeDisplay display = new FakeDisplay(PORT_A);