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