blob: 3d9d005637a3671c3893efe36141e4d362086a16 [file] [log] [blame]
Jeff Brown0a0a1242011-12-02 02:25:22 -08001/*
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;
Jeff Browne87bf032012-09-20 18:30:13 -070042 jmethodID dispatchHotplug;
Jeff Brown0a0a1242011-12-02 02:25:22 -080043} gDisplayEventReceiverClassInfo;
44
45
Jeff Brown80a1de12012-05-31 16:23:11 -070046class NativeDisplayEventReceiver : public LooperCallback {
Jeff Brown0a0a1242011-12-02 02:25:22 -080047public:
48 NativeDisplayEventReceiver(JNIEnv* env,
Jeff Brown603b4452012-04-06 17:39:41 -070049 jobject receiverObj, const sp<MessageQueue>& messageQueue);
Jeff Brown0a0a1242011-12-02 02:25:22 -080050
51 status_t initialize();
Jeff Brown80a1de12012-05-31 16:23:11 -070052 void dispose();
Jeff Brown0a0a1242011-12-02 02:25:22 -080053 status_t scheduleVsync();
Jeff Brown0a0a1242011-12-02 02:25:22 -080054
55protected:
56 virtual ~NativeDisplayEventReceiver();
57
58private:
59 jobject mReceiverObjGlobal;
Jeff Brown603b4452012-04-06 17:39:41 -070060 sp<MessageQueue> mMessageQueue;
Jeff Brown0a0a1242011-12-02 02:25:22 -080061 DisplayEventReceiver mReceiver;
62 bool mWaitingForVsync;
Jeff Brownbec0a862012-03-29 12:42:31 -070063
Jeff Brown80a1de12012-05-31 16:23:11 -070064 virtual int handleEvent(int receiveFd, int events, void* data);
Jeff Browne87bf032012-09-20 18:30:13 -070065 bool readLastVsyncMessage(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount);
66 void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
67 void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
Jeff Brown0a0a1242011-12-02 02:25:22 -080068};
69
70
71NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
Jeff Brown603b4452012-04-06 17:39:41 -070072 jobject receiverObj, const sp<MessageQueue>& messageQueue) :
Jeff Brown0a0a1242011-12-02 02:25:22 -080073 mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
Jeff Brown603b4452012-04-06 17:39:41 -070074 mMessageQueue(messageQueue), mWaitingForVsync(false) {
Jeff Brown0a0a1242011-12-02 02:25:22 -080075 ALOGV("receiver %p ~ Initializing input event receiver.", this);
76}
77
78NativeDisplayEventReceiver::~NativeDisplayEventReceiver() {
Jeff Brown0a0a1242011-12-02 02:25:22 -080079 JNIEnv* env = AndroidRuntime::getJNIEnv();
80 env->DeleteGlobalRef(mReceiverObjGlobal);
81}
82
83status_t NativeDisplayEventReceiver::initialize() {
84 status_t result = mReceiver.initCheck();
85 if (result) {
Steve Block8564c8d2012-01-05 23:22:43 +000086 ALOGW("Failed to initialize display event receiver, status=%d", result);
Jeff Brown0a0a1242011-12-02 02:25:22 -080087 return result;
88 }
89
Jeff Brown603b4452012-04-06 17:39:41 -070090 int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT,
Jeff Brown80a1de12012-05-31 16:23:11 -070091 this, NULL);
Jeff Brown58aedbc2012-02-13 20:15:01 -080092 if (rc < 0) {
93 return UNKNOWN_ERROR;
94 }
Jeff Brown0a0a1242011-12-02 02:25:22 -080095 return OK;
96}
97
Jeff Brown80a1de12012-05-31 16:23:11 -070098void NativeDisplayEventReceiver::dispose() {
99 ALOGV("receiver %p ~ Disposing display event receiver.", this);
100
101 if (!mReceiver.initCheck()) {
102 mMessageQueue->getLooper()->removeFd(mReceiver.getFd());
103 }
104}
105
Jeff Brown0a0a1242011-12-02 02:25:22 -0800106status_t NativeDisplayEventReceiver::scheduleVsync() {
107 if (!mWaitingForVsync) {
108 ALOGV("receiver %p ~ Scheduling vsync.", this);
109
110 // Drain all pending events.
Jeff Brownbec0a862012-03-29 12:42:31 -0700111 nsecs_t vsyncTimestamp;
Jeff Browne87bf032012-09-20 18:30:13 -0700112 int32_t vsyncDisplayId;
Jeff Brownbec0a862012-03-29 12:42:31 -0700113 uint32_t vsyncCount;
Jeff Browne87bf032012-09-20 18:30:13 -0700114 readLastVsyncMessage(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800115
Mathias Agopian6779df22011-12-06 17:22:19 -0800116 status_t status = mReceiver.requestNextVsync();
117 if (status) {
Steve Block8564c8d2012-01-05 23:22:43 +0000118 ALOGW("Failed to request next vsync, status=%d", status);
Mathias Agopian6779df22011-12-06 17:22:19 -0800119 return status;
120 }
121
Jeff Brown0a0a1242011-12-02 02:25:22 -0800122 mWaitingForVsync = true;
123 }
124 return OK;
125}
126
Jeff Brown80a1de12012-05-31 16:23:11 -0700127int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* data) {
Jeff Brown0a0a1242011-12-02 02:25:22 -0800128 if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
Steve Block3762c312012-01-06 19:20:56 +0000129 ALOGE("Display event receiver pipe was closed or an error occurred. "
Jeff Brown0a0a1242011-12-02 02:25:22 -0800130 "events=0x%x", events);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800131 return 0; // remove the callback
132 }
133
134 if (!(events & ALOOPER_EVENT_INPUT)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000135 ALOGW("Received spurious callback for unhandled poll event. "
Jeff Brown0a0a1242011-12-02 02:25:22 -0800136 "events=0x%x", events);
137 return 1; // keep the callback
138 }
139
140 // Drain all pending events, keep the last vsync.
Jeff Brownbec0a862012-03-29 12:42:31 -0700141 nsecs_t vsyncTimestamp;
Jeff Browne87bf032012-09-20 18:30:13 -0700142 int32_t vsyncDisplayId;
Jeff Brownbec0a862012-03-29 12:42:31 -0700143 uint32_t vsyncCount;
Jeff Browne87bf032012-09-20 18:30:13 -0700144 if (!readLastVsyncMessage(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
Jeff Brown80a1de12012-05-31 16:23:11 -0700145 ALOGV("receiver %p ~ Woke up but there was no vsync pulse!", this);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800146 return 1; // keep the callback, did not obtain a vsync pulse
147 }
148
Jeff Browne87bf032012-09-20 18:30:13 -0700149 ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, id=%d, count=%d",
150 this, vsyncTimestamp, vsyncDisplayId, vsyncCount);
Jeff Brown80a1de12012-05-31 16:23:11 -0700151 mWaitingForVsync = false;
Jeff Brown0a0a1242011-12-02 02:25:22 -0800152
Jeff Browne87bf032012-09-20 18:30:13 -0700153 dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
Jeff Brown58aedbc2012-02-13 20:15:01 -0800154 return 1; // keep the callback
Jeff Brown0a0a1242011-12-02 02:25:22 -0800155}
156
Jeff Brownbec0a862012-03-29 12:42:31 -0700157bool NativeDisplayEventReceiver::readLastVsyncMessage(
Jeff Browne87bf032012-09-20 18:30:13 -0700158 nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount) {
Jeff Brownbec0a862012-03-29 12:42:31 -0700159 DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
160 ssize_t n;
161 while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
162 ALOGV("receiver %p ~ Read %d events.", this, int(n));
163 while (n-- > 0) {
Jeff Browne87bf032012-09-20 18:30:13 -0700164 const DisplayEventReceiver::Event& ev = buf[n];
165 if (ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
166 *outTimestamp = ev.header.timestamp;
167 *outId = ev.header.id;
168 *outCount = ev.vsync.count;
Jeff Brownbec0a862012-03-29 12:42:31 -0700169 return true; // stop at last vsync in the buffer
170 }
Jeff Browne87bf032012-09-20 18:30:13 -0700171
172 if (ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG) {
173 dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected);
174 }
Jeff Brownbec0a862012-03-29 12:42:31 -0700175 }
176 }
177 if (n < 0) {
178 ALOGW("Failed to get events from display event receiver, status=%d", status_t(n));
179 }
180 return false;
181}
182
Jeff Browne87bf032012-09-20 18:30:13 -0700183void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {
184 JNIEnv* env = AndroidRuntime::getJNIEnv();
185
186 ALOGV("receiver %p ~ Invoking vsync handler.", this);
187 env->CallVoidMethod(mReceiverObjGlobal,
188 gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
189 ALOGV("receiver %p ~ Returned from vsync handler.", this);
190
191 mMessageQueue->raiseAndClearException(env, "dispatchVsync");
192}
193
194void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected) {
195 JNIEnv* env = AndroidRuntime::getJNIEnv();
196
197 ALOGV("receiver %p ~ Invoking hotplug handler.", this);
198 env->CallVoidMethod(mReceiverObjGlobal,
199 gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, id, connected);
200 ALOGV("receiver %p ~ Returned from hotplug handler.", this);
201
202 mMessageQueue->raiseAndClearException(env, "dispatchHotplug");
203}
204
Jeff Brown0a0a1242011-12-02 02:25:22 -0800205
206static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
207 jobject messageQueueObj) {
Jeff Brown603b4452012-04-06 17:39:41 -0700208 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
209 if (messageQueue == NULL) {
Jeff Brown0a0a1242011-12-02 02:25:22 -0800210 jniThrowRuntimeException(env, "MessageQueue is not initialized.");
211 return 0;
212 }
213
214 sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
Jeff Brown603b4452012-04-06 17:39:41 -0700215 receiverObj, messageQueue);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800216 status_t status = receiver->initialize();
217 if (status) {
218 String8 message;
219 message.appendFormat("Failed to initialize display event receiver. status=%d", status);
220 jniThrowRuntimeException(env, message.string());
221 return 0;
222 }
223
224 receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
225 return reinterpret_cast<jint>(receiver.get());
226}
227
228static void nativeDispose(JNIEnv* env, jclass clazz, jint receiverPtr) {
229 sp<NativeDisplayEventReceiver> receiver =
230 reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
Jeff Brown80a1de12012-05-31 16:23:11 -0700231 receiver->dispose();
Jeff Brown0a0a1242011-12-02 02:25:22 -0800232 receiver->decStrong(gDisplayEventReceiverClassInfo.clazz); // drop reference held by the object
233}
234
235static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jint receiverPtr) {
236 sp<NativeDisplayEventReceiver> receiver =
237 reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
238 status_t status = receiver->scheduleVsync();
239 if (status) {
240 String8 message;
241 message.appendFormat("Failed to schedule next vertical sync pulse. status=%d", status);
242 jniThrowRuntimeException(env, message.string());
243 }
244}
245
246
247static JNINativeMethod gMethods[] = {
248 /* name, signature, funcPtr */
249 { "nativeInit",
250 "(Landroid/view/DisplayEventReceiver;Landroid/os/MessageQueue;)I",
251 (void*)nativeInit },
252 { "nativeDispose",
253 "(I)V",
254 (void*)nativeDispose },
255 { "nativeScheduleVsync", "(I)V",
256 (void*)nativeScheduleVsync }
257};
258
259#define FIND_CLASS(var, className) \
260 var = env->FindClass(className); \
261 LOG_FATAL_IF(! var, "Unable to find class " className); \
262 var = jclass(env->NewGlobalRef(var));
263
264#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
265 var = env->GetMethodID(clazz, methodName, methodDescriptor); \
266 LOG_FATAL_IF(! var, "Unable to find method " methodName);
267
268int register_android_view_DisplayEventReceiver(JNIEnv* env) {
269 int res = jniRegisterNativeMethods(env, "android/view/DisplayEventReceiver",
270 gMethods, NELEM(gMethods));
271 LOG_FATAL_IF(res < 0, "Unable to register native methods.");
272
273 FIND_CLASS(gDisplayEventReceiverClassInfo.clazz, "android/view/DisplayEventReceiver");
274
275 GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchVsync,
276 gDisplayEventReceiverClassInfo.clazz,
Jeff Browne87bf032012-09-20 18:30:13 -0700277 "dispatchVsync", "(JII)V");
278 GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchHotplug,
279 gDisplayEventReceiverClassInfo.clazz,
280 "dispatchHotplug", "(JIZ)V");
Jeff Brown0a0a1242011-12-02 02:25:22 -0800281 return 0;
282}
283
284} // namespace android