blob: 91a3c7e6891f86bc9f4f2b827d01127579c6e182 [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
Jeff Brown3b4049e2015-04-17 15:22:27 -070032#include <ScopedLocalRef.h>
33
Andreas Gampe987f79f2014-11-18 17:29:46 -080034#include "core_jni_helpers.h"
35
Jeff Brown0a0a1242011-12-02 02:25:22 -080036namespace android {
37
38// Number of events to read at a time from the DisplayEventReceiver pipe.
39// The value should be large enough that we can quickly drain the pipe
40// using just a few large reads.
41static const size_t EVENT_BUFFER_SIZE = 100;
42
43static struct {
44 jclass clazz;
45
46 jmethodID dispatchVsync;
Jeff Browne87bf032012-09-20 18:30:13 -070047 jmethodID dispatchHotplug;
Jeff Brown0a0a1242011-12-02 02:25:22 -080048} gDisplayEventReceiverClassInfo;
49
50
Jeff Brown80a1de12012-05-31 16:23:11 -070051class NativeDisplayEventReceiver : public LooperCallback {
Jeff Brown0a0a1242011-12-02 02:25:22 -080052public:
53 NativeDisplayEventReceiver(JNIEnv* env,
Jeff Brown3b4049e2015-04-17 15:22:27 -070054 jobject receiverWeak, const sp<MessageQueue>& messageQueue);
Jeff Brown0a0a1242011-12-02 02:25:22 -080055
56 status_t initialize();
Jeff Brown80a1de12012-05-31 16:23:11 -070057 void dispose();
Jeff Brown0a0a1242011-12-02 02:25:22 -080058 status_t scheduleVsync();
Jeff Brown0a0a1242011-12-02 02:25:22 -080059
60protected:
61 virtual ~NativeDisplayEventReceiver();
62
63private:
Jeff Brown3b4049e2015-04-17 15:22:27 -070064 jobject mReceiverWeakGlobal;
Jeff Brown603b4452012-04-06 17:39:41 -070065 sp<MessageQueue> mMessageQueue;
Jeff Brown0a0a1242011-12-02 02:25:22 -080066 DisplayEventReceiver mReceiver;
67 bool mWaitingForVsync;
Jeff Brownbec0a862012-03-29 12:42:31 -070068
Jeff Brown80a1de12012-05-31 16:23:11 -070069 virtual int handleEvent(int receiveFd, int events, void* data);
Jesse Hall16823bd2012-11-19 10:53:26 -080070 bool processPendingEvents(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount);
Jeff Browne87bf032012-09-20 18:30:13 -070071 void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
72 void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
Jeff Brown0a0a1242011-12-02 02:25:22 -080073};
74
75
76NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
Jeff Brown3b4049e2015-04-17 15:22:27 -070077 jobject receiverWeak, const sp<MessageQueue>& messageQueue) :
78 mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
Jeff Brown603b4452012-04-06 17:39:41 -070079 mMessageQueue(messageQueue), mWaitingForVsync(false) {
Jeff Brown0a0a1242011-12-02 02:25:22 -080080 ALOGV("receiver %p ~ Initializing input event receiver.", this);
81}
82
83NativeDisplayEventReceiver::~NativeDisplayEventReceiver() {
Jeff Brown0a0a1242011-12-02 02:25:22 -080084 JNIEnv* env = AndroidRuntime::getJNIEnv();
Jeff Brown3b4049e2015-04-17 15:22:27 -070085 env->DeleteGlobalRef(mReceiverWeakGlobal);
Jeff Brown0a0a1242011-12-02 02:25:22 -080086}
87
88status_t NativeDisplayEventReceiver::initialize() {
89 status_t result = mReceiver.initCheck();
90 if (result) {
Steve Block8564c8d2012-01-05 23:22:43 +000091 ALOGW("Failed to initialize display event receiver, status=%d", result);
Jeff Brown0a0a1242011-12-02 02:25:22 -080092 return result;
93 }
94
Brian Carlstrom82b007d2013-12-12 23:12:55 -080095 int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
Jeff Brown80a1de12012-05-31 16:23:11 -070096 this, NULL);
Jeff Brown58aedbc2012-02-13 20:15:01 -080097 if (rc < 0) {
98 return UNKNOWN_ERROR;
99 }
Jeff Brown0a0a1242011-12-02 02:25:22 -0800100 return OK;
101}
102
Jeff Brown80a1de12012-05-31 16:23:11 -0700103void NativeDisplayEventReceiver::dispose() {
104 ALOGV("receiver %p ~ Disposing display event receiver.", this);
105
106 if (!mReceiver.initCheck()) {
107 mMessageQueue->getLooper()->removeFd(mReceiver.getFd());
108 }
109}
110
Jeff Brown0a0a1242011-12-02 02:25:22 -0800111status_t NativeDisplayEventReceiver::scheduleVsync() {
112 if (!mWaitingForVsync) {
113 ALOGV("receiver %p ~ Scheduling vsync.", this);
114
115 // Drain all pending events.
Jeff Brownbec0a862012-03-29 12:42:31 -0700116 nsecs_t vsyncTimestamp;
Jeff Browne87bf032012-09-20 18:30:13 -0700117 int32_t vsyncDisplayId;
Jeff Brownbec0a862012-03-29 12:42:31 -0700118 uint32_t vsyncCount;
Jesse Hall16823bd2012-11-19 10:53:26 -0800119 processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800120
Mathias Agopian6779df22011-12-06 17:22:19 -0800121 status_t status = mReceiver.requestNextVsync();
122 if (status) {
Steve Block8564c8d2012-01-05 23:22:43 +0000123 ALOGW("Failed to request next vsync, status=%d", status);
Mathias Agopian6779df22011-12-06 17:22:19 -0800124 return status;
125 }
126
Jeff Brown0a0a1242011-12-02 02:25:22 -0800127 mWaitingForVsync = true;
128 }
129 return OK;
130}
131
Jeff Brown80a1de12012-05-31 16:23:11 -0700132int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* data) {
Brian Carlstrom82b007d2013-12-12 23:12:55 -0800133 if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
Steve Block3762c312012-01-06 19:20:56 +0000134 ALOGE("Display event receiver pipe was closed or an error occurred. "
Jeff Brown0a0a1242011-12-02 02:25:22 -0800135 "events=0x%x", events);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800136 return 0; // remove the callback
137 }
138
Brian Carlstrom82b007d2013-12-12 23:12:55 -0800139 if (!(events & Looper::EVENT_INPUT)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000140 ALOGW("Received spurious callback for unhandled poll event. "
Jeff Brown0a0a1242011-12-02 02:25:22 -0800141 "events=0x%x", events);
142 return 1; // keep the callback
143 }
144
145 // Drain all pending events, keep the last vsync.
Jeff Brownbec0a862012-03-29 12:42:31 -0700146 nsecs_t vsyncTimestamp;
Jeff Browne87bf032012-09-20 18:30:13 -0700147 int32_t vsyncDisplayId;
Jeff Brownbec0a862012-03-29 12:42:31 -0700148 uint32_t vsyncCount;
Jesse Hall16823bd2012-11-19 10:53:26 -0800149 if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
Dan Albert46d84442014-11-18 16:07:51 -0800150 ALOGV("receiver %p ~ Vsync pulse: timestamp=%" PRId64 ", id=%d, count=%d",
Jesse Hall16823bd2012-11-19 10:53:26 -0800151 this, vsyncTimestamp, vsyncDisplayId, vsyncCount);
152 mWaitingForVsync = false;
153 dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800154 }
155
Jeff Brown58aedbc2012-02-13 20:15:01 -0800156 return 1; // keep the callback
Jeff Brown0a0a1242011-12-02 02:25:22 -0800157}
158
Jesse Hall16823bd2012-11-19 10:53:26 -0800159bool NativeDisplayEventReceiver::processPendingEvents(
Jeff Browne87bf032012-09-20 18:30:13 -0700160 nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount) {
Jesse Hall16823bd2012-11-19 10:53:26 -0800161 bool gotVsync = false;
Jeff Brownbec0a862012-03-29 12:42:31 -0700162 DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
163 ssize_t n;
164 while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
165 ALOGV("receiver %p ~ Read %d events.", this, int(n));
Jesse Hall16823bd2012-11-19 10:53:26 -0800166 for (ssize_t i = 0; i < n; i++) {
167 const DisplayEventReceiver::Event& ev = buf[i];
168 switch (ev.header.type) {
169 case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
170 // Later vsync events will just overwrite the info from earlier
171 // ones. That's fine, we only care about the most recent.
172 gotVsync = true;
Jeff Browne87bf032012-09-20 18:30:13 -0700173 *outTimestamp = ev.header.timestamp;
174 *outId = ev.header.id;
175 *outCount = ev.vsync.count;
Jesse Hall16823bd2012-11-19 10:53:26 -0800176 break;
177 case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
Jeff Browne87bf032012-09-20 18:30:13 -0700178 dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected);
Jesse Hall16823bd2012-11-19 10:53:26 -0800179 break;
180 default:
181 ALOGW("receiver %p ~ ignoring unknown event type %#x", this, ev.header.type);
182 break;
Jeff Browne87bf032012-09-20 18:30:13 -0700183 }
Jeff Brownbec0a862012-03-29 12:42:31 -0700184 }
185 }
186 if (n < 0) {
187 ALOGW("Failed to get events from display event receiver, status=%d", status_t(n));
188 }
Jesse Hall16823bd2012-11-19 10:53:26 -0800189 return gotVsync;
Jeff Brownbec0a862012-03-29 12:42:31 -0700190}
191
Jeff Browne87bf032012-09-20 18:30:13 -0700192void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {
193 JNIEnv* env = AndroidRuntime::getJNIEnv();
194
Jeff Brown3b4049e2015-04-17 15:22:27 -0700195 ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
196 if (receiverObj.get()) {
197 ALOGV("receiver %p ~ Invoking vsync handler.", this);
198 env->CallVoidMethod(receiverObj.get(),
199 gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
200 ALOGV("receiver %p ~ Returned from vsync handler.", this);
201 }
Jeff Browne87bf032012-09-20 18:30:13 -0700202
203 mMessageQueue->raiseAndClearException(env, "dispatchVsync");
204}
205
206void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected) {
207 JNIEnv* env = AndroidRuntime::getJNIEnv();
208
Jeff Brown3b4049e2015-04-17 15:22:27 -0700209 ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
210 if (receiverObj.get()) {
211 ALOGV("receiver %p ~ Invoking hotplug handler.", this);
212 env->CallVoidMethod(receiverObj.get(),
213 gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, id, connected);
214 ALOGV("receiver %p ~ Returned from hotplug handler.", this);
215 }
Jeff Browne87bf032012-09-20 18:30:13 -0700216
217 mMessageQueue->raiseAndClearException(env, "dispatchHotplug");
218}
219
Jeff Brown0a0a1242011-12-02 02:25:22 -0800220
Jeff Brown3b4049e2015-04-17 15:22:27 -0700221static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
Jeff Brown0a0a1242011-12-02 02:25:22 -0800222 jobject messageQueueObj) {
Jeff Brown603b4452012-04-06 17:39:41 -0700223 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
224 if (messageQueue == NULL) {
Jeff Brown0a0a1242011-12-02 02:25:22 -0800225 jniThrowRuntimeException(env, "MessageQueue is not initialized.");
226 return 0;
227 }
228
229 sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
Jeff Brown3b4049e2015-04-17 15:22:27 -0700230 receiverWeak, messageQueue);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800231 status_t status = receiver->initialize();
232 if (status) {
233 String8 message;
234 message.appendFormat("Failed to initialize display event receiver. status=%d", status);
235 jniThrowRuntimeException(env, message.string());
236 return 0;
237 }
238
239 receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
Ashok Bhat27285822013-12-18 18:00:05 +0000240 return reinterpret_cast<jlong>(receiver.get());
Jeff Brown0a0a1242011-12-02 02:25:22 -0800241}
242
Ashok Bhat27285822013-12-18 18:00:05 +0000243static void nativeDispose(JNIEnv* env, jclass clazz, jlong receiverPtr) {
Jeff Brown0a0a1242011-12-02 02:25:22 -0800244 sp<NativeDisplayEventReceiver> receiver =
245 reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
Jeff Brown80a1de12012-05-31 16:23:11 -0700246 receiver->dispose();
Jeff Brown0a0a1242011-12-02 02:25:22 -0800247 receiver->decStrong(gDisplayEventReceiverClassInfo.clazz); // drop reference held by the object
248}
249
Ashok Bhat27285822013-12-18 18:00:05 +0000250static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
Jeff Brown0a0a1242011-12-02 02:25:22 -0800251 sp<NativeDisplayEventReceiver> receiver =
252 reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
253 status_t status = receiver->scheduleVsync();
254 if (status) {
255 String8 message;
256 message.appendFormat("Failed to schedule next vertical sync pulse. status=%d", status);
257 jniThrowRuntimeException(env, message.string());
258 }
259}
260
261
262static JNINativeMethod gMethods[] = {
263 /* name, signature, funcPtr */
264 { "nativeInit",
Jeff Brown3b4049e2015-04-17 15:22:27 -0700265 "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;)J",
Jeff Brown0a0a1242011-12-02 02:25:22 -0800266 (void*)nativeInit },
267 { "nativeDispose",
Ashok Bhat27285822013-12-18 18:00:05 +0000268 "(J)V",
Jeff Brown0a0a1242011-12-02 02:25:22 -0800269 (void*)nativeDispose },
Ashok Bhat27285822013-12-18 18:00:05 +0000270 { "nativeScheduleVsync", "(J)V",
Jeff Brown0a0a1242011-12-02 02:25:22 -0800271 (void*)nativeScheduleVsync }
272};
273
Jeff Brown0a0a1242011-12-02 02:25:22 -0800274int register_android_view_DisplayEventReceiver(JNIEnv* env) {
Andreas Gampe987f79f2014-11-18 17:29:46 -0800275 int res = RegisterMethodsOrDie(env, "android/view/DisplayEventReceiver", gMethods,
276 NELEM(gMethods));
Jeff Brown0a0a1242011-12-02 02:25:22 -0800277
Andreas Gampe987f79f2014-11-18 17:29:46 -0800278 jclass clazz = FindClassOrDie(env, "android/view/DisplayEventReceiver");
279 gDisplayEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800280
Andreas Gampe987f79f2014-11-18 17:29:46 -0800281 gDisplayEventReceiverClassInfo.dispatchVsync = GetMethodIDOrDie(env,
282 gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JII)V");
283 gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
284 gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JIZ)V");
285
286 return res;
Jeff Brown0a0a1242011-12-02 02:25:22 -0800287}
288
289} // namespace android