diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index edc59931d4f86..01779047a0cd0 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -1111,15 +1111,12 @@ public final class Choreographer { */ public static class FrameData { private long mFrameTimeNanos; - private final FrameTimeline[] mFrameTimelines = - new FrameTimeline[DisplayEventReceiver.VsyncEventData.FRAME_TIMELINES_LENGTH]; + private FrameTimeline[] mFrameTimelines; private int mPreferredFrameTimelineIndex; private boolean mInCallback = false; FrameData() { - for (int i = 0; i < mFrameTimelines.length; i++) { - mFrameTimelines[i] = new FrameTimeline(); - } + allocateFrameTimelines(DisplayEventReceiver.VsyncEventData.FRAME_TIMELINES_CAPACITY); } /** The time in nanoseconds when the frame started being rendered. */ @@ -1157,21 +1154,29 @@ public final class Choreographer { } } + private void allocateFrameTimelines(int length) { + mFrameTimelines = new FrameTimeline[length]; + for (int i = 0; i < mFrameTimelines.length; i++) { + mFrameTimelines[i] = new FrameTimeline(); + } + } + /** * Update the frame data with a {@code DisplayEventReceiver.VsyncEventData} received from * native. */ FrameTimeline update( long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) { - if (vsyncEventData.frameTimelines.length != mFrameTimelines.length) { - throw new IllegalStateException( - "Length of native frame timelines received does not match Java. Did " - + "FRAME_TIMELINES_LENGTH or kFrameTimelinesLength (native) " - + "change?"); + if (vsyncEventData.frameTimelinesLength == 0) { + throw new IllegalArgumentException( + "Vsync event timelines length must be greater than 0"); + } + if (mFrameTimelines.length != vsyncEventData.frameTimelinesLength) { + allocateFrameTimelines(vsyncEventData.frameTimelinesLength); } mFrameTimeNanos = frameTimeNanos; mPreferredFrameTimelineIndex = vsyncEventData.preferredFrameTimelineIndex; - for (int i = 0; i < vsyncEventData.frameTimelines.length; i++) { + for (int i = 0; i < mFrameTimelines.length; i++) { DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline = vsyncEventData.frameTimelines[i]; mFrameTimelines[i].update(frameTimeline.vsyncId, diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java index 54db34e788e9f..50246f6007536 100644 --- a/core/java/android/view/DisplayEventReceiver.java +++ b/core/java/android/view/DisplayEventReceiver.java @@ -152,11 +152,10 @@ public abstract class DisplayEventReceiver { * @hide */ public static final class VsyncEventData { - // The amount of frame timeline choices. - // Must be in sync with VsyncEventData::kFrameTimelinesLength in - // frameworks/native/libs/gui/include/gui/VsyncEventData.h. If they do not match, a runtime - // assertion is thrown when Choreographer is processing VsyncEventData. - static final int FRAME_TIMELINES_LENGTH = 7; + // The max capacity of frame timeline choices. + // Must be in sync with VsyncEventData::kFrameTimelinesCapacity in + // frameworks/native/libs/gui/include/gui/VsyncEventData.h + static final int FRAME_TIMELINES_CAPACITY = 7; public static class FrameTimeline { FrameTimeline() {} @@ -198,8 +197,10 @@ public abstract class DisplayEventReceiver { public int preferredFrameTimelineIndex = 0; + public int frameTimelinesLength = 0; + VsyncEventData() { - frameTimelines = new FrameTimeline[FRAME_TIMELINES_LENGTH]; + frameTimelines = new FrameTimeline[FRAME_TIMELINES_CAPACITY]; for (int i = 0; i < frameTimelines.length; i++) { frameTimelines[i] = new FrameTimeline(); } @@ -208,14 +209,16 @@ public abstract class DisplayEventReceiver { // Called from native code. @SuppressWarnings("unused") VsyncEventData(FrameTimeline[] frameTimelines, int preferredFrameTimelineIndex, - long frameInterval) { + int frameTimelinesLength, long frameInterval) { this.frameTimelines = frameTimelines; this.preferredFrameTimelineIndex = preferredFrameTimelineIndex; + this.frameTimelinesLength = frameTimelinesLength; this.frameInterval = frameInterval; } void copyFrom(VsyncEventData other) { preferredFrameTimelineIndex = other.preferredFrameTimelineIndex; + frameTimelinesLength = other.frameTimelinesLength; frameInterval = other.frameInterval; for (int i = 0; i < frameTimelines.length; i++) { frameTimelines[i].copyFrom(other.frameTimelines[i]); diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp index 410b44161cf64..624bd5f4da23b 100644 --- a/core/jni/android_view_DisplayEventReceiver.cpp +++ b/core/jni/android_view_DisplayEventReceiver.cpp @@ -63,6 +63,7 @@ static struct { jfieldID frameInterval; jfieldID preferredFrameTimelineIndex; + jfieldID frameTimelinesLength; jfieldID frameTimelines; } vsyncEventDataClassInfo; @@ -127,7 +128,7 @@ void NativeDisplayEventReceiver::dispose() { static jobject createJavaVsyncEventData(JNIEnv* env, VsyncEventData vsyncEventData) { ScopedLocalRef frameTimelineObjs(env, - env->NewObjectArray(VsyncEventData::kFrameTimelinesLength, + env->NewObjectArray(vsyncEventData.frameTimelinesLength, gDisplayEventReceiverClassInfo .frameTimelineClassInfo.clazz, /*initial element*/ NULL)); @@ -137,7 +138,7 @@ static jobject createJavaVsyncEventData(JNIEnv* env, VsyncEventData vsyncEventDa env->ExceptionClear(); return NULL; } - for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { + for (int i = 0; i < vsyncEventData.frameTimelinesLength; i++) { VsyncEventData::FrameTimeline frameTimeline = vsyncEventData.frameTimelines[i]; ScopedLocalRef frameTimelineObj(env, @@ -159,7 +160,7 @@ static jobject createJavaVsyncEventData(JNIEnv* env, VsyncEventData vsyncEventDa return env->NewObject(gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.init, frameTimelineObjs.get(), vsyncEventData.preferredFrameTimelineIndex, - vsyncEventData.frameInterval); + vsyncEventData.frameTimelinesLength, vsyncEventData.frameInterval); } void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, @@ -175,6 +176,10 @@ void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDispla gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo .preferredFrameTimelineIndex, vsyncEventData.preferredFrameTimelineIndex); + env->SetIntField(vsyncEventDataObj.get(), + gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo + .frameTimelinesLength, + vsyncEventData.frameTimelinesLength); env->SetLongField(vsyncEventDataObj.get(), gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameInterval, vsyncEventData.frameInterval); @@ -186,7 +191,7 @@ void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDispla gDisplayEventReceiverClassInfo .vsyncEventDataClassInfo .frameTimelines))); - for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { + for (int i = 0; i < vsyncEventData.frameTimelinesLength; i++) { VsyncEventData::FrameTimeline& frameTimeline = vsyncEventData.frameTimelines[i]; ScopedLocalRef frameTimelineObj(env, env->GetObjectArrayElement(frameTimelinesObj.get(), i)); @@ -392,11 +397,14 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) { GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz, "", "([Landroid/view/" - "DisplayEventReceiver$VsyncEventData$FrameTimeline;IJ)V"); + "DisplayEventReceiver$VsyncEventData$FrameTimeline;IIJ)V"); gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.preferredFrameTimelineIndex = GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz, "preferredFrameTimelineIndex", "I"); + gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameTimelinesLength = + GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz, + "frameTimelinesLength", "I"); gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameInterval = GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz, "frameInterval", "J");