android_view_DisplayEventReceiver.cpp revision 603b44589682db3ff33ade172facb0c5e309f1be
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 22#include "JNIHelp.h" 23 24#include <android_runtime/AndroidRuntime.h> 25#include <utils/Log.h> 26#include <utils/Looper.h> 27#include <utils/threads.h> 28#include <gui/DisplayEventReceiver.h> 29#include "android_os_MessageQueue.h" 30 31namespace android { 32 33// Number of events to read at a time from the DisplayEventReceiver pipe. 34// The value should be large enough that we can quickly drain the pipe 35// using just a few large reads. 36static const size_t EVENT_BUFFER_SIZE = 100; 37 38static struct { 39 jclass clazz; 40 41 jmethodID dispatchVsync; 42} gDisplayEventReceiverClassInfo; 43 44 45class NativeDisplayEventReceiver : public RefBase { 46public: 47 NativeDisplayEventReceiver(JNIEnv* env, 48 jobject receiverObj, const sp<MessageQueue>& messageQueue); 49 50 status_t initialize(); 51 status_t scheduleVsync(); 52 53protected: 54 virtual ~NativeDisplayEventReceiver(); 55 56private: 57 jobject mReceiverObjGlobal; 58 sp<MessageQueue> mMessageQueue; 59 DisplayEventReceiver mReceiver; 60 bool mWaitingForVsync; 61 62 static int handleReceiveCallback(int receiveFd, int events, void* data); 63 bool readLastVsyncMessage(nsecs_t* outTimestamp, uint32_t* outCount); 64}; 65 66 67NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, 68 jobject receiverObj, const sp<MessageQueue>& messageQueue) : 69 mReceiverObjGlobal(env->NewGlobalRef(receiverObj)), 70 mMessageQueue(messageQueue), mWaitingForVsync(false) { 71 ALOGV("receiver %p ~ Initializing input event receiver.", this); 72} 73 74NativeDisplayEventReceiver::~NativeDisplayEventReceiver() { 75 ALOGV("receiver %p ~ Disposing display event receiver.", this); 76 77 if (!mReceiver.initCheck()) { 78 mMessageQueue->getLooper()->removeFd(mReceiver.getFd()); 79 } 80 81 JNIEnv* env = AndroidRuntime::getJNIEnv(); 82 env->DeleteGlobalRef(mReceiverObjGlobal); 83} 84 85status_t NativeDisplayEventReceiver::initialize() { 86 status_t result = mReceiver.initCheck(); 87 if (result) { 88 ALOGW("Failed to initialize display event receiver, status=%d", result); 89 return result; 90 } 91 92 int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT, 93 handleReceiveCallback, this); 94 if (rc < 0) { 95 return UNKNOWN_ERROR; 96 } 97 return OK; 98} 99 100status_t NativeDisplayEventReceiver::scheduleVsync() { 101 if (!mWaitingForVsync) { 102 ALOGV("receiver %p ~ Scheduling vsync.", this); 103 104 // Drain all pending events. 105 nsecs_t vsyncTimestamp; 106 uint32_t vsyncCount; 107 readLastVsyncMessage(&vsyncTimestamp, &vsyncCount); 108 109 status_t status = mReceiver.requestNextVsync(); 110 if (status) { 111 ALOGW("Failed to request next vsync, status=%d", status); 112 return status; 113 } 114 115 mWaitingForVsync = true; 116 } 117 return OK; 118} 119 120int NativeDisplayEventReceiver::handleReceiveCallback(int receiveFd, int events, void* data) { 121 sp<NativeDisplayEventReceiver> r = static_cast<NativeDisplayEventReceiver*>(data); 122 123 if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { 124 ALOGE("Display event receiver pipe was closed or an error occurred. " 125 "events=0x%x", events); 126 return 0; // remove the callback 127 } 128 129 if (!(events & ALOOPER_EVENT_INPUT)) { 130 ALOGW("Received spurious callback for unhandled poll event. " 131 "events=0x%x", events); 132 return 1; // keep the callback 133 } 134 135 // Drain all pending events, keep the last vsync. 136 nsecs_t vsyncTimestamp; 137 uint32_t vsyncCount; 138 if (!r->readLastVsyncMessage(&vsyncTimestamp, &vsyncCount)) { 139 ALOGV("receiver %p ~ Woke up but there was no vsync pulse!", data); 140 return 1; // keep the callback, did not obtain a vsync pulse 141 } 142 143 ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, count=%d", 144 data, vsyncTimestamp, vsyncCount); 145 r->mWaitingForVsync = false; 146 147 JNIEnv* env = AndroidRuntime::getJNIEnv(); 148 149 ALOGV("receiver %p ~ Invoking vsync handler.", data); 150 env->CallVoidMethod(r->mReceiverObjGlobal, 151 gDisplayEventReceiverClassInfo.dispatchVsync, vsyncTimestamp, vsyncCount); 152 ALOGV("receiver %p ~ Returned from vsync handler.", data); 153 154 r->mMessageQueue->raiseAndClearException(env, "dispatchVsync"); 155 return 1; // keep the callback 156} 157 158bool NativeDisplayEventReceiver::readLastVsyncMessage( 159 nsecs_t* outTimestamp, uint32_t* outCount) { 160 DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; 161 ssize_t n; 162 while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { 163 ALOGV("receiver %p ~ Read %d events.", this, int(n)); 164 while (n-- > 0) { 165 if (buf[n].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { 166 *outTimestamp = buf[n].header.timestamp; 167 *outCount = buf[n].vsync.count; 168 return true; // stop at last vsync in the buffer 169 } 170 } 171 } 172 if (n < 0) { 173 ALOGW("Failed to get events from display event receiver, status=%d", status_t(n)); 174 } 175 return false; 176} 177 178 179static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj, 180 jobject messageQueueObj) { 181 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); 182 if (messageQueue == NULL) { 183 jniThrowRuntimeException(env, "MessageQueue is not initialized."); 184 return 0; 185 } 186 187 sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env, 188 receiverObj, messageQueue); 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<jint>(receiver.get()); 199} 200 201static void nativeDispose(JNIEnv* env, jclass clazz, jint receiverPtr) { 202 sp<NativeDisplayEventReceiver> receiver = 203 reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr); 204 receiver->decStrong(gDisplayEventReceiverClassInfo.clazz); // drop reference held by the object 205} 206 207static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jint receiverPtr) { 208 sp<NativeDisplayEventReceiver> receiver = 209 reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr); 210 status_t status = receiver->scheduleVsync(); 211 if (status) { 212 String8 message; 213 message.appendFormat("Failed to schedule next vertical sync pulse. status=%d", status); 214 jniThrowRuntimeException(env, message.string()); 215 } 216} 217 218 219static JNINativeMethod gMethods[] = { 220 /* name, signature, funcPtr */ 221 { "nativeInit", 222 "(Landroid/view/DisplayEventReceiver;Landroid/os/MessageQueue;)I", 223 (void*)nativeInit }, 224 { "nativeDispose", 225 "(I)V", 226 (void*)nativeDispose }, 227 { "nativeScheduleVsync", "(I)V", 228 (void*)nativeScheduleVsync } 229}; 230 231#define FIND_CLASS(var, className) \ 232 var = env->FindClass(className); \ 233 LOG_FATAL_IF(! var, "Unable to find class " className); \ 234 var = jclass(env->NewGlobalRef(var)); 235 236#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ 237 var = env->GetMethodID(clazz, methodName, methodDescriptor); \ 238 LOG_FATAL_IF(! var, "Unable to find method " methodName); 239 240int register_android_view_DisplayEventReceiver(JNIEnv* env) { 241 int res = jniRegisterNativeMethods(env, "android/view/DisplayEventReceiver", 242 gMethods, NELEM(gMethods)); 243 LOG_FATAL_IF(res < 0, "Unable to register native methods."); 244 245 FIND_CLASS(gDisplayEventReceiverClassInfo.clazz, "android/view/DisplayEventReceiver"); 246 247 GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchVsync, 248 gDisplayEventReceiverClassInfo.clazz, 249 "dispatchVsync", "(JI)V"); 250 return 0; 251} 252 253} // namespace android 254