summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/DisplayEventReceiver.java9
-rw-r--r--core/java/android/view/DisplayInfo.java15
-rw-r--r--core/java/android/view/SurfaceControl.java5
-rw-r--r--core/jni/android_view_DisplayEventReceiver.cpp8
-rw-r--r--core/jni/android_view_SurfaceControl.cpp4
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceInfo.java9
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java18
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java51
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java1
-rw-r--r--services/core/java/com/android/server/display/OverlayDisplayAdapter.java1
-rw-r--r--services/core/java/com/android/server/display/VirtualDisplayAdapter.java1
-rw-r--r--services/core/java/com/android/server/display/WifiDisplayAdapter.java1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java57
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java108
14 files changed, 255 insertions, 33 deletions
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 169c8c51bb53..ce7606a0cf70 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -227,8 +227,10 @@ public abstract class DisplayEventReceiver {
* timebase.
* @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
* @param modeId The new mode Id
+ * @param renderPeriod The render frame period, which is a multiple of the mode's vsync period
*/
- public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) {
+ public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId,
+ long renderPeriod) {
}
/**
@@ -303,8 +305,9 @@ public abstract class DisplayEventReceiver {
// Called from native code.
@SuppressWarnings("unused")
- private void dispatchModeChanged(long timestampNanos, long physicalDisplayId, int modeId) {
- onModeChanged(timestampNanos, physicalDisplayId, modeId);
+ private void dispatchModeChanged(long timestampNanos, long physicalDisplayId, int modeId,
+ long renderPeriod) {
+ onModeChanged(timestampNanos, physicalDisplayId, modeId, renderPeriod);
}
// Called from native code.
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 138017c5f0ec..85cb517f6369 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -180,6 +180,16 @@ public final class DisplayInfo implements Parcelable {
public int modeId;
/**
+ * The render frame rate this display is scheduled at, which is a divisor of the active mode
+ * refresh rate. This is the rate SurfaceFlinger would consume frames and would be observable
+ * by applications via the cadence of {@link android.view.Choreographer} callbacks and
+ * by backpressure when submitting buffers as fast as possible.
+ * Apps can call {@link android.view.Display#getRefreshRate} to query this value.
+ *
+ */
+ public float renderFrameRate;
+
+ /**
* The default display mode.
*/
public int defaultModeId;
@@ -376,6 +386,7 @@ public final class DisplayInfo implements Parcelable {
&& Objects.equals(displayCutout, other.displayCutout)
&& rotation == other.rotation
&& modeId == other.modeId
+ && renderFrameRate == other.renderFrameRate
&& defaultModeId == other.defaultModeId
&& Arrays.equals(supportedModes, other.supportedModes)
&& colorMode == other.colorMode
@@ -428,6 +439,7 @@ public final class DisplayInfo implements Parcelable {
displayCutout = other.displayCutout;
rotation = other.rotation;
modeId = other.modeId;
+ renderFrameRate = other.renderFrameRate;
defaultModeId = other.defaultModeId;
supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length);
colorMode = other.colorMode;
@@ -475,6 +487,7 @@ public final class DisplayInfo implements Parcelable {
displayCutout = DisplayCutout.ParcelableWrapper.readCutoutFromParcel(source);
rotation = source.readInt();
modeId = source.readInt();
+ renderFrameRate = source.readFloat();
defaultModeId = source.readInt();
int nModes = source.readInt();
supportedModes = new Display.Mode[nModes];
@@ -535,6 +548,7 @@ public final class DisplayInfo implements Parcelable {
DisplayCutout.ParcelableWrapper.writeCutoutToParcel(displayCutout, dest, flags);
dest.writeInt(rotation);
dest.writeInt(modeId);
+ dest.writeFloat(renderFrameRate);
dest.writeInt(defaultModeId);
dest.writeInt(supportedModes.length);
for (int i = 0; i < supportedModes.length; i++) {
@@ -764,6 +778,7 @@ public final class DisplayInfo implements Parcelable {
sb.append(presentationDeadlineNanos);
sb.append(", mode ");
sb.append(modeId);
+ sb.append(renderFrameRate);
sb.append(", defaultMode ");
sb.append(defaultModeId);
sb.append(", modes ");
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 30e7a7ac5a45..89a0c05e0e3f 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -1504,6 +1504,7 @@ public final class SurfaceControl implements Parcelable {
public static final class DynamicDisplayInfo {
public DisplayMode[] supportedDisplayModes;
public int activeDisplayModeId;
+ public float renderFrameRate;
public int[] supportedColorModes;
public int activeColorMode;
@@ -1520,6 +1521,7 @@ public final class SurfaceControl implements Parcelable {
return "DynamicDisplayInfo{"
+ "supportedDisplayModes=" + Arrays.toString(supportedDisplayModes)
+ ", activeDisplayModeId=" + activeDisplayModeId
+ + ", renderFrameRate=" + renderFrameRate
+ ", supportedColorModes=" + Arrays.toString(supportedColorModes)
+ ", activeColorMode=" + activeColorMode
+ ", hdrCapabilities=" + hdrCapabilities
@@ -1535,6 +1537,7 @@ public final class SurfaceControl implements Parcelable {
DynamicDisplayInfo that = (DynamicDisplayInfo) o;
return Arrays.equals(supportedDisplayModes, that.supportedDisplayModes)
&& activeDisplayModeId == that.activeDisplayModeId
+ && renderFrameRate == that.renderFrameRate
&& Arrays.equals(supportedColorModes, that.supportedColorModes)
&& activeColorMode == that.activeColorMode
&& Objects.equals(hdrCapabilities, that.hdrCapabilities)
@@ -1544,7 +1547,7 @@ public final class SurfaceControl implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(Arrays.hashCode(supportedDisplayModes), activeDisplayModeId,
- activeColorMode, hdrCapabilities);
+ renderFrameRate, activeColorMode, hdrCapabilities);
}
}
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 019e3bd32be9..a8d8a431666a 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -80,7 +80,7 @@ private:
VsyncEventData vsyncEventData) override;
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
- nsecs_t vsyncPeriod) override;
+ nsecs_t renderPeriod) override;
void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
std::vector<FrameRateOverride> overrides) override;
void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {}
@@ -168,14 +168,14 @@ void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, PhysicalDisp
}
void NativeDisplayEventReceiver::dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
- int32_t modeId, nsecs_t) {
+ int32_t modeId, nsecs_t renderPeriod) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
if (receiverObj.get()) {
ALOGV("receiver %p ~ Invoking mode changed handler.", this);
env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchModeChanged,
- timestamp, displayId.value, modeId);
+ timestamp, displayId.value, modeId, renderPeriod);
ALOGV("receiver %p ~ Returned from mode changed handler.", this);
}
@@ -290,7 +290,7 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) {
gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
gDisplayEventReceiverClassInfo.dispatchModeChanged =
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeChanged",
- "(JJI)V");
+ "(JJIJ)V");
gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides =
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz,
"dispatchFrameRateOverrides",
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 2c5386d6da69..1ed355577a3f 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -109,6 +109,7 @@ static struct {
jmethodID ctor;
jfieldID supportedDisplayModes;
jfieldID activeDisplayModeId;
+ jfieldID renderFrameRate;
jfieldID supportedColorModes;
jfieldID activeColorMode;
jfieldID hdrCapabilities;
@@ -1184,6 +1185,7 @@ static jobject nativeGetDynamicDisplayInfo(JNIEnv* env, jclass clazz, jobject to
env->SetObjectField(object, gDynamicDisplayInfoClassInfo.supportedDisplayModes, modesArray);
env->SetIntField(object, gDynamicDisplayInfoClassInfo.activeDisplayModeId,
info.activeDisplayModeId);
+ env->SetFloatField(object, gDynamicDisplayInfoClassInfo.renderFrameRate, info.renderFrameRate);
jintArray colorModesArray = env->NewIntArray(info.supportedColorModes.size());
if (colorModesArray == NULL) {
@@ -2174,6 +2176,8 @@ int register_android_view_SurfaceControl(JNIEnv* env)
"[Landroid/view/SurfaceControl$DisplayMode;");
gDynamicDisplayInfoClassInfo.activeDisplayModeId =
GetFieldIDOrDie(env, dynamicInfoClazz, "activeDisplayModeId", "I");
+ gDynamicDisplayInfoClassInfo.renderFrameRate =
+ GetFieldIDOrDie(env, dynamicInfoClazz, "renderFrameRate", "F");
gDynamicDisplayInfoClassInfo.supportedColorModes =
GetFieldIDOrDie(env, dynamicInfoClazz, "supportedColorModes", "[I");
gDynamicDisplayInfoClassInfo.activeColorMode =
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 881199964d45..2ac951c3a127 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -237,6 +237,12 @@ final class DisplayDeviceInfo {
public int modeId;
/**
+ * The render frame rate this display is scheduled at.
+ * @see android.view.DisplayInfo#renderFrameRate for more details.
+ */
+ public float renderFrameRate;
+
+ /**
* The default mode of the display.
*/
public int defaultModeId;
@@ -431,6 +437,7 @@ final class DisplayDeviceInfo {
|| width != other.width
|| height != other.height
|| modeId != other.modeId
+ || renderFrameRate != other.renderFrameRate
|| defaultModeId != other.defaultModeId
|| !Arrays.equals(supportedModes, other.supportedModes)
|| !Arrays.equals(supportedColorModes, other.supportedColorModes)
@@ -475,6 +482,7 @@ final class DisplayDeviceInfo {
width = other.width;
height = other.height;
modeId = other.modeId;
+ renderFrameRate = other.renderFrameRate;
defaultModeId = other.defaultModeId;
supportedModes = other.supportedModes;
colorMode = other.colorMode;
@@ -515,6 +523,7 @@ final class DisplayDeviceInfo {
sb.append(name).append("\": uniqueId=\"").append(uniqueId).append("\", ");
sb.append(width).append(" x ").append(height);
sb.append(", modeId ").append(modeId);
+ sb.append(", renderFrameRate ").append(renderFrameRate);
sb.append(", defaultModeId ").append(defaultModeId);
sb.append(", supportedModes ").append(Arrays.toString(supportedModes));
sb.append(", colorMode ").append(colorMode);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index a7e6b7fdb862..cee699b2a5bf 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -35,6 +35,7 @@ import static android.hardware.display.DisplayManagerGlobal.DisplayEvent;
import static android.hardware.display.DisplayViewport.VIEWPORT_EXTERNAL;
import static android.hardware.display.DisplayViewport.VIEWPORT_INTERNAL;
import static android.hardware.display.DisplayViewport.VIEWPORT_VIRTUAL;
+import static android.os.Process.FIRST_APPLICATION_UID;
import static android.os.Process.ROOT_UID;
import android.Manifest;
@@ -881,20 +882,27 @@ public final class DisplayManagerService extends SystemService {
private DisplayInfo getDisplayInfoForFrameRateOverride(DisplayEventReceiver.FrameRateOverride[]
frameRateOverrides, DisplayInfo info, int callingUid) {
- float frameRateHz = 0;
+ float frameRateHz = info.renderFrameRate;
for (DisplayEventReceiver.FrameRateOverride frameRateOverride : frameRateOverrides) {
if (frameRateOverride.uid == callingUid) {
frameRateHz = frameRateOverride.frameRateHz;
break;
}
}
+
if (frameRateHz == 0) {
return info;
}
+ // For non-apps users we always return the physical refresh rate from display mode
+ boolean displayModeReturnsPhysicalRefreshRate =
+ callingUid < FIRST_APPLICATION_UID
+ || CompatChanges.isChangeEnabled(
+ DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE, callingUid);
+
// Override the refresh rate only if it is a divisor of the current
// refresh rate. This calculation needs to be in sync with the native code
- // in RefreshRateConfigs::getFrameRateDivisor
+ // in RefreshRateSelector::getFrameRateDivisor
Display.Mode currentMode = info.getMode();
float numPeriods = currentMode.getRefreshRate() / frameRateHz;
float numPeriodsRound = Math.round(numPeriods);
@@ -918,8 +926,7 @@ public final class DisplayManagerService extends SystemService {
}
overriddenInfo.refreshRateOverride = mode.getRefreshRate();
- if (!CompatChanges.isChangeEnabled(DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE,
- callingUid)) {
+ if (!displayModeReturnsPhysicalRefreshRate) {
overriddenInfo.modeId = mode.getModeId();
}
return overriddenInfo;
@@ -927,8 +934,7 @@ public final class DisplayManagerService extends SystemService {
}
overriddenInfo.refreshRateOverride = frameRateHz;
- if (!CompatChanges.isChangeEnabled(DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE,
- callingUid)) {
+ if (!displayModeReturnsPhysicalRefreshRate) {
overriddenInfo.supportedModes = Arrays.copyOf(info.supportedModes,
info.supportedModes.length + 1);
overriddenInfo.supportedModes[overriddenInfo.supportedModes.length - 1] =
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index dc5c80f20d78..ee53b6087143 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -226,6 +226,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private SurfaceControl.DisplayMode[] mSfDisplayModes;
// The active display mode in SurfaceFlinger
private SurfaceControl.DisplayMode mActiveSfDisplayMode;
+ // The active display vsync period in SurfaceFlinger
+ private float mActiveRenderFrameRate;
private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides =
new DisplayEventReceiver.FrameRateOverride[0];
@@ -267,7 +269,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
SurfaceControl.DesiredDisplayModeSpecs modeSpecs) {
boolean changed = updateDisplayModesLocked(
dynamicInfo.supportedDisplayModes, dynamicInfo.preferredBootDisplayMode,
- dynamicInfo.activeDisplayModeId, modeSpecs);
+ dynamicInfo.activeDisplayModeId, dynamicInfo.renderFrameRate, modeSpecs);
changed |= updateStaticInfo(staticInfo);
changed |= updateColorModesLocked(dynamicInfo.supportedColorModes,
dynamicInfo.activeColorMode);
@@ -283,7 +285,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
public boolean updateDisplayModesLocked(
SurfaceControl.DisplayMode[] displayModes, int preferredSfDisplayModeId,
- int activeSfDisplayModeId, SurfaceControl.DesiredDisplayModeSpecs modeSpecs) {
+ int activeSfDisplayModeId, float renderFrameRate,
+ SurfaceControl.DesiredDisplayModeSpecs modeSpecs) {
mSfDisplayModes = Arrays.copyOf(displayModes, displayModes.length);
mActiveSfDisplayMode = getModeById(displayModes, activeSfDisplayModeId);
SurfaceControl.DisplayMode preferredSfDisplayMode =
@@ -379,6 +382,16 @@ final class LocalDisplayAdapter extends DisplayAdapter {
sendTraversalRequestLocked();
}
+ boolean renderFrameRateChanged = false;
+
+ if (mActiveRenderFrameRate > 0 && mActiveRenderFrameRate != renderFrameRate) {
+ Slog.d(TAG, "The render frame rate was changed from SurfaceFlinger or the display"
+ + " device to " + renderFrameRate);
+ mActiveRenderFrameRate = renderFrameRate;
+ renderFrameRateChanged = true;
+ sendTraversalRequestLocked();
+ }
+
// Check whether surface flinger spontaneously changed display config specs out from
// under us. If so, schedule a traversal to reapply our display config specs.
if (mDisplayModeSpecs.baseModeId != INVALID_MODE_ID) {
@@ -398,7 +411,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
boolean recordsChanged = records.size() != mSupportedModes.size() || modesAdded;
// If the records haven't changed then we're done here.
if (!recordsChanged) {
- return activeModeChanged || preferredModeChanged;
+ return activeModeChanged || preferredModeChanged || renderFrameRateChanged;
}
mSupportedModes.clear();
@@ -410,16 +423,19 @@ final class LocalDisplayAdapter extends DisplayAdapter {
if (mDefaultModeId == INVALID_MODE_ID) {
mDefaultModeId = activeRecord.mMode.getModeId();
mDefaultModeGroup = mActiveSfDisplayMode.group;
+ mActiveRenderFrameRate = renderFrameRate;
} else if (modesAdded && activeModeChanged) {
Slog.d(TAG, "New display modes are added and the active mode has changed, "
+ "use active mode as default mode.");
mDefaultModeId = activeRecord.mMode.getModeId();
mDefaultModeGroup = mActiveSfDisplayMode.group;
+ mActiveRenderFrameRate = renderFrameRate;
} else if (findSfDisplayModeIdLocked(mDefaultModeId, mDefaultModeGroup) < 0) {
Slog.w(TAG, "Default display mode no longer available, using currently"
+ " active mode as default.");
mDefaultModeId = activeRecord.mMode.getModeId();
mDefaultModeGroup = mActiveSfDisplayMode.group;
+ mActiveRenderFrameRate = renderFrameRate;
}
// Determine whether the display mode specs' base mode is still there.
@@ -620,6 +636,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mInfo.width = mActiveSfDisplayMode.width;
mInfo.height = mActiveSfDisplayMode.height;
mInfo.modeId = mActiveModeId;
+ mInfo.renderFrameRate = mActiveRenderFrameRate;
mInfo.defaultModeId = getPreferredModeId();
mInfo.supportedModes = getDisplayModes(mSupportedModes);
mInfo.colorMode = mActiveColorMode;
@@ -995,8 +1012,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
updateDeviceInfoLocked();
}
- public void onActiveDisplayModeChangedLocked(int sfModeId) {
- if (updateActiveModeLocked(sfModeId)) {
+ public void onActiveDisplayModeChangedLocked(int sfModeId, float renderFrameRate) {
+ if (updateActiveModeLocked(sfModeId, renderFrameRate)) {
updateDeviceInfoLocked();
}
}
@@ -1008,8 +1025,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
- public boolean updateActiveModeLocked(int activeSfModeId) {
- if (mActiveSfDisplayMode.id == activeSfModeId) {
+ public boolean updateActiveModeLocked(int activeSfModeId, float renderFrameRate) {
+ if (mActiveSfDisplayMode.id == activeSfModeId
+ && mActiveRenderFrameRate == renderFrameRate) {
return false;
}
mActiveSfDisplayMode = getModeById(mSfDisplayModes, activeSfModeId);
@@ -1018,6 +1036,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
Slog.w(TAG, "In unknown mode after setting allowed modes"
+ ", activeModeId=" + activeSfModeId);
}
+ mActiveRenderFrameRate = renderFrameRate;
return true;
}
@@ -1114,6 +1133,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
pw.println(" " + sfDisplayMode);
}
pw.println("mActiveSfDisplayMode=" + mActiveSfDisplayMode);
+ pw.println("mActiveRenderFrameRate=" + mActiveRenderFrameRate);
pw.println("mSupportedModes=");
for (int i = 0; i < mSupportedModes.size(); i++) {
pw.println(" " + mSupportedModes.valueAt(i));
@@ -1288,7 +1308,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
public interface DisplayEventListener {
void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected);
- void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId);
+ void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId,
+ long renderPeriod);
void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
DisplayEventReceiver.FrameRateOverride[] overrides);
@@ -1309,8 +1330,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
@Override
- public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) {
- mListener.onModeChanged(timestampNanos, physicalDisplayId, modeId);
+ public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId,
+ long renderPeriod) {
+ mListener.onModeChanged(timestampNanos, physicalDisplayId, modeId, renderPeriod);
}
@Override
@@ -1333,12 +1355,14 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
@Override
- public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) {
+ public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId,
+ long renderPeriod) {
if (DEBUG) {
Slog.d(TAG, "onModeChanged("
+ "timestampNanos=" + timestampNanos
+ ", physicalDisplayId=" + physicalDisplayId
- + ", modeId=" + modeId + ")");
+ + ", modeId=" + modeId
+ + ", renderPeriod=" + renderPeriod + ")");
}
synchronized (getSyncRoot()) {
LocalDisplayDevice device = mDevices.get(physicalDisplayId);
@@ -1349,7 +1373,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
return;
}
- device.onActiveDisplayModeChangedLocked(modeId);
+ float renderFrameRate = 1e9f / renderPeriod;
+ device.onActiveDisplayModeChangedLocked(modeId, renderFrameRate);
}
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 8dd169bf4bf6..c7b27deb420d 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -377,6 +377,7 @@ final class LogicalDisplay {
mBaseDisplayInfo.logicalHeight = maskedHeight;
mBaseDisplayInfo.rotation = Surface.ROTATION_0;
mBaseDisplayInfo.modeId = deviceInfo.modeId;
+ mBaseDisplayInfo.renderFrameRate = deviceInfo.renderFrameRate;
mBaseDisplayInfo.defaultModeId = deviceInfo.defaultModeId;
mBaseDisplayInfo.supportedModes = Arrays.copyOf(
deviceInfo.supportedModes, deviceInfo.supportedModes.length);
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 0e11b53e0257..3e67f0a466d7 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -340,6 +340,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
mInfo.width = mode.getPhysicalWidth();
mInfo.height = mode.getPhysicalHeight();
mInfo.modeId = mode.getModeId();
+ mInfo.renderFrameRate = mode.getRefreshRate();
mInfo.defaultModeId = mModes[0].getModeId();
mInfo.supportedModes = mModes;
mInfo.densityDpi = rawMode.mDensityDpi;
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index d0e518b876dd..ad8d71514832 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -446,6 +446,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
mInfo.width = mWidth;
mInfo.height = mHeight;
mInfo.modeId = mMode.getModeId();
+ mInfo.renderFrameRate = mMode.getRefreshRate();
mInfo.defaultModeId = mMode.getModeId();
mInfo.supportedModes = new Display.Mode[] { mMode };
mInfo.densityDpi = mDensityDpi;
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index c759d98561f9..e8327018e144 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -646,6 +646,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
mInfo.width = mWidth;
mInfo.height = mHeight;
mInfo.modeId = mMode.getModeId();
+ mInfo.renderFrameRate = mMode.getRefreshRate();
mInfo.defaultModeId = mMode.getModeId();
mInfo.supportedModes = new Display.Mode[] { mMode };
mInfo.presentationDeadlineNanos = 1000000000L / (int) mRefreshRate; // 1 frame
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index be32b79a9d13..f10597114a5e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -212,7 +212,7 @@ public class LocalDisplayAdapterTest {
SurfaceControl.DisplayMode displayMode = createFakeDisplayMode(0, 1920, 1080, 0);
displayMode.supportedHdrTypes = new int[0];
FakeDisplay display = new FakeDisplay(PORT_A, new SurfaceControl.DisplayMode[]{displayMode},
- 0);
+ 0, 0);
setUpDisplay(display);
updateAvailableDisplays();
mAdapter.registerLocked();
@@ -393,7 +393,7 @@ public class LocalDisplayAdapterTest {
SurfaceControl.DisplayMode displayMode = createFakeDisplayMode(0, 1920, 1080, 60f);
SurfaceControl.DisplayMode[] modes =
new SurfaceControl.DisplayMode[]{displayMode};
- FakeDisplay display = new FakeDisplay(PORT_A, modes, 0);
+ FakeDisplay display = new FakeDisplay(PORT_A, modes, 0, displayMode.refreshRate);
setUpDisplay(display);
updateAvailableDisplays();
mAdapter.registerLocked();
@@ -449,7 +449,7 @@ public class LocalDisplayAdapterTest {
SurfaceControl.DisplayMode displayMode = createFakeDisplayMode(0, 1920, 1080, 60f);
SurfaceControl.DisplayMode[] modes =
new SurfaceControl.DisplayMode[]{displayMode};
- FakeDisplay display = new FakeDisplay(PORT_A, modes, 0);
+ FakeDisplay display = new FakeDisplay(PORT_A, modes, 0, displayMode.refreshRate);
setUpDisplay(display);
updateAvailableDisplays();
mAdapter.registerLocked();
@@ -504,7 +504,7 @@ public class LocalDisplayAdapterTest {
createFakeDisplayMode(0, 1920, 1080, 60f),
createFakeDisplayMode(1, 1920, 1080, 50f)
};
- FakeDisplay display = new FakeDisplay(PORT_A, modes, /* activeMode */ 0);
+ FakeDisplay display = new FakeDisplay(PORT_A, modes, /* activeMode */ 0, 60f);
setUpDisplay(display);
updateAvailableDisplays();
mAdapter.registerLocked();
@@ -538,6 +538,49 @@ public class LocalDisplayAdapterTest {
}
@Test
+ public void testAfterDisplayChange_RenderFrameRateIsUpdated() throws Exception {
+ SurfaceControl.DisplayMode[] modes = new SurfaceControl.DisplayMode[]{
+ createFakeDisplayMode(0, 1920, 1080, 60f),
+ };
+ FakeDisplay display = new FakeDisplay(PORT_A, modes, /* activeMode */ 0,
+ /* renderFrameRate */30f);
+ setUpDisplay(display);
+ updateAvailableDisplays();
+ mAdapter.registerLocked();
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+ assertThat(mListener.addedDisplays.size()).isEqualTo(1);
+ assertThat(mListener.changedDisplays).isEmpty();
+
+ DisplayDeviceInfo displayDeviceInfo = mListener.addedDisplays.get(0)
+ .getDisplayDeviceInfoLocked();
+
+ Display.Mode activeMode = getModeById(displayDeviceInfo, displayDeviceInfo.modeId);
+ assertThat(activeMode.matches(1920, 1080, 60f)).isTrue();
+ assertEquals(Float.floatToIntBits(30f),
+ Float.floatToIntBits(displayDeviceInfo.renderFrameRate));
+
+ // Change the render frame rate
+ display.dynamicInfo.renderFrameRate = 60f;
+ setUpDisplay(display);
+ mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+ assertTrue(mListener.traversalRequested);
+ assertThat(mListener.addedDisplays.size()).isEqualTo(1);
+ assertThat(mListener.changedDisplays.size()).isEqualTo(1);
+
+ DisplayDevice displayDevice = mListener.changedDisplays.get(0);
+ displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
+ displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked();
+
+ activeMode = getModeById(displayDeviceInfo, displayDeviceInfo.modeId);
+ assertThat(activeMode.matches(1920, 1080, 60f)).isTrue();
+ assertEquals(Float.floatToIntBits(60f),
+ Float.floatToIntBits(displayDeviceInfo.renderFrameRate));
+ }
+
+ @Test
public void testAfterDisplayChange_HdrCapabilitiesAreUpdated() throws Exception {
FakeDisplay display = new FakeDisplay(PORT_A);
Display.HdrCapabilities initialHdrCapabilities = new Display.HdrCapabilities(new int[0],
@@ -722,7 +765,7 @@ public class LocalDisplayAdapterTest {
createFakeDisplayMode(1, 1920, 1080, 50f)
};
final int activeMode = 0;
- FakeDisplay display = new FakeDisplay(PORT_A, modes, activeMode);
+ FakeDisplay display = new FakeDisplay(PORT_A, modes, activeMode, 60f);
display.desiredDisplayModeSpecs.defaultMode = 1;
setUpDisplay(display);
@@ -979,11 +1022,13 @@ public class LocalDisplayAdapterTest {
dynamicInfo.activeDisplayModeId = 0;
}
- private FakeDisplay(int port, SurfaceControl.DisplayMode[] modes, int activeMode) {
+ private FakeDisplay(int port, SurfaceControl.DisplayMode[] modes, int activeMode,
+ float renderFrameRate) {
address = createDisplayAddress(port);
info = createFakeDisplayInfo();
dynamicInfo.supportedDisplayModes = modes;
dynamicInfo.activeDisplayModeId = activeMode;
+ dynamicInfo.renderFrameRate = renderFrameRate;
}
private FakeDisplay(int port, SurfaceControl.DisplayMode[] modes, int activeMode,
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 5af05584c07a..069feedbe6b6 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -1164,6 +1164,76 @@ public class DisplayManagerServiceTest {
}
/**
+ * Tests that there is a display change notification if the render frame rate is updated
+ */
+ @Test
+ public void testShouldNotifyChangeWhenDisplayInfoRenderFrameRateChanged() throws Exception {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mShortMockedInjector);
+ DisplayManagerService.BinderService displayManagerBinderService =
+ displayManager.new BinderService();
+ registerDefaultDisplays(displayManager);
+ displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+ FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, new float[]{60f});
+ FakeDisplayManagerCallback callback = registerDisplayListenerCallback(displayManager,
+ displayManagerBinderService, displayDevice);
+
+ updateRenderFrameRate(displayManager, displayDevice, 30f);
+ assertTrue(callback.mDisplayChangedCalled);
+ callback.clear();
+
+ updateRenderFrameRate(displayManager, displayDevice, 30f);
+ assertFalse(callback.mDisplayChangedCalled);
+
+ updateRenderFrameRate(displayManager, displayDevice, 20f);
+ assertTrue(callback.mDisplayChangedCalled);
+ callback.clear();
+ }
+
+ /**
+ * Tests that the DisplayInfo is updated correctly with a render frame rate
+ */
+ @Test
+ public void testDisplayInfoRenderFrameRate() throws Exception {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mShortMockedInjector);
+ DisplayManagerService.BinderService displayManagerBinderService =
+ displayManager.new BinderService();
+ registerDefaultDisplays(displayManager);
+ displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+ FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
+ new float[]{60f, 30f, 20f});
+ int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+ displayDevice);
+ DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+ assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
+
+ updateRenderFrameRate(displayManager, displayDevice, 20f);
+ displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+ assertEquals(20f, displayInfo.getRefreshRate(), 0.01f);
+ }
+
+ /**
+ * Tests that the mode reflects the render frame rate is in compat mode
+ */
+ @Test
+ @DisableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
+ public void testDisplayInfoRenderFrameRateModeCompat() throws Exception {
+ testDisplayInfoRenderFrameRateModeCompat(/*compatChangeEnabled*/ false);
+ }
+
+ /**
+ * Tests that the mode reflects the physical display refresh rate when not in compat mode.
+ */
+ @Test
+ @EnableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
+ public void testDisplayInfoRenderFrameRateMode() throws Exception {
+ testDisplayInfoRenderFrameRateModeCompat(/*compatChangeEnabled*/ true);
+ }
+
+ /**
* Tests that EVENT_DISPLAY_ADDED is sent when a display is added.
*/
@Test
@@ -1383,6 +1453,34 @@ public class DisplayManagerServiceTest {
assertEquals(expectedMode, displayInfo.getMode());
}
+ private void testDisplayInfoRenderFrameRateModeCompat(boolean compatChangeEnabled)
+ throws Exception {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mShortMockedInjector);
+ DisplayManagerService.BinderService displayManagerBinderService =
+ displayManager.new BinderService();
+ registerDefaultDisplays(displayManager);
+ displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+ FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
+ new float[]{60f, 30f, 20f});
+ int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+ displayDevice);
+ DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+ assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
+
+ updateRenderFrameRate(displayManager, displayDevice, 20f);
+ displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+ assertEquals(20f, displayInfo.getRefreshRate(), 0.01f);
+ Display.Mode expectedMode;
+ if (compatChangeEnabled) {
+ expectedMode = new Display.Mode(1, 100, 200, 60f);
+ } else {
+ expectedMode = new Display.Mode(3, 100, 200, 20f);
+ }
+ assertEquals(expectedMode, displayInfo.getMode());
+ }
+
private void testDisplayInfoNonNativeFrameRateOverrideMode(boolean compatChangeEnabled) {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
@@ -1452,6 +1550,15 @@ public class DisplayManagerServiceTest {
updateDisplayDeviceInfo(displayManager, displayDevice, displayDeviceInfo);
}
+ private void updateRenderFrameRate(DisplayManagerService displayManager,
+ FakeDisplayDevice displayDevice,
+ float renderFrameRate) {
+ DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
+ displayDeviceInfo.copyFrom(displayDevice.getDisplayDeviceInfoLocked());
+ displayDeviceInfo.renderFrameRate = renderFrameRate;
+ updateDisplayDeviceInfo(displayManager, displayDevice, displayDeviceInfo);
+ }
+
private void updateModeId(DisplayManagerService displayManager,
FakeDisplayDevice displayDevice,
int modeId) {
@@ -1491,6 +1598,7 @@ public class DisplayManagerServiceTest {
new Display.Mode(i + 1, width, height, refreshRates[i]);
}
displayDeviceInfo.modeId = 1;
+ displayDeviceInfo.renderFrameRate = displayDeviceInfo.supportedModes[0].getRefreshRate();
displayDeviceInfo.width = width;
displayDeviceInfo.height = height;
final Rect zeroRect = new Rect();