1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "DisplayEventReceiver"
18 
19 //#define LOG_NDEBUG 0
20 
21 #include <android_runtime/AndroidRuntime.h>
22 #include <android_runtime/Log.h>
23 #include <gui/DisplayEventDispatcher.h>
24 #include <inttypes.h>
25 #include <nativehelper/JNIHelp.h>
26 #include <nativehelper/ScopedLocalRef.h>
27 #include <utils/Log.h>
28 #include <utils/Looper.h>
29 #include <utils/threads.h>
30 
31 #include "android_os_MessageQueue.h"
32 #include "core_jni_helpers.h"
33 
34 namespace android {
35 
36 static struct {
37     jclass clazz;
38 
39     jmethodID dispatchVsync;
40     jmethodID dispatchHotplug;
41     jmethodID dispatchHotplugConnectionError;
42     jmethodID dispatchModeChanged;
43     jmethodID dispatchFrameRateOverrides;
44     jmethodID dispatchHdcpLevelsChanged;
45 
46     struct {
47         jclass clazz;
48         jmethodID init;
49     } frameRateOverrideClassInfo;
50 
51     struct {
52         jclass clazz;
53 
54         jmethodID init;
55 
56         jfieldID vsyncId;
57         jfieldID expectedPresentationTime;
58         jfieldID deadline;
59     } frameTimelineClassInfo;
60 
61     struct {
62         jclass clazz;
63 
64         jmethodID init;
65 
66         jfieldID frameInterval;
67         jfieldID preferredFrameTimelineIndex;
68         jfieldID frameTimelinesLength;
69         jfieldID frameTimelines;
70     } vsyncEventDataClassInfo;
71 
72 } gDisplayEventReceiverClassInfo;
73 
74 
75 class NativeDisplayEventReceiver : public DisplayEventDispatcher {
76 public:
77     NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak, jobject vsyncEventDataWeak,
78                                const sp<MessageQueue>& messageQueue, jint vsyncSource,
79                                jint eventRegistration, jlong layerHandle);
80 
81     void dispose();
82 
83 protected:
84     virtual ~NativeDisplayEventReceiver();
85 
86 private:
87     jobject mReceiverWeakGlobal;
88     jobject mVsyncEventDataWeakGlobal;
89     sp<MessageQueue> mMessageQueue;
90 
91     void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
92                        VsyncEventData vsyncEventData) override;
93     void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
94     void dispatchHotplugConnectionError(nsecs_t timestamp, int errorCode) override;
95     void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
96                              nsecs_t renderPeriod) override;
97     void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
98                                     std::vector<FrameRateOverride> overrides) override;
dispatchNullEvent(nsecs_t timestamp,PhysicalDisplayId displayId)99     void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {}
100     void dispatchHdcpLevelsChanged(PhysicalDisplayId displayId, int connectedLevel,
101                                    int maxLevel) override;
102 };
103 
NativeDisplayEventReceiver(JNIEnv * env,jobject receiverWeak,jobject vsyncEventDataWeak,const sp<MessageQueue> & messageQueue,jint vsyncSource,jint eventRegistration,jlong layerHandle)104 NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
105                                                        jobject vsyncEventDataWeak,
106                                                        const sp<MessageQueue>& messageQueue,
107                                                        jint vsyncSource, jint eventRegistration,
108                                                        jlong layerHandle)
109       : DisplayEventDispatcher(messageQueue->getLooper(),
110                                static_cast<gui::ISurfaceComposer::VsyncSource>(vsyncSource),
111                                static_cast<gui::ISurfaceComposer::EventRegistration>(
112                                        eventRegistration),
113                                layerHandle != 0 ? sp<IBinder>::fromExisting(
114                                                           reinterpret_cast<IBinder*>(layerHandle))
115                                                 : nullptr),
116         mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
117         mVsyncEventDataWeakGlobal(env->NewGlobalRef(vsyncEventDataWeak)),
118         mMessageQueue(messageQueue) {
119     ALOGV("receiver %p ~ Initializing display event receiver.", this);
120 }
121 
~NativeDisplayEventReceiver()122 NativeDisplayEventReceiver::~NativeDisplayEventReceiver() {
123     JNIEnv* env = AndroidRuntime::getJNIEnv();
124     env->DeleteGlobalRef(mReceiverWeakGlobal);
125     ALOGV("receiver %p ~ dtor display event receiver.", this);
126 }
127 
dispose()128 void NativeDisplayEventReceiver::dispose() {
129     ALOGV("receiver %p ~ Disposing display event receiver.", this);
130     DisplayEventDispatcher::dispose();
131 }
132 
createJavaVsyncEventData(JNIEnv * env,VsyncEventData vsyncEventData)133 static jobject createJavaVsyncEventData(JNIEnv* env, VsyncEventData vsyncEventData) {
134     ScopedLocalRef<jobjectArray>
135             frameTimelineObjs(env,
136                               env->NewObjectArray(vsyncEventData.frameTimelinesLength,
137                                                   gDisplayEventReceiverClassInfo
138                                                           .frameTimelineClassInfo.clazz,
139                                                   /*initial element*/ NULL));
140     if (!frameTimelineObjs.get() || env->ExceptionCheck()) {
141         ALOGW("%s: Failed to create FrameTimeline array", __func__);
142         LOGW_EX(env);
143         env->ExceptionClear();
144         return NULL;
145     }
146     for (size_t i = 0; i < vsyncEventData.frameTimelinesLength; i++) {
147         VsyncEventData::FrameTimeline frameTimeline = vsyncEventData.frameTimelines[i];
148         ScopedLocalRef<jobject>
149                 frameTimelineObj(env,
150                                  env->NewObject(gDisplayEventReceiverClassInfo
151                                                         .frameTimelineClassInfo.clazz,
152                                                 gDisplayEventReceiverClassInfo
153                                                         .frameTimelineClassInfo.init,
154                                                 frameTimeline.vsyncId,
155                                                 frameTimeline.expectedPresentationTime,
156                                                 frameTimeline.deadlineTimestamp));
157         if (!frameTimelineObj.get() || env->ExceptionCheck()) {
158             ALOGW("%s: Failed to create FrameTimeline object", __func__);
159             LOGW_EX(env);
160             env->ExceptionClear();
161             return NULL;
162         }
163         env->SetObjectArrayElement(frameTimelineObjs.get(), i, frameTimelineObj.get());
164     }
165     return env->NewObject(gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
166                           gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.init,
167                           frameTimelineObjs.get(), vsyncEventData.preferredFrameTimelineIndex,
168                           vsyncEventData.frameTimelinesLength, vsyncEventData.frameInterval);
169 }
170 
dispatchVsync(nsecs_t timestamp,PhysicalDisplayId displayId,uint32_t count,VsyncEventData vsyncEventData)171 void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
172                                                uint32_t count, VsyncEventData vsyncEventData) {
173     JNIEnv* env = AndroidRuntime::getJNIEnv();
174 
175     ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
176     ScopedLocalRef<jobject> vsyncEventDataObj(env, GetReferent(env, mVsyncEventDataWeakGlobal));
177     if (receiverObj.get() && vsyncEventDataObj.get()) {
178         ALOGV("receiver %p ~ Invoking vsync handler.", this);
179 
180         env->SetIntField(vsyncEventDataObj.get(),
181                          gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo
182                                  .preferredFrameTimelineIndex,
183                          vsyncEventData.preferredFrameTimelineIndex);
184         env->SetIntField(vsyncEventDataObj.get(),
185                          gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo
186                                  .frameTimelinesLength,
187                          vsyncEventData.frameTimelinesLength);
188         env->SetLongField(vsyncEventDataObj.get(),
189                           gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameInterval,
190                           vsyncEventData.frameInterval);
191 
192         ScopedLocalRef<jobjectArray>
193                 frameTimelinesObj(env,
194                                   reinterpret_cast<jobjectArray>(
195                                           env->GetObjectField(vsyncEventDataObj.get(),
196                                                               gDisplayEventReceiverClassInfo
197                                                                       .vsyncEventDataClassInfo
198                                                                       .frameTimelines)));
199         for (size_t i = 0; i < vsyncEventData.frameTimelinesLength; i++) {
200             VsyncEventData::FrameTimeline& frameTimeline = vsyncEventData.frameTimelines[i];
201             ScopedLocalRef<jobject>
202                     frameTimelineObj(env, env->GetObjectArrayElement(frameTimelinesObj.get(), i));
203             env->SetLongField(frameTimelineObj.get(),
204                               gDisplayEventReceiverClassInfo.frameTimelineClassInfo.vsyncId,
205                               frameTimeline.vsyncId);
206             env->SetLongField(frameTimelineObj.get(),
207                               gDisplayEventReceiverClassInfo.frameTimelineClassInfo
208                                       .expectedPresentationTime,
209                               frameTimeline.expectedPresentationTime);
210             env->SetLongField(frameTimelineObj.get(),
211                               gDisplayEventReceiverClassInfo.frameTimelineClassInfo.deadline,
212                               frameTimeline.deadlineTimestamp);
213         }
214 
215         env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
216                             timestamp, displayId.value, count);
217         ALOGV("receiver %p ~ Returned from vsync handler.", this);
218     }
219 
220     mMessageQueue->raiseAndClearException(env, "dispatchVsync");
221 }
222 
dispatchHotplug(nsecs_t timestamp,PhysicalDisplayId displayId,bool connected)223 void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
224                                                  bool connected) {
225     JNIEnv* env = AndroidRuntime::getJNIEnv();
226 
227     ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
228     if (receiverObj.get()) {
229         ALOGV("receiver %p ~ Invoking hotplug handler.", this);
230         env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchHotplug,
231                             timestamp, displayId.value, connected);
232         ALOGV("receiver %p ~ Returned from hotplug handler.", this);
233     }
234 
235     mMessageQueue->raiseAndClearException(env, "dispatchHotplug");
236 }
237 
dispatchHotplugConnectionError(nsecs_t timestamp,int connectionError)238 void NativeDisplayEventReceiver::dispatchHotplugConnectionError(nsecs_t timestamp,
239                                                                 int connectionError) {
240     JNIEnv* env = AndroidRuntime::getJNIEnv();
241 
242     ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
243     if (receiverObj.get()) {
244         ALOGV("receiver %p ~ Invoking hotplug dispatchHotplugConnectionError handler.", this);
245         env->CallVoidMethod(receiverObj.get(),
246                             gDisplayEventReceiverClassInfo.dispatchHotplugConnectionError,
247                             timestamp, connectionError);
248         ALOGV("receiver %p ~ Returned from hotplug dispatchHotplugConnectionError handler.", this);
249     }
250 
251     mMessageQueue->raiseAndClearException(env, "dispatchHotplugConnectionError");
252 }
253 
dispatchModeChanged(nsecs_t timestamp,PhysicalDisplayId displayId,int32_t modeId,nsecs_t renderPeriod)254 void NativeDisplayEventReceiver::dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
255                                                      int32_t modeId, nsecs_t renderPeriod) {
256     JNIEnv* env = AndroidRuntime::getJNIEnv();
257 
258     ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
259     if (receiverObj.get()) {
260         ALOGV("receiver %p ~ Invoking mode changed handler.", this);
261         env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchModeChanged,
262                             timestamp, displayId.value, modeId, renderPeriod);
263         ALOGV("receiver %p ~ Returned from mode changed handler.", this);
264     }
265 
266     mMessageQueue->raiseAndClearException(env, "dispatchModeChanged");
267 }
268 
dispatchFrameRateOverrides(nsecs_t timestamp,PhysicalDisplayId displayId,std::vector<FrameRateOverride> overrides)269 void NativeDisplayEventReceiver::dispatchFrameRateOverrides(
270         nsecs_t timestamp, PhysicalDisplayId displayId, std::vector<FrameRateOverride> overrides) {
271     JNIEnv* env = AndroidRuntime::getJNIEnv();
272 
273     ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
274     if (receiverObj.get()) {
275         ALOGV("receiver %p ~ Invoking FrameRateOverride handler.", this);
276         const auto frameRateOverrideClass =
277                 gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz;
278         const auto frameRateOverrideInit =
279                 gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.init;
280         auto frameRateOverrideInitObject =
281                 env->NewObject(frameRateOverrideClass, frameRateOverrideInit, 0, 0);
282         auto frameRateOverrideArray = env->NewObjectArray(overrides.size(), frameRateOverrideClass,
283                                                           frameRateOverrideInitObject);
284         for (size_t i = 0; i < overrides.size(); i++) {
285             auto FrameRateOverrideObject =
286                     env->NewObject(frameRateOverrideClass, frameRateOverrideInit, overrides[i].uid,
287                                    overrides[i].frameRateHz);
288             env->SetObjectArrayElement(frameRateOverrideArray, i, FrameRateOverrideObject);
289         }
290 
291         env->CallVoidMethod(receiverObj.get(),
292                             gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides, timestamp,
293                             displayId.value, frameRateOverrideArray);
294         ALOGV("receiver %p ~ Returned from FrameRateOverride handler.", this);
295     }
296 
297     mMessageQueue->raiseAndClearException(env, "dispatchModeChanged");
298 }
299 
dispatchHdcpLevelsChanged(PhysicalDisplayId displayId,int connectedLevel,int maxLevel)300 void NativeDisplayEventReceiver::dispatchHdcpLevelsChanged(PhysicalDisplayId displayId,
301                                                            int connectedLevel, int maxLevel) {
302     JNIEnv* env = AndroidRuntime::getJNIEnv();
303 
304     ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
305     if (receiverObj.get()) {
306         ALOGV("receiver %p ~ Invoking hdcp levels changed handler.", this);
307         env->CallVoidMethod(receiverObj.get(),
308                             gDisplayEventReceiverClassInfo.dispatchHdcpLevelsChanged,
309                             displayId.value, connectedLevel, maxLevel);
310         ALOGV("receiver %p ~ Returned from hdcp levels changed handler.", this);
311     }
312 
313     mMessageQueue->raiseAndClearException(env, "dispatchHdcpLevelsChanged");
314 }
315 
nativeInit(JNIEnv * env,jclass clazz,jobject receiverWeak,jobject vsyncEventDataWeak,jobject messageQueueObj,jint vsyncSource,jint eventRegistration,jlong layerHandle)316 static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject vsyncEventDataWeak,
317                         jobject messageQueueObj, jint vsyncSource, jint eventRegistration,
318                         jlong layerHandle) {
319     sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
320     if (messageQueue == NULL) {
321         jniThrowRuntimeException(env, "MessageQueue is not initialized.");
322         return 0;
323     }
324 
325     sp<NativeDisplayEventReceiver> receiver =
326             new NativeDisplayEventReceiver(env, receiverWeak, vsyncEventDataWeak, messageQueue,
327                                            vsyncSource, eventRegistration, layerHandle);
328     status_t status = receiver->initialize();
329     if (status) {
330         String8 message;
331         message.appendFormat("Failed to initialize display event receiver.  status=%d", status);
332         jniThrowRuntimeException(env, message.c_str());
333         return 0;
334     }
335 
336     receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
337     return reinterpret_cast<jlong>(receiver.get());
338 }
339 
release(NativeDisplayEventReceiver * receiver)340 static void release(NativeDisplayEventReceiver* receiver) {
341     receiver->dispose();
342     receiver->decStrong(gDisplayEventReceiverClassInfo.clazz); // drop reference held by the object
343 }
344 
nativeGetDisplayEventReceiverFinalizer(JNIEnv *,jclass)345 static jlong nativeGetDisplayEventReceiverFinalizer(JNIEnv*, jclass) {
346     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&release));
347 }
348 
nativeScheduleVsync(JNIEnv * env,jclass clazz,jlong receiverPtr)349 static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
350     sp<NativeDisplayEventReceiver> receiver =
351             reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
352     status_t status = receiver->scheduleVsync();
353     if (status) {
354         String8 message;
355         message.appendFormat("Failed to schedule next vertical sync pulse.  status=%d", status);
356         jniThrowRuntimeException(env, message.c_str());
357     }
358 }
359 
nativeGetLatestVsyncEventData(JNIEnv * env,jclass clazz,jlong receiverPtr)360 static jobject nativeGetLatestVsyncEventData(JNIEnv* env, jclass clazz, jlong receiverPtr) {
361     sp<NativeDisplayEventReceiver> receiver =
362             reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
363     gui::ParcelableVsyncEventData parcelableVsyncEventData;
364     status_t status = receiver->getLatestVsyncEventData(&parcelableVsyncEventData);
365     if (status) {
366         ALOGW("Failed to get latest vsync event data from surface flinger");
367         return NULL;
368     }
369     return createJavaVsyncEventData(env, parcelableVsyncEventData.vsync);
370 }
371 
372 static const JNINativeMethod gMethods[] = {
373         /* name, signature, funcPtr */
374         {"nativeInit",
375          "(Ljava/lang/ref/WeakReference;Ljava/lang/ref/WeakReference;Landroid/os/"
376          "MessageQueue;IIJ)J",
377          (void*)nativeInit},
378         {"nativeGetDisplayEventReceiverFinalizer", "()J",
379          (void*)nativeGetDisplayEventReceiverFinalizer},
380         // @FastNative
381         {"nativeScheduleVsync", "(J)V", (void*)nativeScheduleVsync},
382         {"nativeGetLatestVsyncEventData", "(J)Landroid/view/DisplayEventReceiver$VsyncEventData;",
383          (void*)nativeGetLatestVsyncEventData}};
384 
register_android_view_DisplayEventReceiver(JNIEnv * env)385 int register_android_view_DisplayEventReceiver(JNIEnv* env) {
386     int res = RegisterMethodsOrDie(env, "android/view/DisplayEventReceiver", gMethods,
387                                    NELEM(gMethods));
388 
389     jclass clazz = FindClassOrDie(env, "android/view/DisplayEventReceiver");
390     gDisplayEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
391 
392     gDisplayEventReceiverClassInfo.dispatchVsync =
393             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JJI)V");
394     gDisplayEventReceiverClassInfo.dispatchHotplug =
395             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug",
396                              "(JJZ)V");
397     gDisplayEventReceiverClassInfo.dispatchHotplugConnectionError =
398             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz,
399                              "dispatchHotplugConnectionError", "(JI)V");
400     gDisplayEventReceiverClassInfo.dispatchModeChanged =
401             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeChanged",
402                              "(JJIJ)V");
403     gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides =
404             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz,
405                              "dispatchFrameRateOverrides",
406                              "(JJ[Landroid/view/DisplayEventReceiver$FrameRateOverride;)V");
407     gDisplayEventReceiverClassInfo.dispatchHdcpLevelsChanged =
408             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchHdcpLevelsChanged",
409                              "(JII)V");
410 
411     jclass frameRateOverrideClazz =
412             FindClassOrDie(env, "android/view/DisplayEventReceiver$FrameRateOverride");
413     gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz =
414             MakeGlobalRefOrDie(env, frameRateOverrideClazz);
415     gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.init =
416             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz,
417                              "<init>", "(IF)V");
418 
419     jclass frameTimelineClazz =
420             FindClassOrDie(env, "android/view/DisplayEventReceiver$VsyncEventData$FrameTimeline");
421     gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz =
422             MakeGlobalRefOrDie(env, frameTimelineClazz);
423     gDisplayEventReceiverClassInfo.frameTimelineClassInfo.init =
424             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
425                              "<init>", "(JJJ)V");
426     gDisplayEventReceiverClassInfo.frameTimelineClassInfo.vsyncId =
427             GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
428                             "vsyncId", "J");
429     gDisplayEventReceiverClassInfo.frameTimelineClassInfo.expectedPresentationTime =
430             GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
431                             "expectedPresentationTime", "J");
432     gDisplayEventReceiverClassInfo.frameTimelineClassInfo.deadline =
433             GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
434                             "deadline", "J");
435 
436     jclass vsyncEventDataClazz =
437             FindClassOrDie(env, "android/view/DisplayEventReceiver$VsyncEventData");
438     gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz =
439             MakeGlobalRefOrDie(env, vsyncEventDataClazz);
440     gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.init =
441             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
442                              "<init>",
443                              "([Landroid/view/"
444                              "DisplayEventReceiver$VsyncEventData$FrameTimeline;IIJ)V");
445 
446     gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.preferredFrameTimelineIndex =
447             GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
448                             "preferredFrameTimelineIndex", "I");
449     gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameTimelinesLength =
450             GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
451                             "frameTimelinesLength", "I");
452     gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameInterval =
453             GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
454                             "frameInterval", "J");
455     gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameTimelines =
456             GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
457                             "frameTimelines",
458                             "[Landroid/view/DisplayEventReceiver$VsyncEventData$FrameTimeline;");
459 
460     return res;
461 }
462 
463 } // namespace android
464