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; 76 void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {} 77 }; 78 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 90 NativeDisplayEventReceiver::~NativeDisplayEventReceiver() { 91 JNIEnv* env = AndroidRuntime::getJNIEnv(); 92 env->DeleteGlobalRef(mReceiverWeakGlobal); 93 ALOGV("receiver %p ~ dtor display event receiver.", this); 94 } 95 96 void NativeDisplayEventReceiver::dispose() { 97 ALOGV("receiver %p ~ Disposing display event receiver.", this); 98 DisplayEventDispatcher::dispose(); 99 } 100 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 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 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 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 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 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 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 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