blob: 0d5495356fadb78b919155694d5bbf7f43714f21 [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
Jeff Brown0a0a1242011-12-02 02:25:22 -080021#include "JNIHelp.h"
22
Dan Albert46d84442014-11-18 16:07:51 -080023#include <inttypes.h>
24
Jeff Brown0a0a1242011-12-02 02:25:22 -080025#include <android_runtime/AndroidRuntime.h>
26#include <utils/Log.h>
27#include <utils/Looper.h>
28#include <utils/threads.h>
29#include <gui/DisplayEventReceiver.h>
30#include "android_os_MessageQueue.h"
31
Andreas Gampe987f79f2014-11-18 17:29:46 -080032#include "core_jni_helpers.h"
33
Jeff Brown0a0a1242011-12-02 02:25:22 -080034namespace android {
35
36// Number of events to read at a time from the DisplayEventReceiver pipe.
37// The value should be large enough that we can quickly drain the pipe
38// using just a few large reads.
39static const size_t EVENT_BUFFER_SIZE = 100;
40
41static struct {
42 jclass clazz;
43
44 jmethodID dispatchVsync;
Jeff Browne87bf032012-09-20 18:30:13 -070045 jmethodID dispatchHotplug;
Jeff Brown0a0a1242011-12-02 02:25:22 -080046} gDisplayEventReceiverClassInfo;
47
48
Jeff Brown80a1de12012-05-31 16:23:11 -070049class NativeDisplayEventReceiver : public LooperCallback {
Jeff Brown0a0a1242011-12-02 02:25:22 -080050public:
51 NativeDisplayEventReceiver(JNIEnv* env,
Jeff Brown603b4452012-04-06 17:39:41 -070052 jobject receiverObj, const sp<MessageQueue>& messageQueue);
Jeff Brown0a0a1242011-12-02 02:25:22 -080053
54 status_t initialize();
Jeff Brown80a1de12012-05-31 16:23:11 -070055 void dispose();
Jeff Brown0a0a1242011-12-02 02:25:22 -080056 status_t scheduleVsync();
Jeff Brown0a0a1242011-12-02 02:25:22 -080057
58protected:
59 virtual ~NativeDisplayEventReceiver();
60
61private:
62 jobject mReceiverObjGlobal;
Jeff Brown603b4452012-04-06 17:39:41 -070063 sp<MessageQueue> mMessageQueue;
Jeff Brown0a0a1242011-12-02 02:25:22 -080064 DisplayEventReceiver mReceiver;
65 bool mWaitingForVsync;
Jeff Brownbec0a862012-03-29 12:42:31 -070066
Jeff Brown80a1de12012-05-31 16:23:11 -070067 virtual int handleEvent(int receiveFd, int events, void* data);
Jesse Hall16823bd2012-11-19 10:53:26 -080068 bool processPendingEvents(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount);
Jeff Browne87bf032012-09-20 18:30:13 -070069 void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
70 void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
Jeff Brown0a0a1242011-12-02 02:25:22 -080071};
72
73
74NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
Jeff Brown603b4452012-04-06 17:39:41 -070075 jobject receiverObj, const sp<MessageQueue>& messageQueue) :
Jeff Brown0a0a1242011-12-02 02:25:22 -080076 mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
Jeff Brown603b4452012-04-06 17:39:41 -070077 mMessageQueue(messageQueue), mWaitingForVsync(false) {
Jeff Brown0a0a1242011-12-02 02:25:22 -080078 ALOGV("receiver %p ~ Initializing input event receiver.", this);
79}
80
81NativeDisplayEventReceiver::~NativeDisplayEventReceiver() {
Jeff Brown0a0a1242011-12-02 02:25:22 -080082 JNIEnv* env = AndroidRuntime::getJNIEnv();
83 env->DeleteGlobalRef(mReceiverObjGlobal);
84}
85
86status_t NativeDisplayEventReceiver::initialize() {
87 status_t result = mReceiver.initCheck();
88 if (result) {
Steve Block8564c8d2012-01-05 23:22:43 +000089 ALOGW("Failed to initialize display event receiver, status=%d", result);
Jeff Brown0a0a1242011-12-02 02:25:22 -080090 return result;
91 }
92
Brian Carlstrom82b007d2013-12-12 23:12:55 -080093 int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
Jeff Brown80a1de12012-05-31 16:23:11 -070094 this, NULL);
Jeff Brown58aedbc2012-02-13 20:15:01 -080095 if (rc < 0) {
96 return UNKNOWN_ERROR;
97 }
Jeff Brown0a0a1242011-12-02 02:25:22 -080098 return OK;
99}
100
Jeff Brown80a1de12012-05-31 16:23:11 -0700101void NativeDisplayEventReceiver::dispose() {
102 ALOGV("receiver %p ~ Disposing display event receiver.", this);
103
104 if (!mReceiver.initCheck()) {
105 mMessageQueue->getLooper()->removeFd(mReceiver.getFd());
106 }
107}
108
Jeff Brown0a0a1242011-12-02 02:25:22 -0800109status_t NativeDisplayEventReceiver::scheduleVsync() {
110 if (!mWaitingForVsync) {
111 ALOGV("receiver %p ~ Scheduling vsync.", this);
112
113 // Drain all pending events.
Jeff Brownbec0a862012-03-29 12:42:31 -0700114 nsecs_t vsyncTimestamp;
Jeff Browne87bf032012-09-20 18:30:13 -0700115 int32_t vsyncDisplayId;
Jeff Brownbec0a862012-03-29 12:42:31 -0700116 uint32_t vsyncCount;
Jesse Hall16823bd2012-11-19 10:53:26 -0800117 processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800118
Mathias Agopian6779df22011-12-06 17:22:19 -0800119 status_t status = mReceiver.requestNextVsync();
120 if (status) {
Steve Block8564c8d2012-01-05 23:22:43 +0000121 ALOGW("Failed to request next vsync, status=%d", status);
Mathias Agopian6779df22011-12-06 17:22:19 -0800122 return status;
123 }
124
Jeff Brown0a0a1242011-12-02 02:25:22 -0800125 mWaitingForVsync = true;
126 }
127 return OK;
128}
129
Jeff Brown80a1de12012-05-31 16:23:11 -0700130int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* data) {
Brian Carlstrom82b007d2013-12-12 23:12:55 -0800131 if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
Steve Block3762c312012-01-06 19:20:56 +0000132 ALOGE("Display event receiver pipe was closed or an error occurred. "
Jeff Brown0a0a1242011-12-02 02:25:22 -0800133 "events=0x%x", events);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800134 return 0; // remove the callback
135 }
136
Brian Carlstrom82b007d2013-12-12 23:12:55 -0800137 if (!(events & Looper::EVENT_INPUT)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000138 ALOGW("Received spurious callback for unhandled poll event. "
Jeff Brown0a0a1242011-12-02 02:25:22 -0800139 "events=0x%x", events);
140 return 1; // keep the callback
141 }
142
143 // Drain all pending events, keep the last vsync.
Jeff Brownbec0a862012-03-29 12:42:31 -0700144 nsecs_t vsyncTimestamp;
Jeff Browne87bf032012-09-20 18:30:13 -0700145 int32_t vsyncDisplayId;
Jeff Brownbec0a862012-03-29 12:42:31 -0700146 uint32_t vsyncCount;
Jesse Hall16823bd2012-11-19 10:53:26 -0800147 if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
Dan Albert46d84442014-11-18 16:07:51 -0800148 ALOGV("receiver %p ~ Vsync pulse: timestamp=%" PRId64 ", id=%d, count=%d",
Jesse Hall16823bd2012-11-19 10:53:26 -0800149 this, vsyncTimestamp, vsyncDisplayId, vsyncCount);
150 mWaitingForVsync = false;
151 dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800152 }
153
Jeff Brown58aedbc2012-02-13 20:15:01 -0800154 return 1; // keep the callback
Jeff Brown0a0a1242011-12-02 02:25:22 -0800155}
156
Jesse Hall16823bd2012-11-19 10:53:26 -0800157bool NativeDisplayEventReceiver::processPendingEvents(
Jeff Browne87bf032012-09-20 18:30:13 -0700158 nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount) {
Jesse Hall16823bd2012-11-19 10:53:26 -0800159 bool gotVsync = false;
Jeff Brownbec0a862012-03-29 12:42:31 -0700160 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));
Jesse Hall16823bd2012-11-19 10:53:26 -0800164 for (ssize_t i = 0; i < n; i++) {
165 const DisplayEventReceiver::Event& ev = buf[i];
166 switch (ev.header.type) {
167 case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
168 // Later vsync events will just overwrite the info from earlier
169 // ones. That's fine, we only care about the most recent.
170 gotVsync = true;
Jeff Browne87bf032012-09-20 18:30:13 -0700171 *outTimestamp = ev.header.timestamp;
172 *outId = ev.header.id;
173 *outCount = ev.vsync.count;
Jesse Hall16823bd2012-11-19 10:53:26 -0800174 break;
175 case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
Jeff Browne87bf032012-09-20 18:30:13 -0700176 dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected);
Jesse Hall16823bd2012-11-19 10:53:26 -0800177 break;
178 default:
179 ALOGW("receiver %p ~ ignoring unknown event type %#x", this, ev.header.type);
180 break;
Jeff Browne87bf032012-09-20 18:30:13 -0700181 }
Jeff Brownbec0a862012-03-29 12:42:31 -0700182 }
183 }
184 if (n < 0) {
185 ALOGW("Failed to get events from display event receiver, status=%d", status_t(n));
186 }
Jesse Hall16823bd2012-11-19 10:53:26 -0800187 return gotVsync;
Jeff Brownbec0a862012-03-29 12:42:31 -0700188}
189
Jeff Browne87bf032012-09-20 18:30:13 -0700190void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {
191 JNIEnv* env = AndroidRuntime::getJNIEnv();
192
193 ALOGV("receiver %p ~ Invoking vsync handler.", this);
194 env->CallVoidMethod(mReceiverObjGlobal,
195 gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
196 ALOGV("receiver %p ~ Returned from vsync handler.", this);
197
198 mMessageQueue->raiseAndClearException(env, "dispatchVsync");
199}
200
201void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected) {
202 JNIEnv* env = AndroidRuntime::getJNIEnv();
203
204 ALOGV("receiver %p ~ Invoking hotplug handler.", this);
205 env->CallVoidMethod(mReceiverObjGlobal,
206 gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, id, connected);
207 ALOGV("receiver %p ~ Returned from hotplug handler.", this);
208
209 mMessageQueue->raiseAndClearException(env, "dispatchHotplug");
210}
211
Jeff Brown0a0a1242011-12-02 02:25:22 -0800212
Ashok Bhat27285822013-12-18 18:00:05 +0000213static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
Jeff Brown0a0a1242011-12-02 02:25:22 -0800214 jobject messageQueueObj) {
Jeff Brown603b4452012-04-06 17:39:41 -0700215 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
216 if (messageQueue == NULL) {
Jeff Brown0a0a1242011-12-02 02:25:22 -0800217 jniThrowRuntimeException(env, "MessageQueue is not initialized.");
218 return 0;
219 }
220
221 sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
Jeff Brown603b4452012-04-06 17:39:41 -0700222 receiverObj, messageQueue);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800223 status_t status = receiver->initialize();
224 if (status) {
225 String8 message;
226 message.appendFormat("Failed to initialize display event receiver. status=%d", status);
227 jniThrowRuntimeException(env, message.string());
228 return 0;
229 }
230
231 receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
Ashok Bhat27285822013-12-18 18:00:05 +0000232 return reinterpret_cast<jlong>(receiver.get());
Jeff Brown0a0a1242011-12-02 02:25:22 -0800233}
234
Ashok Bhat27285822013-12-18 18:00:05 +0000235static void nativeDispose(JNIEnv* env, jclass clazz, jlong receiverPtr) {
Jeff Brown0a0a1242011-12-02 02:25:22 -0800236 sp<NativeDisplayEventReceiver> receiver =
237 reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
Jeff Brown80a1de12012-05-31 16:23:11 -0700238 receiver->dispose();
Jeff Brown0a0a1242011-12-02 02:25:22 -0800239 receiver->decStrong(gDisplayEventReceiverClassInfo.clazz); // drop reference held by the object
240}
241
Ashok Bhat27285822013-12-18 18:00:05 +0000242static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
Jeff Brown0a0a1242011-12-02 02:25:22 -0800243 sp<NativeDisplayEventReceiver> receiver =
244 reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
245 status_t status = receiver->scheduleVsync();
246 if (status) {
247 String8 message;
248 message.appendFormat("Failed to schedule next vertical sync pulse. status=%d", status);
249 jniThrowRuntimeException(env, message.string());
250 }
251}
252
253
254static JNINativeMethod gMethods[] = {
255 /* name, signature, funcPtr */
256 { "nativeInit",
Ashok Bhat27285822013-12-18 18:00:05 +0000257 "(Landroid/view/DisplayEventReceiver;Landroid/os/MessageQueue;)J",
Jeff Brown0a0a1242011-12-02 02:25:22 -0800258 (void*)nativeInit },
259 { "nativeDispose",
Ashok Bhat27285822013-12-18 18:00:05 +0000260 "(J)V",
Jeff Brown0a0a1242011-12-02 02:25:22 -0800261 (void*)nativeDispose },
Ashok Bhat27285822013-12-18 18:00:05 +0000262 { "nativeScheduleVsync", "(J)V",
Jeff Brown0a0a1242011-12-02 02:25:22 -0800263 (void*)nativeScheduleVsync }
264};
265
Jeff Brown0a0a1242011-12-02 02:25:22 -0800266int register_android_view_DisplayEventReceiver(JNIEnv* env) {
Andreas Gampe987f79f2014-11-18 17:29:46 -0800267 int res = RegisterMethodsOrDie(env, "android/view/DisplayEventReceiver", gMethods,
268 NELEM(gMethods));
Jeff Brown0a0a1242011-12-02 02:25:22 -0800269
Andreas Gampe987f79f2014-11-18 17:29:46 -0800270 jclass clazz = FindClassOrDie(env, "android/view/DisplayEventReceiver");
271 gDisplayEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800272
Andreas Gampe987f79f2014-11-18 17:29:46 -0800273 gDisplayEventReceiverClassInfo.dispatchVsync = GetMethodIDOrDie(env,
274 gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JII)V");
275 gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
276 gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JIZ)V");
277
278 return res;
Jeff Brown0a0a1242011-12-02 02:25:22 -0800279}
280
281} // namespace android