• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 dispatchModeChanged;
42     jmethodID dispatchFrameRateOverrides;
43 
44     struct {
45         jclass clazz;
46         jmethodID init;
47     } frameRateOverrideClassInfo;
48 
49     struct {
50         jclass clazz;
51 
52         jmethodID init;
53 
54         jfieldID vsyncId;
55         jfieldID expectedPresentationTime;
56         jfieldID deadline;
57     } frameTimelineClassInfo;
58 
59     struct {
60         jclass clazz;
61 
62         jmethodID init;
63 
64         jfieldID frameInterval;
65         jfieldID preferredFrameTimelineIndex;
66         jfieldID frameTimelinesLength;
67         jfieldID frameTimelines;
68     } vsyncEventDataClassInfo;
69 
70 } gDisplayEventReceiverClassInfo;
71 
72 
73 class NativeDisplayEventReceiver : public DisplayEventDispatcher {
74 public:
75     NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak, jobject vsyncEventDataWeak,
76                                const sp<MessageQueue>& messageQueue, jint vsyncSource,
77                                jint eventRegistration, jlong layerHandle);
78 
79     void dispose();
80 
81 protected:
82     virtual ~NativeDisplayEventReceiver();
83 
84 private:
85     jobject mReceiverWeakGlobal;
86     jobject mVsyncEventDataWeakGlobal;
87     sp<MessageQueue> mMessageQueue;
88 
89     void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
90                        VsyncEventData vsyncEventData) override;
91     void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
92     void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
93                              nsecs_t renderPeriod) override;
94     void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
95                                     std::vector<FrameRateOverride> overrides) override;
dispatchNullEvent(nsecs_t timestamp,PhysicalDisplayId displayId)96     void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {}
97 };
98 
NativeDisplayEventReceiver(JNIEnv * env,jobject receiverWeak,jobject vsyncEventDataWeak,const sp<MessageQueue> & messageQueue,jint vsyncSource,jint eventRegistration,jlong layerHandle)99 NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
100                                                        jobject vsyncEventDataWeak,
101                                                        const sp<MessageQueue>& messageQueue,
102                                                        jint vsyncSource, jint eventRegistration,
103                                                        jlong layerHandle)
104       : DisplayEventDispatcher(messageQueue->getLooper(),
105                                static_cast<gui::ISurfaceComposer::VsyncSource>(vsyncSource),
106                                static_cast<gui::ISurfaceComposer::EventRegistration>(
107                                        eventRegistration),
108                                layerHandle != 0 ? sp<IBinder>::fromExisting(
109                                                           reinterpret_cast<IBinder*>(layerHandle))
110                                                 : nullptr),
111         mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
112         mVsyncEventDataWeakGlobal(env->NewGlobalRef(vsyncEventDataWeak)),
113         mMessageQueue(messageQueue) {
114     ALOGV("receiver %p ~ Initializing display event receiver.", this);
115 }
116 
~NativeDisplayEventReceiver()117 NativeDisplayEventReceiver::~NativeDisplayEventReceiver() {
118     JNIEnv* env = AndroidRuntime::getJNIEnv();
119     env->DeleteGlobalRef(mReceiverWeakGlobal);
120     ALOGV("receiver %p ~ dtor display event receiver.", this);
121 }
122 
dispose()123 void NativeDisplayEventReceiver::dispose() {
124     ALOGV("receiver %p ~ Disposing display event receiver.", this);
125     DisplayEventDispatcher::dispose();
126 }
127 
createJavaVsyncEventData(JNIEnv * env,VsyncEventData vsyncEventData)128 static jobject createJavaVsyncEventData(JNIEnv* env, VsyncEventData vsyncEventData) {
129     ScopedLocalRef<jobjectArray>
130             frameTimelineObjs(env,
131                               env->NewObjectArray(vsyncEventData.frameTimelinesLength,
132                                                   gDisplayEventReceiverClassInfo
133                                                           .frameTimelineClassInfo.clazz,
134                                                   /*initial element*/ NULL));
135     if (!frameTimelineObjs.get() || env->ExceptionCheck()) {
136         ALOGW("%s: Failed to create FrameTimeline array", __func__);
137         LOGW_EX(env);
138         env->ExceptionClear();
139         return NULL;
140     }
141     for (int i = 0; i < vsyncEventData.frameTimelinesLength; i++) {
142         VsyncEventData::FrameTimeline frameTimeline = vsyncEventData.frameTimelines[i];
143         ScopedLocalRef<jobject>
144                 frameTimelineObj(env,
145                                  env->NewObject(gDisplayEventReceiverClassInfo
146                                                         .frameTimelineClassInfo.clazz,
147                                                 gDisplayEventReceiverClassInfo
148                                                         .frameTimelineClassInfo.init,
149                                                 frameTimeline.vsyncId,
150                                                 frameTimeline.expectedPresentationTime,
151                                                 frameTimeline.deadlineTimestamp));
152         if (!frameTimelineObj.get() || env->ExceptionCheck()) {
153             ALOGW("%s: Failed to create FrameTimeline object", __func__);
154             LOGW_EX(env);
155             env->ExceptionClear();
156             return NULL;
157         }
158         env->SetObjectArrayElement(frameTimelineObjs.get(), i, frameTimelineObj.get());
159     }
160     return env->NewObject(gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
161                           gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.init,
162                           frameTimelineObjs.get(), vsyncEventData.preferredFrameTimelineIndex,
163                           vsyncEventData.frameTimelinesLength, vsyncEventData.frameInterval);
164 }
165 
dispatchVsync(nsecs_t timestamp,PhysicalDisplayId displayId,uint32_t count,VsyncEventData vsyncEventData)166 void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
167                                                uint32_t count, VsyncEventData vsyncEventData) {
168     JNIEnv* env = AndroidRuntime::getJNIEnv();
169 
170     ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
171     ScopedLocalRef<jobject> vsyncEventDataObj(env, GetReferent(env, mVsyncEventDataWeakGlobal));
172     if (receiverObj.get() && vsyncEventDataObj.get()) {
173         ALOGV("receiver %p ~ Invoking vsync handler.", this);
174 
175         env->SetIntField(vsyncEventDataObj.get(),
176                          gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo
177                                  .preferredFrameTimelineIndex,
178                          vsyncEventData.preferredFrameTimelineIndex);
179         env->SetIntField(vsyncEventDataObj.get(),
180                          gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo
181                                  .frameTimelinesLength,
182                          vsyncEventData.frameTimelinesLength);
183         env->SetLongField(vsyncEventDataObj.get(),
184                           gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameInterval,
185                           vsyncEventData.frameInterval);
186 
187         ScopedLocalRef<jobjectArray>
188                 frameTimelinesObj(env,
189                                   reinterpret_cast<jobjectArray>(
190                                           env->GetObjectField(vsyncEventDataObj.get(),
191                                                               gDisplayEventReceiverClassInfo
192                                                                       .vsyncEventDataClassInfo
193                                                                       .frameTimelines)));
194         for (int i = 0; i < vsyncEventData.frameTimelinesLength; i++) {
195             VsyncEventData::FrameTimeline& frameTimeline = vsyncEventData.frameTimelines[i];
196             ScopedLocalRef<jobject>
197                     frameTimelineObj(env, env->GetObjectArrayElement(frameTimelinesObj.get(), i));
198             env->SetLongField(frameTimelineObj.get(),
199                               gDisplayEventReceiverClassInfo.frameTimelineClassInfo.vsyncId,
200                               frameTimeline.vsyncId);
201             env->SetLongField(frameTimelineObj.get(),
202                               gDisplayEventReceiverClassInfo.frameTimelineClassInfo
203                                       .expectedPresentationTime,
204                               frameTimeline.expectedPresentationTime);
205             env->SetLongField(frameTimelineObj.get(),
206                               gDisplayEventReceiverClassInfo.frameTimelineClassInfo.deadline,
207                               frameTimeline.deadlineTimestamp);
208         }
209 
210         env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
211                             timestamp, displayId.value, count);
212         ALOGV("receiver %p ~ Returned from vsync handler.", this);
213     }
214 
215     mMessageQueue->raiseAndClearException(env, "dispatchVsync");
216 }
217 
dispatchHotplug(nsecs_t timestamp,PhysicalDisplayId displayId,bool connected)218 void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
219                                                  bool connected) {
220     JNIEnv* env = AndroidRuntime::getJNIEnv();
221 
222     ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
223     if (receiverObj.get()) {
224         ALOGV("receiver %p ~ Invoking hotplug handler.", this);
225         env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchHotplug,
226                             timestamp, displayId.value, connected);
227         ALOGV("receiver %p ~ Returned from hotplug handler.", this);
228     }
229 
230     mMessageQueue->raiseAndClearException(env, "dispatchHotplug");
231 }
232 
dispatchModeChanged(nsecs_t timestamp,PhysicalDisplayId displayId,int32_t modeId,nsecs_t renderPeriod)233 void NativeDisplayEventReceiver::dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
234                                                      int32_t modeId, nsecs_t renderPeriod) {
235     JNIEnv* env = AndroidRuntime::getJNIEnv();
236 
237     ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
238     if (receiverObj.get()) {
239         ALOGV("receiver %p ~ Invoking mode changed handler.", this);
240         env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchModeChanged,
241                             timestamp, displayId.value, modeId, renderPeriod);
242         ALOGV("receiver %p ~ Returned from mode changed handler.", this);
243     }
244 
245     mMessageQueue->raiseAndClearException(env, "dispatchModeChanged");
246 }
247 
dispatchFrameRateOverrides(nsecs_t timestamp,PhysicalDisplayId displayId,std::vector<FrameRateOverride> overrides)248 void NativeDisplayEventReceiver::dispatchFrameRateOverrides(
249         nsecs_t timestamp, PhysicalDisplayId displayId, std::vector<FrameRateOverride> overrides) {
250     JNIEnv* env = AndroidRuntime::getJNIEnv();
251 
252     ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
253     if (receiverObj.get()) {
254         ALOGV("receiver %p ~ Invoking FrameRateOverride handler.", this);
255         const auto frameRateOverrideClass =
256                 gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz;
257         const auto frameRateOverrideInit =
258                 gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.init;
259         auto frameRateOverrideInitObject =
260                 env->NewObject(frameRateOverrideClass, frameRateOverrideInit, 0, 0);
261         auto frameRateOverrideArray = env->NewObjectArray(overrides.size(), frameRateOverrideClass,
262                                                           frameRateOverrideInitObject);
263         for (size_t i = 0; i < overrides.size(); i++) {
264             auto FrameRateOverrideObject =
265                     env->NewObject(frameRateOverrideClass, frameRateOverrideInit, overrides[i].uid,
266                                    overrides[i].frameRateHz);
267             env->SetObjectArrayElement(frameRateOverrideArray, i, FrameRateOverrideObject);
268         }
269 
270         env->CallVoidMethod(receiverObj.get(),
271                             gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides, timestamp,
272                             displayId.value, frameRateOverrideArray);
273         ALOGV("receiver %p ~ Returned from FrameRateOverride handler.", this);
274     }
275 
276     mMessageQueue->raiseAndClearException(env, "dispatchModeChanged");
277 }
278 
nativeInit(JNIEnv * env,jclass clazz,jobject receiverWeak,jobject vsyncEventDataWeak,jobject messageQueueObj,jint vsyncSource,jint eventRegistration,jlong layerHandle)279 static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject vsyncEventDataWeak,
280                         jobject messageQueueObj, jint vsyncSource, jint eventRegistration,
281                         jlong layerHandle) {
282     sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
283     if (messageQueue == NULL) {
284         jniThrowRuntimeException(env, "MessageQueue is not initialized.");
285         return 0;
286     }
287 
288     sp<NativeDisplayEventReceiver> receiver =
289             new NativeDisplayEventReceiver(env, receiverWeak, vsyncEventDataWeak, messageQueue,
290                                            vsyncSource, eventRegistration, layerHandle);
291     status_t status = receiver->initialize();
292     if (status) {
293         String8 message;
294         message.appendFormat("Failed to initialize display event receiver.  status=%d", status);
295         jniThrowRuntimeException(env, message.string());
296         return 0;
297     }
298 
299     receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
300     return reinterpret_cast<jlong>(receiver.get());
301 }
302 
release(NativeDisplayEventReceiver * receiver)303 static void release(NativeDisplayEventReceiver* receiver) {
304     receiver->dispose();
305     receiver->decStrong(gDisplayEventReceiverClassInfo.clazz); // drop reference held by the object
306 }
307 
nativeGetDisplayEventReceiverFinalizer(JNIEnv *,jclass)308 static jlong nativeGetDisplayEventReceiverFinalizer(JNIEnv*, jclass) {
309     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&release));
310 }
311 
nativeScheduleVsync(JNIEnv * env,jclass clazz,jlong receiverPtr)312 static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
313     sp<NativeDisplayEventReceiver> receiver =
314             reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
315     status_t status = receiver->scheduleVsync();
316     if (status) {
317         String8 message;
318         message.appendFormat("Failed to schedule next vertical sync pulse.  status=%d", status);
319         jniThrowRuntimeException(env, message.string());
320     }
321 }
322 
nativeGetLatestVsyncEventData(JNIEnv * env,jclass clazz,jlong receiverPtr)323 static jobject nativeGetLatestVsyncEventData(JNIEnv* env, jclass clazz, jlong receiverPtr) {
324     sp<NativeDisplayEventReceiver> receiver =
325             reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
326     gui::ParcelableVsyncEventData parcelableVsyncEventData;
327     status_t status = receiver->getLatestVsyncEventData(&parcelableVsyncEventData);
328     if (status) {
329         ALOGW("Failed to get latest vsync event data from surface flinger");
330         return NULL;
331     }
332     return createJavaVsyncEventData(env, parcelableVsyncEventData.vsync);
333 }
334 
335 static const JNINativeMethod gMethods[] = {
336         /* name, signature, funcPtr */
337         {"nativeInit",
338          "(Ljava/lang/ref/WeakReference;Ljava/lang/ref/WeakReference;Landroid/os/"
339          "MessageQueue;IIJ)J",
340          (void*)nativeInit},
341         {"nativeGetDisplayEventReceiverFinalizer", "()J",
342          (void*)nativeGetDisplayEventReceiverFinalizer},
343         // @FastNative
344         {"nativeScheduleVsync", "(J)V", (void*)nativeScheduleVsync},
345         {"nativeGetLatestVsyncEventData", "(J)Landroid/view/DisplayEventReceiver$VsyncEventData;",
346          (void*)nativeGetLatestVsyncEventData}};
347 
register_android_view_DisplayEventReceiver(JNIEnv * env)348 int register_android_view_DisplayEventReceiver(JNIEnv* env) {
349     int res = RegisterMethodsOrDie(env, "android/view/DisplayEventReceiver", gMethods,
350                                    NELEM(gMethods));
351 
352     jclass clazz = FindClassOrDie(env, "android/view/DisplayEventReceiver");
353     gDisplayEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
354 
355     gDisplayEventReceiverClassInfo.dispatchVsync =
356             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JJI)V");
357     gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
358             gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
359     gDisplayEventReceiverClassInfo.dispatchModeChanged =
360             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeChanged",
361                              "(JJIJ)V");
362     gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides =
363             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz,
364                              "dispatchFrameRateOverrides",
365                              "(JJ[Landroid/view/DisplayEventReceiver$FrameRateOverride;)V");
366 
367     jclass frameRateOverrideClazz =
368             FindClassOrDie(env, "android/view/DisplayEventReceiver$FrameRateOverride");
369     gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz =
370             MakeGlobalRefOrDie(env, frameRateOverrideClazz);
371     gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.init =
372             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz,
373                              "<init>", "(IF)V");
374 
375     jclass frameTimelineClazz =
376             FindClassOrDie(env, "android/view/DisplayEventReceiver$VsyncEventData$FrameTimeline");
377     gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz =
378             MakeGlobalRefOrDie(env, frameTimelineClazz);
379     gDisplayEventReceiverClassInfo.frameTimelineClassInfo.init =
380             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
381                              "<init>", "(JJJ)V");
382     gDisplayEventReceiverClassInfo.frameTimelineClassInfo.vsyncId =
383             GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
384                             "vsyncId", "J");
385     gDisplayEventReceiverClassInfo.frameTimelineClassInfo.expectedPresentationTime =
386             GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
387                             "expectedPresentationTime", "J");
388     gDisplayEventReceiverClassInfo.frameTimelineClassInfo.deadline =
389             GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
390                             "deadline", "J");
391 
392     jclass vsyncEventDataClazz =
393             FindClassOrDie(env, "android/view/DisplayEventReceiver$VsyncEventData");
394     gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz =
395             MakeGlobalRefOrDie(env, vsyncEventDataClazz);
396     gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.init =
397             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
398                              "<init>",
399                              "([Landroid/view/"
400                              "DisplayEventReceiver$VsyncEventData$FrameTimeline;IIJ)V");
401 
402     gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.preferredFrameTimelineIndex =
403             GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
404                             "preferredFrameTimelineIndex", "I");
405     gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameTimelinesLength =
406             GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
407                             "frameTimelinesLength", "I");
408     gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameInterval =
409             GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
410                             "frameInterval", "J");
411     gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameTimelines =
412             GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
413                             "frameTimelines",
414                             "[Landroid/view/DisplayEventReceiver$VsyncEventData$FrameTimeline;");
415 
416     return res;
417 }
418 
419 } // namespace android
420