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
Bug: 273204503
Test: atest LocalDisplayAdapterTest && manual
Change-Id: Ia2fbab768b696c59578d974c88157ee3c8f3ddde
Merged-In: Ia2fbab768b696c59578d974c88157ee3c8f3ddde
(cherry picked from commit 07c6ebdd97)
This commit is contained in:
Nicolo' Mazzucato
2022-03-10 16:43:27 +00:00
committed by Nicolò Mazzucato
parent 8e63a7c8a4
commit 99b9c47dee
7 changed files with 114 additions and 3 deletions

View File

@@ -40,6 +40,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.Trace;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
@@ -1006,7 +1007,8 @@ public final class DisplayManagerGlobal {
@Override
public void onDisplayEvent(int displayId, @DisplayEvent int event) {
if (DEBUG) {
Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event);
Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + eventToString(
event));
}
handleDisplayEvent(displayId, event);
}
@@ -1040,6 +1042,12 @@ public final class DisplayManagerGlobal {
@Override
public void handleMessage(Message msg) {
if (DEBUG) {
Trace.beginSection(
"DisplayListenerDelegate(" + eventToString(msg.what)
+ ", display=" + msg.arg1
+ ", listener=" + mListener.getClass() + ")");
}
switch (msg.what) {
case EVENT_DISPLAY_ADDED:
if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) {
@@ -1066,6 +1074,9 @@ public final class DisplayManagerGlobal {
}
break;
}
if (DEBUG) {
Trace.endSection();
}
}
}
@@ -1172,4 +1183,18 @@ public final class DisplayManagerGlobal {
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

@@ -1599,6 +1599,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.
* @hide

View File

@@ -252,6 +252,12 @@ public final class DisplayInfo implements Parcelable {
*/
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.
* <p>
@@ -380,6 +386,7 @@ public final class DisplayInfo implements Parcelable {
&& appVsyncOffsetNanos == other.appVsyncOffsetNanos
&& presentationDeadlineNanos == other.presentationDeadlineNanos
&& state == other.state
&& committedState == other.committedState
&& ownerUid == other.ownerUid
&& Objects.equals(ownerPackageName, other.ownerPackageName)
&& removeMode == other.removeMode
@@ -431,6 +438,7 @@ public final class DisplayInfo implements Parcelable {
appVsyncOffsetNanos = other.appVsyncOffsetNanos;
presentationDeadlineNanos = other.presentationDeadlineNanos;
state = other.state;
committedState = other.committedState;
ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName;
removeMode = other.removeMode;
@@ -482,6 +490,7 @@ public final class DisplayInfo implements Parcelable {
appVsyncOffsetNanos = source.readLong();
presentationDeadlineNanos = source.readLong();
state = source.readInt();
committedState = source.readInt();
ownerUid = source.readInt();
ownerPackageName = source.readString8();
uniqueId = source.readString8();
@@ -538,6 +547,7 @@ public final class DisplayInfo implements Parcelable {
dest.writeLong(appVsyncOffsetNanos);
dest.writeLong(presentationDeadlineNanos);
dest.writeInt(state);
dest.writeInt(committedState);
dest.writeInt(ownerUid);
dest.writeString8(ownerPackageName);
dest.writeString8(uniqueId);
@@ -761,6 +771,8 @@ public final class DisplayInfo implements Parcelable {
sb.append(rotation);
sb.append(", state ");
sb.append(Display.stateToString(state));
sb.append(", committedState ");
sb.append(Display.stateToString(committedState));
if (Process.myUid() != Process.SYSTEM_UID) {
sb.append("}");

View File

@@ -180,7 +180,7 @@ final class DisplayDeviceInfo {
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;
@@ -341,6 +341,13 @@ final class DisplayDeviceInfo {
*/
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.
* <p>
@@ -394,7 +401,7 @@ final class DisplayDeviceInfo {
*/
public int diff(DisplayDeviceInfo other) {
int diff = 0;
if (state != other.state) {
if (state != other.state || committedState != other.committedState) {
diff |= DIFF_STATE;
}
if (colorMode != other.colorMode) {
@@ -468,6 +475,7 @@ final class DisplayDeviceInfo {
address = other.address;
deviceProductInfo = other.deviceProductInfo;
state = other.state;
committedState = other.committedState;
ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName;
frameRateOverrides = other.frameRateOverrides;
@@ -508,6 +516,7 @@ final class DisplayDeviceInfo {
}
sb.append(", deviceProductInfo ").append(deviceProductInfo);
sb.append(", state ").append(Display.stateToString(state));
sb.append(", committedState ").append(Display.stateToString(committedState));
if (ownerUid != 0 || ownerPackageName != null) {
sb.append(", owner ").append(ownerPackageName);
sb.append(" (uid ").append(ownerUid).append(")");

View File

@@ -198,6 +198,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private DisplayDeviceInfo mInfo;
private boolean mHavePendingChanges;
private int mState = Display.STATE_UNKNOWN;
private int mCommittedState = Display.STATE_UNKNOWN;
// This is only set in the runnable returned from requestDisplayStateLocked.
private float mBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
private float mSdrBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
@@ -635,6 +637,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mInfo.appVsyncOffsetNanos = mActiveSfDisplayMode.appVsyncOffsetNanos;
mInfo.presentationDeadlineNanos = mActiveSfDisplayMode.presentationDeadlineNanos;
mInfo.state = mState;
mInfo.committedState = mCommittedState;
mInfo.uniqueId = getUniqueId();
final DisplayAddress.Physical physicalAddress =
DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId);
@@ -822,6 +825,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
setCommittedState(state);
// 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.
if (Display.isSuspendedState(state) && state != Display.STATE_OFF
@@ -836,6 +840,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,
float sdrBrightnessState) {
// brightnessState includes invalid, off and full range.
@@ -1108,6 +1122,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
pw.println("mDefaultModeId=" + mDefaultModeId);
pw.println("mUserPreferredModeId=" + mUserPreferredModeId);
pw.println("mState=" + Display.stateToString(mState));
pw.println("mCommittedState=" + Display.stateToString(mCommittedState));
pw.println("mBrightnessState=" + mBrightnessState);
pw.println("mBacklightAdapter=" + mBacklightAdapter);
pw.println("mAllmSupported=" + mAllmSupported);

View File

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

View File

@@ -575,6 +575,40 @@ public class LocalDisplayAdapterTest {
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
public void testAfterDisplayChange_GameContentTypeSupportIsUpdated() throws Exception {
FakeDisplay display = new FakeDisplay(PORT_A);