• 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 <nativehelper/JNIHelp.h>
22 
23 #include <inttypes.h>
24 
25 #include <android_runtime/AndroidRuntime.h>
26 #include <gui/DisplayEventDispatcher.h>
27 #include <utils/Log.h>
28 #include <utils/Looper.h>
29 #include <utils/threads.h>
30 #include "android_os_MessageQueue.h"
31 
32 #include <nativehelper/ScopedLocalRef.h>
33 
34 #include "core_jni_helpers.h"
35 
36 namespace android {
37 
38 static struct {
39     jclass clazz;
40 
41     jmethodID dispatchVsync;
42     jmethodID dispatchHotplug;
43     jmethodID dispatchModeChanged;
44     jmethodID dispatchFrameRateOverrides;
45 
46     struct {
47         jclass clazz;
48         jmethodID init;
49     } frameRateOverrideClassInfo;
50 
51 } gDisplayEventReceiverClassInfo;
52 
53 
54 class NativeDisplayEventReceiver : public DisplayEventDispatcher {
55 public:
56     NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
57                                const sp<MessageQueue>& messageQueue, jint vsyncSource,
58                                jint eventRegistration);
59 
60     void dispose();
61 
62 protected:
63     virtual ~NativeDisplayEventReceiver();
64 
65 private:
66     jobject mReceiverWeakGlobal;
67     sp<MessageQueue> mMessageQueue;
68 
69     void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
70                        VsyncEventData vsyncEventData) override;
71     void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
72     void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
73                              nsecs_t vsyncPeriod) override;
74     void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
75                                     std::vector<FrameRateOverride> overrides) override;
dispatchNullEvent(nsecs_t timestamp,PhysicalDisplayId displayId)76     void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {}
77 };
78 
NativeDisplayEventReceiver(JNIEnv * env,jobject receiverWeak,const sp<MessageQueue> & messageQueue,jint vsyncSource,jint eventRegistration)79 NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
80                                                        const sp<MessageQueue>& messageQueue,
81                                                        jint vsyncSource, jint eventRegistration)
82       : DisplayEventDispatcher(messageQueue->getLooper(),
83                                static_cast<ISurfaceComposer::VsyncSource>(vsyncSource),
84                                static_cast<ISurfaceComposer::EventRegistration>(eventRegistration)),
85         mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
86         mMessageQueue(messageQueue) {
87     ALOGV("receiver %p ~ Initializing display event receiver.", this);
88 }
89 
~NativeDisplayEventReceiver()90 NativeDisplayEventReceiver::~NativeDisplayEventReceiver() {
91     JNIEnv* env = AndroidRuntime::getJNIEnv();
92     env->DeleteGlobalRef(mReceiverWeakGlobal);
93     ALOGV("receiver %p ~ dtor display event receiver.", this);
94 }
95 
dispose()96 void NativeDisplayEventReceiver::dispose() {
97     ALOGV("receiver %p ~ Disposing display event receiver.", this);
98     DisplayEventDispatcher::dispose();
99 }
100 
dispatchVsync(nsecs_t timestamp,PhysicalDisplayId displayId,uint32_t count,VsyncEventData vsyncEventData)101 void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
102                                                uint32_t count, VsyncEventData vsyncEventData) {
103     JNIEnv* env = AndroidRuntime::getJNIEnv();
104 
105     ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
106     if (receiverObj.get()) {
107         ALOGV("receiver %p ~ Invoking vsync handler.", this);
108         env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
109                             timestamp, displayId.value, count, vsyncEventData.id,
110                             vsyncEventData.deadlineTimestamp, vsyncEventData.frameInterval);
111         ALOGV("receiver %p ~ Returned from vsync handler.", this);
112     }
113 
114     mMessageQueue->raiseAndClearException(env, "dispatchVsync");
115 }
116 
dispatchHotplug(nsecs_t timestamp,PhysicalDisplayId displayId,bool connected)117 void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
118                                                  bool connected) {
119     JNIEnv* env = AndroidRuntime::getJNIEnv();
120 
121     ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
122     if (receiverObj.get()) {
123         ALOGV("receiver %p ~ Invoking hotplug handler.", this);
124         env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchHotplug,
125                             timestamp, displayId.value, connected);
126         ALOGV("receiver %p ~ Returned from hotplug handler.", this);
127     }
128 
129     mMessageQueue->raiseAndClearException(env, "dispatchHotplug");
130 }
131 
dispatchModeChanged(nsecs_t timestamp,PhysicalDisplayId displayId,int32_t modeId,nsecs_t)132 void NativeDisplayEventReceiver::dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
133                                                      int32_t modeId, nsecs_t) {
134     JNIEnv* env = AndroidRuntime::getJNIEnv();
135 
136     ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
137     if (receiverObj.get()) {
138         ALOGV("receiver %p ~ Invoking mode changed handler.", this);
139         env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchModeChanged,
140                             timestamp, displayId.value, modeId);
141         ALOGV("receiver %p ~ Returned from mode changed handler.", this);
142     }
143 
144     mMessageQueue->raiseAndClearException(env, "dispatchModeChanged");
145 }
146 
dispatchFrameRateOverrides(nsecs_t timestamp,PhysicalDisplayId displayId,std::vector<FrameRateOverride> overrides)147 void NativeDisplayEventReceiver::dispatchFrameRateOverrides(
148         nsecs_t timestamp, PhysicalDisplayId displayId, std::vector<FrameRateOverride> overrides) {
149     JNIEnv* env = AndroidRuntime::getJNIEnv();
150 
151     ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
152     if (receiverObj.get()) {
153         ALOGV("receiver %p ~ Invoking FrameRateOverride handler.", this);
154         const auto frameRateOverrideClass =
155                 gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz;
156         const auto frameRateOverrideInit =
157                 gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.init;
158         auto frameRateOverrideInitObject =
159                 env->NewObject(frameRateOverrideClass, frameRateOverrideInit, 0, 0);
160         auto frameRateOverrideArray = env->NewObjectArray(overrides.size(), frameRateOverrideClass,
161                                                           frameRateOverrideInitObject);
162         for (size_t i = 0; i < overrides.size(); i++) {
163             auto FrameRateOverrideObject =
164                     env->NewObject(frameRateOverrideClass, frameRateOverrideInit, overrides[i].uid,
165                                    overrides[i].frameRateHz);
166             env->SetObjectArrayElement(frameRateOverrideArray, i, FrameRateOverrideObject);
167         }
168 
169         env->CallVoidMethod(receiverObj.get(),
170                             gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides, timestamp,
171                             displayId.value, frameRateOverrideArray);
172         ALOGV("receiver %p ~ Returned from FrameRateOverride handler.", this);
173     }
174 
175     mMessageQueue->raiseAndClearException(env, "dispatchModeChanged");
176 }
177 
nativeInit(JNIEnv * env,jclass clazz,jobject receiverWeak,jobject messageQueueObj,jint vsyncSource,jint eventRegistration)178 static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj,
179                         jint vsyncSource, jint eventRegistration) {
180     sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
181     if (messageQueue == NULL) {
182         jniThrowRuntimeException(env, "MessageQueue is not initialized.");
183         return 0;
184     }
185 
186     sp<NativeDisplayEventReceiver> receiver =
187             new NativeDisplayEventReceiver(env, receiverWeak, messageQueue, vsyncSource,
188                                            eventRegistration);
189     status_t status = receiver->initialize();
190     if (status) {
191         String8 message;
192         message.appendFormat("Failed to initialize display event receiver.  status=%d", status);
193         jniThrowRuntimeException(env, message.string());
194         return 0;
195     }
196 
197     receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
198     return reinterpret_cast<jlong>(receiver.get());
199 }
200 
nativeDispose(JNIEnv * env,jclass clazz,jlong receiverPtr)201 static void nativeDispose(JNIEnv* env, jclass clazz, jlong receiverPtr) {
202     NativeDisplayEventReceiver* receiver =
203             reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
204     receiver->dispose();
205     receiver->decStrong(gDisplayEventReceiverClassInfo.clazz); // drop reference held by the object
206 }
207 
nativeScheduleVsync(JNIEnv * env,jclass clazz,jlong receiverPtr)208 static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
209     sp<NativeDisplayEventReceiver> receiver =
210             reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
211     status_t status = receiver->scheduleVsync();
212     if (status) {
213         String8 message;
214         message.appendFormat("Failed to schedule next vertical sync pulse.  status=%d", status);
215         jniThrowRuntimeException(env, message.string());
216     }
217 }
218 
219 
220 static const JNINativeMethod gMethods[] = {
221     /* name, signature, funcPtr */
222     { "nativeInit",
223             "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;II)J",
224             (void*)nativeInit },
225     { "nativeDispose",
226             "(J)V",
227             (void*)nativeDispose },
228     // @FastNative
229     { "nativeScheduleVsync", "(J)V",
230             (void*)nativeScheduleVsync }
231 };
232 
register_android_view_DisplayEventReceiver(JNIEnv * env)233 int register_android_view_DisplayEventReceiver(JNIEnv* env) {
234     int res = RegisterMethodsOrDie(env, "android/view/DisplayEventReceiver", gMethods,
235                                    NELEM(gMethods));
236 
237     jclass clazz = FindClassOrDie(env, "android/view/DisplayEventReceiver");
238     gDisplayEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
239 
240     gDisplayEventReceiverClassInfo.dispatchVsync =
241             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync",
242                              "(JJIJJJ)V");
243     gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
244             gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
245     gDisplayEventReceiverClassInfo.dispatchModeChanged =
246             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeChanged",
247                              "(JJI)V");
248     gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides =
249             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz,
250                              "dispatchFrameRateOverrides",
251                              "(JJ[Landroid/view/DisplayEventReceiver$FrameRateOverride;)V");
252 
253     jclass frameRateOverrideClazz =
254             FindClassOrDie(env, "android/view/DisplayEventReceiver$FrameRateOverride");
255     gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz =
256             MakeGlobalRefOrDie(env, frameRateOverrideClazz);
257     gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.init =
258             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz,
259                              "<init>", "(IF)V");
260 
261     return res;
262 }
263 
264 } // namespace android
265