summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Rachel Lee <rnlee@google.com> 2022-01-18 20:30:18 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2022-01-18 20:30:18 +0000
commit34f56bf78adbd20dbe779e6804af1ad5fd821c70 (patch)
treee020754ff93f4bc6fd2f7f228be050642fdfb3b2
parent87c13a545d7d8e5feabb13ca2c396969f0c21369 (diff)
parent5af0462a57e7df4aef44f57250c5a3e0ed8514d7 (diff)
Merge "Implement Java Choreographer multi frame timeline."
-rw-r--r--core/api/current.txt18
-rw-r--r--core/java/android/view/Choreographer.java212
-rw-r--r--core/java/android/view/DisplayEventReceiver.java53
-rw-r--r--core/jni/android_view_DisplayEventReceiver.cpp63
4 files changed, 314 insertions, 32 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index ea6ab0ce14a1..280eb8023766 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -48079,15 +48079,33 @@ package android.view {
public final class Choreographer {
method public static android.view.Choreographer getInstance();
+ method public void postExtendedFrameCallback(@NonNull android.view.Choreographer.ExtendedFrameCallback);
method public void postFrameCallback(android.view.Choreographer.FrameCallback);
method public void postFrameCallbackDelayed(android.view.Choreographer.FrameCallback, long);
+ method public void removeExtendedFrameCallback(@Nullable android.view.Choreographer.ExtendedFrameCallback);
method public void removeFrameCallback(android.view.Choreographer.FrameCallback);
}
+ public static interface Choreographer.ExtendedFrameCallback {
+ method public void onVsync(@NonNull android.view.Choreographer.FrameData);
+ }
+
public static interface Choreographer.FrameCallback {
method public void doFrame(long);
}
+ public static class Choreographer.FrameData {
+ method public long getFrameTimeNanos();
+ method @NonNull public android.view.Choreographer.FrameTimeline[] getFrameTimelines();
+ method @NonNull public android.view.Choreographer.FrameTimeline getPreferredFrameTimeline();
+ }
+
+ public static class Choreographer.FrameTimeline {
+ method public long getDeadlineNanos();
+ method public long getExpectedPresentTimeNanos();
+ method public long getVsyncId();
+ }
+
public interface CollapsibleActionView {
method public void onActionViewCollapsed();
method public void onActionViewExpanded();
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index be172f748b55..9b8523f9b006 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -19,6 +19,9 @@ package android.view;
import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP;
import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.FrameInfo;
@@ -151,10 +154,15 @@ public final class Choreographer {
private static final int MSG_DO_SCHEDULE_VSYNC = 1;
private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
- // All frame callbacks posted by applications have this token.
+ // All frame callbacks posted by applications have this token or EXTENDED_FRAME_CALLBACK_TOKEN.
private static final Object FRAME_CALLBACK_TOKEN = new Object() {
public String toString() { return "FRAME_CALLBACK_TOKEN"; }
};
+ private static final Object EXTENDED_FRAME_CALLBACK_TOKEN = new Object() {
+ public String toString() {
+ return "EXTENDED_FRAME_CALLBACK_TOKEN";
+ }
+ };
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final Object mLock = new Object();
@@ -484,6 +492,24 @@ public final class Choreographer {
}
/**
+ * Posts an extended frame callback to run on the next frame.
+ * <p>
+ * The callback runs once then is automatically removed.
+ * </p>
+ *
+ * @param callback The extended frame callback to run during the next frame.
+ *
+ * @see #removeExtendedFrameCallback
+ */
+ public void postExtendedFrameCallback(@NonNull ExtendedFrameCallback callback) {
+ if (callback == null) {
+ throw new IllegalArgumentException("callback must not be null");
+ }
+
+ postCallbackDelayedInternal(CALLBACK_ANIMATION, callback, EXTENDED_FRAME_CALLBACK_TOKEN, 0);
+ }
+
+ /**
* Removes callbacks that have the specified action and token.
*
* @param callbackType The callback type.
@@ -573,6 +599,21 @@ public final class Choreographer {
}
/**
+ * Removes a previously posted extended frame callback.
+ *
+ * @param callback The extended frame callback to remove.
+ *
+ * @see #postExtendedFrameCallback
+ */
+ public void removeExtendedFrameCallback(@Nullable ExtendedFrameCallback callback) {
+ if (callback == null) {
+ throw new IllegalArgumentException("callback must not be null");
+ }
+
+ removeCallbacksInternal(CALLBACK_ANIMATION, callback, EXTENDED_FRAME_CALLBACK_TOKEN);
+ }
+
+ /**
* Gets the time when the current frame started.
* <p>
* This method provides the time in milliseconds when the frame started being rendered.
@@ -673,7 +714,7 @@ public final class Choreographer {
* @hide
*/
public long getVsyncId() {
- return mLastVsyncEventData.id;
+ return mLastVsyncEventData.preferredFrameTimeline().vsyncId;
}
/**
@@ -684,7 +725,7 @@ public final class Choreographer {
* @hide
*/
public long getFrameDeadline() {
- return mLastVsyncEventData.frameDeadline;
+ return mLastVsyncEventData.preferredFrameTimeline().deadline;
}
void setFPSDivisor(int divisor) {
@@ -705,8 +746,9 @@ public final class Choreographer {
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW,
- "Choreographer#doFrame " + vsyncEventData.id);
+ "Choreographer#doFrame " + vsyncEventData.preferredFrameTimeline().vsyncId);
}
+ FrameData frameData = new FrameData(frameTimeNanos, vsyncEventData);
synchronized (mLock) {
if (!mFrameScheduled) {
traceMessage("Frame not scheduled");
@@ -737,6 +779,7 @@ public final class Choreographer {
+ "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
}
frameTimeNanos = startNanos - lastFrameOffset;
+ frameData.setFrameTimeNanos(-lastFrameOffset);
}
if (frameTimeNanos < mLastFrameTimeNanos) {
@@ -758,8 +801,10 @@ public final class Choreographer {
}
}
- mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, vsyncEventData.id,
- vsyncEventData.frameDeadline, startNanos, vsyncEventData.frameInterval);
+ mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos,
+ vsyncEventData.preferredFrameTimeline().vsyncId,
+ vsyncEventData.preferredFrameTimeline().deadline, startNanos,
+ vsyncEventData.frameInterval);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
mLastFrameIntervalNanos = frameIntervalNanos;
@@ -769,17 +814,17 @@ public final class Choreographer {
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
- doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos, frameIntervalNanos);
+ doCallbacks(Choreographer.CALLBACK_INPUT, frameData, frameIntervalNanos);
mFrameInfo.markAnimationsStart();
- doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos, frameIntervalNanos);
- doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos,
+ doCallbacks(Choreographer.CALLBACK_ANIMATION, frameData, frameIntervalNanos);
+ doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameData,
frameIntervalNanos);
mFrameInfo.markPerformTraversalsStart();
- doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos, frameIntervalNanos);
+ doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameData, frameIntervalNanos);
- doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos, frameIntervalNanos);
+ doCallbacks(Choreographer.CALLBACK_COMMIT, frameData, frameIntervalNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
@@ -793,8 +838,9 @@ public final class Choreographer {
}
}
- void doCallbacks(int callbackType, long frameTimeNanos, long frameIntervalNanos) {
+ void doCallbacks(int callbackType, FrameData frameData, long frameIntervalNanos) {
CallbackRecord callbacks;
+ long frameTimeNanos = frameData.mFrameTimeNanos;
synchronized (mLock) {
// We use "now" to determine when callbacks become due because it's possible
// for earlier processing phases in a frame to post callbacks that should run
@@ -831,6 +877,7 @@ public final class Choreographer {
}
frameTimeNanos = now - lastFrameOffset;
mLastFrameTimeNanos = frameTimeNanos;
+ frameData.setFrameTimeNanos(frameTimeNanos);
}
}
}
@@ -842,7 +889,7 @@ public final class Choreographer {
+ ", action=" + c.action + ", token=" + c.token
+ ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
}
- c.run(frameTimeNanos);
+ c.run(frameData);
}
} finally {
synchronized (mLock) {
@@ -942,6 +989,130 @@ public final class Choreographer {
public void doFrame(long frameTimeNanos);
}
+ /** Holds data that describes one possible VSync frame event to render at. */
+ public static class FrameTimeline {
+ static final FrameTimeline INVALID_FRAME_TIMELINE = new FrameTimeline(
+ FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE);
+
+ FrameTimeline(long vsyncId, long expectedPresentTimeNanos, long deadlineNanos) {
+ this.mVsyncId = vsyncId;
+ this.mExpectedPresentTimeNanos = expectedPresentTimeNanos;
+ this.mDeadlineNanos = deadlineNanos;
+ }
+
+ private long mVsyncId;
+ private long mExpectedPresentTimeNanos;
+ private long mDeadlineNanos;
+
+ /**
+ * The id that corresponds to this frame timeline, used to correlate a frame
+ * produced by HWUI with the timeline data stored in Surface Flinger.
+ */
+ public long getVsyncId() {
+ return mVsyncId;
+ }
+
+ /** Sets the vsync ID. */
+ void resetVsyncId() {
+ mVsyncId = FrameInfo.INVALID_VSYNC_ID;
+ }
+
+ /**
+ * The time in {@link System#nanoTime()} timebase which this frame is expected to be
+ * presented.
+ */
+ public long getExpectedPresentTimeNanos() {
+ return mExpectedPresentTimeNanos;
+ }
+
+ /**
+ * The time in {@link System#nanoTime()} timebase which this frame needs to be ready by.
+ */
+ public long getDeadlineNanos() {
+ return mDeadlineNanos;
+ }
+ }
+
+ /**
+ * The payload for {@link ExtendedFrameCallback} which includes frame information such as when
+ * the frame started being rendered, and multiple possible frame timelines and their
+ * information including deadline and expected present time.
+ */
+ public static class FrameData {
+ static final FrameTimeline[] INVALID_FRAME_TIMELINES = new FrameTimeline[0];
+ FrameData() {
+ this.mFrameTimelines = INVALID_FRAME_TIMELINES;
+ this.mPreferredFrameTimeline = FrameTimeline.INVALID_FRAME_TIMELINE;
+ }
+
+ FrameData(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) {
+ FrameTimeline[] frameTimelines =
+ new FrameTimeline[vsyncEventData.frameTimelines.length];
+ for (int i = 0; i < vsyncEventData.frameTimelines.length; i++) {
+ DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline =
+ vsyncEventData.frameTimelines[i];
+ frameTimelines[i] = new FrameTimeline(frameTimeline.vsyncId,
+ frameTimeline.expectedPresentTime, frameTimeline.deadline);
+ }
+ this.mFrameTimeNanos = frameTimeNanos;
+ this.mFrameTimelines = frameTimelines;
+ this.mPreferredFrameTimeline =
+ frameTimelines[vsyncEventData.preferredFrameTimelineIndex];
+ }
+
+ private long mFrameTimeNanos;
+ private final FrameTimeline[] mFrameTimelines;
+ private final FrameTimeline mPreferredFrameTimeline;
+
+ void setFrameTimeNanos(long frameTimeNanos) {
+ mFrameTimeNanos = frameTimeNanos;
+ for (FrameTimeline ft : mFrameTimelines) {
+ // The ID is no longer valid because the frame time that was registered with the ID
+ // no longer matches.
+ // TODO(b/205721584): Ask SF for valid vsync information.
+ ft.resetVsyncId();
+ }
+ }
+
+ /** The time in nanoseconds when the frame started being rendered. */
+ public long getFrameTimeNanos() {
+ return mFrameTimeNanos;
+ }
+
+ /** The possible frame timelines, sorted chronologically. */
+ @NonNull
+ @SuppressLint("ArrayReturn") // For API consistency and speed.
+ public FrameTimeline[] getFrameTimelines() {
+ return mFrameTimelines;
+ }
+
+ /** The platform-preferred frame timeline. */
+ @NonNull
+ public FrameTimeline getPreferredFrameTimeline() {
+ return mPreferredFrameTimeline;
+ }
+ }
+
+ /**
+ * Implement this interface to receive a callback to start the next frame. The callback is
+ * invoked on the {@link Looper} thread to which the {@link Choreographer} is attached. The
+ * callback payload contains information about multiple possible frames, allowing choice of
+ * the appropriate frame based on latency requirements.
+ *
+ * @see FrameCallback
+ */
+ public interface ExtendedFrameCallback {
+ /**
+ * Called when a new display frame is being rendered.
+ *
+ * @param data The payload which includes frame information. Divide nanosecond values by
+ * {@code 1000000} to convert it to the {@link SystemClock#uptimeMillis()}
+ * time base.
+ * @see FrameCallback#doFrame
+ **/
+ void onVsync(@NonNull FrameData data);
+ }
+
private final class FrameHandler extends Handler {
public FrameHandler(Looper looper) {
super(looper);
@@ -983,7 +1154,8 @@ public final class Choreographer {
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW,
- "Choreographer#onVsync " + vsyncEventData.id);
+ "Choreographer#onVsync "
+ + vsyncEventData.preferredFrameTimeline().vsyncId);
}
// Post the vsync event to the Handler.
// The idea is to prevent incoming vsync events from completely starving
@@ -1026,7 +1198,9 @@ public final class Choreographer {
private static final class CallbackRecord {
public CallbackRecord next;
public long dueTime;
- public Object action; // Runnable or FrameCallback
+ /** Runnable or FrameCallback or ExtendedFrameCallback object. */
+ public Object action;
+ /** Denotes the action type. */
public Object token;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -1037,6 +1211,14 @@ public final class Choreographer {
((Runnable)action).run();
}
}
+
+ void run(FrameData frameData) {
+ if (token == EXTENDED_FRAME_CALLBACK_TOKEN) {
+ ((ExtendedFrameCallback) action).onVsync(frameData);
+ } else {
+ run(frameData.getFrameTimeNanos());
+ }
+ }
}
private final class CallbackQueue {
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 5c086328bda7..774bab41fb9a 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -138,13 +138,28 @@ public abstract class DisplayEventReceiver {
}
static final class VsyncEventData {
- // The frame timeline vsync id, used to correlate a frame
- // produced by HWUI with the timeline data stored in Surface Flinger.
- public final long id;
- // The frame deadline timestamp in {@link System#nanoTime()} timebase that it is
- // allotted for the frame to be completed.
- public final long frameDeadline;
+ static final FrameTimeline[] INVALID_FRAME_TIMELINES =
+ {new FrameTimeline(FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE)};
+
+ public static class FrameTimeline {
+ FrameTimeline(long vsyncId, long expectedPresentTime, long deadline) {
+ this.vsyncId = vsyncId;
+ this.expectedPresentTime = expectedPresentTime;
+ this.deadline = deadline;
+ }
+
+ // The frame timeline vsync id, used to correlate a frame
+ // produced by HWUI with the timeline data stored in Surface Flinger.
+ public final long vsyncId;
+
+ // The frame timestamp for when the frame is expected to be presented.
+ public final long expectedPresentTime;
+
+ // The frame deadline timestamp in {@link System#nanoTime()} timebase that it is
+ // allotted for the frame to be completed.
+ public final long deadline;
+ }
/**
* The current interval between frames in ns. This will be used to align
@@ -153,16 +168,27 @@ public abstract class DisplayEventReceiver {
*/
public final long frameInterval;
- VsyncEventData(long id, long frameDeadline, long frameInterval) {
- this.id = id;
- this.frameDeadline = frameDeadline;
+ public final FrameTimeline[] frameTimelines;
+
+ public final int preferredFrameTimelineIndex;
+
+ // Called from native code.
+ @SuppressWarnings("unused")
+ VsyncEventData(FrameTimeline[] frameTimelines, int preferredFrameTimelineIndex,
+ long frameInterval) {
+ this.frameTimelines = frameTimelines;
+ this.preferredFrameTimelineIndex = preferredFrameTimelineIndex;
this.frameInterval = frameInterval;
}
VsyncEventData() {
- this.id = FrameInfo.INVALID_VSYNC_ID;
- this.frameDeadline = Long.MAX_VALUE;
this.frameInterval = -1;
+ this.frameTimelines = INVALID_FRAME_TIMELINES;
+ this.preferredFrameTimelineIndex = 0;
+ }
+
+ public FrameTimeline preferredFrameTimeline() {
+ return frameTimelines[preferredFrameTimelineIndex];
}
}
@@ -256,9 +282,8 @@ public abstract class DisplayEventReceiver {
// Called from native code.
@SuppressWarnings("unused")
private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame,
- long frameTimelineVsyncId, long frameDeadline, long frameInterval) {
- onVsync(timestampNanos, physicalDisplayId, frame,
- new VsyncEventData(frameTimelineVsyncId, frameDeadline, frameInterval));
+ VsyncEventData vsyncEventData) {
+ onVsync(timestampNanos, physicalDisplayId, frame, vsyncEventData);
}
// Called from native code.
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index ce772cf9faff..d91d526e3d4c 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -48,6 +48,16 @@ static struct {
jmethodID init;
} frameRateOverrideClassInfo;
+ struct {
+ jclass clazz;
+ jmethodID init;
+ } frameTimelineClassInfo;
+
+ struct {
+ jclass clazz;
+ jmethodID init;
+ } vsyncEventDataClassInfo;
+
} gDisplayEventReceiverClassInfo;
@@ -105,9 +115,38 @@ void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDispla
ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
if (receiverObj.get()) {
ALOGV("receiver %p ~ Invoking vsync handler.", this);
+
+ ScopedLocalRef<jobjectArray>
+ frameTimelineObjs(env,
+ env->NewObjectArray(vsyncEventData.frameTimelines.size(),
+ gDisplayEventReceiverClassInfo
+ .frameTimelineClassInfo.clazz,
+ /*initial element*/ NULL));
+ for (int i = 0; i < vsyncEventData.frameTimelines.size(); i++) {
+ VsyncEventData::FrameTimeline frameTimeline = vsyncEventData.frameTimelines[i];
+ ScopedLocalRef<jobject>
+ frameTimelineObj(env,
+ env->NewObject(gDisplayEventReceiverClassInfo
+ .frameTimelineClassInfo.clazz,
+ gDisplayEventReceiverClassInfo
+ .frameTimelineClassInfo.init,
+ frameTimeline.id,
+ frameTimeline.expectedPresentTime,
+ frameTimeline.deadlineTimestamp));
+ env->SetObjectArrayElement(frameTimelineObjs.get(), i, frameTimelineObj.get());
+ }
+ ScopedLocalRef<jobject>
+ vsyncEventDataJava(env,
+ env->NewObject(gDisplayEventReceiverClassInfo
+ .vsyncEventDataClassInfo.clazz,
+ gDisplayEventReceiverClassInfo
+ .vsyncEventDataClassInfo.init,
+ frameTimelineObjs.get(),
+ vsyncEventData.preferredFrameTimelineIndex,
+ vsyncEventData.frameInterval));
+
env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
- timestamp, displayId.value, count, vsyncEventData.id,
- vsyncEventData.deadlineTimestamp, vsyncEventData.frameInterval);
+ timestamp, displayId.value, count, vsyncEventDataJava.get());
ALOGV("receiver %p ~ Returned from vsync handler.", this);
}
@@ -239,7 +278,7 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) {
gDisplayEventReceiverClassInfo.dispatchVsync =
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync",
- "(JJIJJJ)V");
+ "(JJILandroid/view/DisplayEventReceiver$VsyncEventData;)V");
gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
gDisplayEventReceiverClassInfo.dispatchModeChanged =
@@ -258,6 +297,24 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) {
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz,
"<init>", "(IF)V");
+ jclass frameTimelineClazz =
+ FindClassOrDie(env, "android/view/DisplayEventReceiver$VsyncEventData$FrameTimeline");
+ gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz =
+ MakeGlobalRefOrDie(env, frameTimelineClazz);
+ gDisplayEventReceiverClassInfo.frameTimelineClassInfo.init =
+ GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
+ "<init>", "(JJJ)V");
+
+ jclass vsyncEventDataClazz =
+ FindClassOrDie(env, "android/view/DisplayEventReceiver$VsyncEventData");
+ gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz =
+ MakeGlobalRefOrDie(env, vsyncEventDataClazz);
+ gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.init =
+ GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
+ "<init>",
+ "([Landroid/view/"
+ "DisplayEventReceiver$VsyncEventData$FrameTimeline;IJ)V");
+
return res;
}