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 "JNIHelp.h" 22 23 #include <inttypes.h> 24 25 #include <android_runtime/AndroidRuntime.h> 26 #include <androidfw/DisplayEventDispatcher.h> 27 #include <utils/Log.h> 28 #include <utils/Looper.h> 29 #include <utils/threads.h> 30 #include <gui/DisplayEventReceiver.h> 31 #include "android_os_MessageQueue.h" 32 33 #include <ScopedLocalRef.h> 34 35 #include "core_jni_helpers.h" 36 37 namespace android { 38 39 // Number of events to read at a time from the DisplayEventReceiver pipe. 40 // The value should be large enough that we can quickly drain the pipe 41 // using just a few large reads. 42 static const size_t EVENT_BUFFER_SIZE = 100; 43 44 static struct { 45 jclass clazz; 46 47 jmethodID dispatchVsync; 48 jmethodID dispatchHotplug; 49 } gDisplayEventReceiverClassInfo; 50 51 52 class NativeDisplayEventReceiver : public DisplayEventDispatcher { 53 public: 54 NativeDisplayEventReceiver(JNIEnv* env, 55 jobject receiverWeak, const sp<MessageQueue>& messageQueue); 56 57 void dispose(); 58 59 protected: 60 virtual ~NativeDisplayEventReceiver(); 61 62 private: 63 jobject mReceiverWeakGlobal; 64 sp<MessageQueue> mMessageQueue; 65 DisplayEventReceiver mReceiver; 66 bool mWaitingForVsync; 67 68 virtual void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count); 69 virtual void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected); 70 }; 71 72 73 NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, 74 jobject receiverWeak, const sp<MessageQueue>& messageQueue) : 75 DisplayEventDispatcher(messageQueue->getLooper()), 76 mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)), 77 mMessageQueue(messageQueue), mWaitingForVsync(false) { 78 ALOGV("receiver %p ~ Initializing display event receiver.", this); 79 } 80 81 NativeDisplayEventReceiver::~NativeDisplayEventReceiver() { 82 JNIEnv* env = AndroidRuntime::getJNIEnv(); 83 env->DeleteGlobalRef(mReceiverWeakGlobal); 84 ALOGV("receiver %p ~ dtor display event receiver.", this); 85 } 86 87 void NativeDisplayEventReceiver::dispose() { 88 ALOGV("receiver %p ~ Disposing display event receiver.", this); 89 DisplayEventDispatcher::dispose(); 90 } 91 92 void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) { 93 JNIEnv* env = AndroidRuntime::getJNIEnv(); 94 95 ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal)); 96 if (receiverObj.get()) { 97 ALOGV("receiver %p ~ Invoking vsync handler.", this); 98 env->CallVoidMethod(receiverObj.get(), 99 gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count); 100 ALOGV("receiver %p ~ Returned from vsync handler.", this); 101 } 102 103 mMessageQueue->raiseAndClearException(env, "dispatchVsync"); 104 } 105 106 void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected) { 107 JNIEnv* env = AndroidRuntime::getJNIEnv(); 108 109 ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal)); 110 if (receiverObj.get()) { 111 ALOGV("receiver %p ~ Invoking hotplug handler.", this); 112 env->CallVoidMethod(receiverObj.get(), 113 gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, id, connected); 114 ALOGV("receiver %p ~ Returned from hotplug handler.", this); 115 } 116 117 mMessageQueue->raiseAndClearException(env, "dispatchHotplug"); 118 } 119 120 121 static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, 122 jobject messageQueueObj) { 123 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); 124 if (messageQueue == NULL) { 125 jniThrowRuntimeException(env, "MessageQueue is not initialized."); 126 return 0; 127 } 128 129 sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env, 130 receiverWeak, messageQueue); 131 status_t status = receiver->initialize(); 132 if (status) { 133 String8 message; 134 message.appendFormat("Failed to initialize display event receiver. status=%d", status); 135 jniThrowRuntimeException(env, message.string()); 136 return 0; 137 } 138 139 receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object 140 return reinterpret_cast<jlong>(receiver.get()); 141 } 142 143 static void nativeDispose(JNIEnv* env, jclass clazz, jlong receiverPtr) { 144 NativeDisplayEventReceiver* receiver = 145 reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr); 146 receiver->dispose(); 147 receiver->decStrong(gDisplayEventReceiverClassInfo.clazz); // drop reference held by the object 148 } 149 150 static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) { 151 sp<NativeDisplayEventReceiver> receiver = 152 reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr); 153 status_t status = receiver->scheduleVsync(); 154 if (status) { 155 String8 message; 156 message.appendFormat("Failed to schedule next vertical sync pulse. status=%d", status); 157 jniThrowRuntimeException(env, message.string()); 158 } 159 } 160 161 162 static const JNINativeMethod gMethods[] = { 163 /* name, signature, funcPtr */ 164 { "nativeInit", 165 "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;)J", 166 (void*)nativeInit }, 167 { "nativeDispose", 168 "(J)V", 169 (void*)nativeDispose }, 170 { "nativeScheduleVsync", "!(J)V", 171 (void*)nativeScheduleVsync } 172 }; 173 174 int register_android_view_DisplayEventReceiver(JNIEnv* env) { 175 int res = RegisterMethodsOrDie(env, "android/view/DisplayEventReceiver", gMethods, 176 NELEM(gMethods)); 177 178 jclass clazz = FindClassOrDie(env, "android/view/DisplayEventReceiver"); 179 gDisplayEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); 180 181 gDisplayEventReceiverClassInfo.dispatchVsync = GetMethodIDOrDie(env, 182 gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JII)V"); 183 gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env, 184 gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JIZ)V"); 185 186 return res; 187 } 188 189 } // namespace android 190