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 "InputEventReceiver"
18
19 //#define LOG_NDEBUG 0
20
21 #include <inttypes.h>
22
23 #include <nativehelper/JNIHelp.h>
24
25 #include <android-base/stringprintf.h>
26 #include <android_runtime/AndroidRuntime.h>
27 #include <input/InputTransport.h>
28 #include <log/log.h>
29 #include <utils/Looper.h>
30 #include <variant>
31 #include <vector>
32 #include "android_os_MessageQueue.h"
33 #include "android_view_InputChannel.h"
34 #include "android_view_KeyEvent.h"
35 #include "android_view_MotionEvent.h"
36
37 #include <nativehelper/ScopedLocalRef.h>
38
39 #include "core_jni_helpers.h"
40
41 namespace android {
42
43 static const bool kDebugDispatchCycle = false;
44
toString(bool value)45 static const char* toString(bool value) {
46 return value ? "true" : "false";
47 }
48
49 static struct {
50 jclass clazz;
51
52 jmethodID dispatchInputEvent;
53 jmethodID onFocusEvent;
54 jmethodID onPointerCaptureEvent;
55 jmethodID onDragEvent;
56 jmethodID onBatchedInputEventPending;
57 jmethodID onTouchModeChanged;
58 } gInputEventReceiverClassInfo;
59
60 // Add prefix to the beginning of each line in 'str'
addPrefix(std::string str,std::string_view prefix)61 static std::string addPrefix(std::string str, std::string_view prefix) {
62 str.insert(0, prefix); // insert at the beginning of the first line
63 const size_t prefixLength = prefix.length();
64 size_t pos = prefixLength; // just inserted prefix. start at the end of it
65 while (true) { // process all newline characters in 'str'
66 pos = str.find('\n', pos);
67 if (pos == std::string::npos) {
68 break;
69 }
70 str.insert(pos + 1, prefix); // insert prefix just after the '\n' character
71 pos += prefixLength + 1; // advance the position past the newly inserted prefix
72 }
73 return str;
74 }
75
76 class NativeInputEventReceiver : public LooperCallback {
77 public:
78 NativeInputEventReceiver(JNIEnv* env, jobject receiverWeak,
79 const std::shared_ptr<InputChannel>& inputChannel,
80 const sp<MessageQueue>& messageQueue);
81
82 status_t initialize();
83 void dispose();
84 status_t finishInputEvent(uint32_t seq, bool handled);
85 status_t reportTimeline(int32_t inputEventId, nsecs_t gpuCompletedTime, nsecs_t presentTime);
86 status_t consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime,
87 bool* outConsumedBatch);
88 std::string dump(const char* prefix);
89
90 protected:
91 virtual ~NativeInputEventReceiver();
92
93 private:
94 struct Finish {
95 uint32_t seq;
96 bool handled;
97 };
98
99 struct Timeline {
100 int32_t inputEventId;
101 std::array<nsecs_t, GraphicsTimeline::SIZE> timeline;
102 };
103 typedef std::variant<Finish, Timeline> OutboundEvent;
104
105 jobject mReceiverWeakGlobal;
106 InputConsumer mInputConsumer;
107 sp<MessageQueue> mMessageQueue;
108 PreallocatedInputEventFactory mInputEventFactory;
109 bool mBatchedInputEventPending;
110 int mFdEvents;
111 std::vector<OutboundEvent> mOutboundQueue;
112
113 void setFdEvents(int events);
114
getInputChannelName()115 const std::string getInputChannelName() {
116 return mInputConsumer.getChannel()->getName();
117 }
118
119 status_t processOutboundEvents();
120 // From 'LooperCallback'
121 int handleEvent(int receiveFd, int events, void* data) override;
122 };
123
NativeInputEventReceiver(JNIEnv * env,jobject receiverWeak,const std::shared_ptr<InputChannel> & inputChannel,const sp<MessageQueue> & messageQueue)124 NativeInputEventReceiver::NativeInputEventReceiver(
125 JNIEnv* env, jobject receiverWeak, const std::shared_ptr<InputChannel>& inputChannel,
126 const sp<MessageQueue>& messageQueue)
127 : mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
128 mInputConsumer(inputChannel),
129 mMessageQueue(messageQueue),
130 mBatchedInputEventPending(false),
131 mFdEvents(0) {
132 if (kDebugDispatchCycle) {
133 ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName().c_str());
134 }
135 }
136
~NativeInputEventReceiver()137 NativeInputEventReceiver::~NativeInputEventReceiver() {
138 JNIEnv* env = AndroidRuntime::getJNIEnv();
139 env->DeleteGlobalRef(mReceiverWeakGlobal);
140 }
141
initialize()142 status_t NativeInputEventReceiver::initialize() {
143 setFdEvents(ALOOPER_EVENT_INPUT);
144 return OK;
145 }
146
dispose()147 void NativeInputEventReceiver::dispose() {
148 if (kDebugDispatchCycle) {
149 ALOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName().c_str());
150 }
151
152 setFdEvents(0);
153 }
154
finishInputEvent(uint32_t seq,bool handled)155 status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
156 if (kDebugDispatchCycle) {
157 ALOGD("channel '%s' ~ Finished input event.", getInputChannelName().c_str());
158 }
159
160 Finish finish{
161 .seq = seq,
162 .handled = handled,
163 };
164 mOutboundQueue.push_back(finish);
165 return processOutboundEvents();
166 }
167
reportTimeline(int32_t inputEventId,nsecs_t gpuCompletedTime,nsecs_t presentTime)168 status_t NativeInputEventReceiver::reportTimeline(int32_t inputEventId, nsecs_t gpuCompletedTime,
169 nsecs_t presentTime) {
170 if (kDebugDispatchCycle) {
171 ALOGD("channel '%s' ~ %s", getInputChannelName().c_str(), __func__);
172 }
173 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
174 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = gpuCompletedTime;
175 graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = presentTime;
176 Timeline timeline{
177 .inputEventId = inputEventId,
178 .timeline = graphicsTimeline,
179 };
180 mOutboundQueue.push_back(timeline);
181 return processOutboundEvents();
182 }
183
setFdEvents(int events)184 void NativeInputEventReceiver::setFdEvents(int events) {
185 if (mFdEvents != events) {
186 mFdEvents = events;
187 int fd = mInputConsumer.getChannel()->getFd();
188 if (events) {
189 mMessageQueue->getLooper()->addFd(fd, 0, events, this, nullptr);
190 } else {
191 mMessageQueue->getLooper()->removeFd(fd);
192 }
193 }
194 }
195
196 /**
197 * Receiver's primary role is to receive input events, but it has an additional duty of sending
198 * 'ack' for events (using the call 'finishInputEvent') and reporting input event timeline.
199 *
200 * If we are looking at the communication between InputPublisher and InputConsumer, we can say that
201 * from the InputConsumer's perspective, InputMessage's that are sent from publisher to consumer are
202 * called 'inbound / incoming' events, and the InputMessage's sent from InputConsumer to
203 * InputPublisher are 'outbound / outgoing' events.
204 *
205 * NativeInputEventReceiver owns (and acts like) an InputConsumer. So the finish events are outbound
206 * from InputEventReceiver (and will be sent to the InputPublisher). Likewise, timeline events are
207 * outbound events.
208 *
209 * In this function, send as many events from 'mOutboundQueue' as possible across the socket to the
210 * InputPublisher. If no events are remaining, let the looper know so that it doesn't wake up
211 * unnecessarily.
212 */
processOutboundEvents()213 status_t NativeInputEventReceiver::processOutboundEvents() {
214 while (!mOutboundQueue.empty()) {
215 OutboundEvent& outbound = *mOutboundQueue.begin();
216 status_t status;
217
218 if (std::holds_alternative<Finish>(outbound)) {
219 const Finish& finish = std::get<Finish>(outbound);
220 status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);
221 } else if (std::holds_alternative<Timeline>(outbound)) {
222 const Timeline& timeline = std::get<Timeline>(outbound);
223 status = mInputConsumer.sendTimeline(timeline.inputEventId, timeline.timeline);
224 } else {
225 LOG_ALWAYS_FATAL("Unexpected event type in std::variant");
226 status = BAD_VALUE;
227 }
228 if (status == OK) {
229 // Successful send. Erase the entry and keep trying to send more
230 mOutboundQueue.erase(mOutboundQueue.begin());
231 continue;
232 }
233
234 // Publisher is busy, try again later. Keep this entry (do not erase)
235 if (status == WOULD_BLOCK) {
236 if (kDebugDispatchCycle) {
237 ALOGD("channel '%s' ~ Remaining outbound events: %zu.",
238 getInputChannelName().c_str(), mOutboundQueue.size());
239 }
240 setFdEvents(ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT);
241 return WOULD_BLOCK; // try again later
242 }
243
244 // Some other error. Give up
245 ALOGW("Failed to send outbound event on channel '%s'. status=%s(%d)",
246 getInputChannelName().c_str(), statusToString(status).c_str(), status);
247 if (status != DEAD_OBJECT) {
248 JNIEnv* env = AndroidRuntime::getJNIEnv();
249 std::string message =
250 android::base::StringPrintf("Failed to send outbound event. status=%s(%d)",
251 statusToString(status).c_str(), status);
252 jniThrowRuntimeException(env, message.c_str());
253 mMessageQueue->raiseAndClearException(env, "finishInputEvent");
254 }
255 return status;
256 }
257
258 // The queue is now empty. Tell looper there's no more output to expect.
259 setFdEvents(ALOOPER_EVENT_INPUT);
260 return OK;
261 }
262
handleEvent(int receiveFd,int events,void * data)263 int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
264 // Allowed return values of this function as documented in LooperCallback::handleEvent
265 constexpr int REMOVE_CALLBACK = 0;
266 constexpr int KEEP_CALLBACK = 1;
267
268 if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
269 // This error typically occurs when the publisher has closed the input channel
270 // as part of removing a window or finishing an IME session, in which case
271 // the consumer will soon be disposed as well.
272 if (kDebugDispatchCycle) {
273 ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred. events=0x%x",
274 getInputChannelName().c_str(), events);
275 }
276 return REMOVE_CALLBACK;
277 }
278
279 if (events & ALOOPER_EVENT_INPUT) {
280 JNIEnv* env = AndroidRuntime::getJNIEnv();
281 status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr);
282 mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
283 return status == OK || status == NO_MEMORY ? KEEP_CALLBACK : REMOVE_CALLBACK;
284 }
285
286 if (events & ALOOPER_EVENT_OUTPUT) {
287 const status_t status = processOutboundEvents();
288 if (status == OK || status == WOULD_BLOCK) {
289 return KEEP_CALLBACK;
290 } else {
291 return REMOVE_CALLBACK;
292 }
293 }
294
295 ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. events=0x%x",
296 getInputChannelName().c_str(), events);
297 return KEEP_CALLBACK;
298 }
299
consumeEvents(JNIEnv * env,bool consumeBatches,nsecs_t frameTime,bool * outConsumedBatch)300 status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
301 bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
302 if (kDebugDispatchCycle) {
303 ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s, frameTime=%" PRId64,
304 getInputChannelName().c_str(), toString(consumeBatches), frameTime);
305 }
306
307 if (consumeBatches) {
308 mBatchedInputEventPending = false;
309 }
310 if (outConsumedBatch) {
311 *outConsumedBatch = false;
312 }
313
314 ScopedLocalRef<jobject> receiverObj(env, nullptr);
315 bool skipCallbacks = false;
316 for (;;) {
317 uint32_t seq;
318 InputEvent* inputEvent;
319
320 status_t status = mInputConsumer.consume(&mInputEventFactory,
321 consumeBatches, frameTime, &seq, &inputEvent);
322 if (status != OK && status != WOULD_BLOCK) {
323 ALOGE("channel '%s' ~ Failed to consume input event. status=%s(%d)",
324 getInputChannelName().c_str(), statusToString(status).c_str(), status);
325 return status;
326 }
327
328 if (status == WOULD_BLOCK) {
329 if (!skipCallbacks && !mBatchedInputEventPending && mInputConsumer.hasPendingBatch()) {
330 // There is a pending batch. Come back later.
331 if (!receiverObj.get()) {
332 receiverObj.reset(GetReferent(env, mReceiverWeakGlobal));
333 if (!receiverObj.get()) {
334 ALOGW("channel '%s' ~ Receiver object was finalized "
335 "without being disposed.",
336 getInputChannelName().c_str());
337 return DEAD_OBJECT;
338 }
339 }
340
341 mBatchedInputEventPending = true;
342 if (kDebugDispatchCycle) {
343 ALOGD("channel '%s' ~ Dispatching batched input event pending notification.",
344 getInputChannelName().c_str());
345 }
346
347 env->CallVoidMethod(receiverObj.get(),
348 gInputEventReceiverClassInfo.onBatchedInputEventPending,
349 mInputConsumer.getPendingBatchSource());
350 if (env->ExceptionCheck()) {
351 ALOGE("Exception dispatching batched input events.");
352 mBatchedInputEventPending = false; // try again later
353 }
354 }
355 return OK;
356 }
357 assert(inputEvent);
358
359 if (!skipCallbacks) {
360 if (!receiverObj.get()) {
361 receiverObj.reset(GetReferent(env, mReceiverWeakGlobal));
362 if (!receiverObj.get()) {
363 ALOGW("channel '%s' ~ Receiver object was finalized "
364 "without being disposed.", getInputChannelName().c_str());
365 return DEAD_OBJECT;
366 }
367 }
368
369 jobject inputEventObj;
370 switch (inputEvent->getType()) {
371 case InputEventType::KEY:
372 if (kDebugDispatchCycle) {
373 ALOGD("channel '%s' ~ Received key event.", getInputChannelName().c_str());
374 }
375 inputEventObj =
376 android_view_KeyEvent_fromNative(env,
377 static_cast<KeyEvent&>(*inputEvent));
378 break;
379
380 case InputEventType::MOTION: {
381 if (kDebugDispatchCycle) {
382 ALOGD("channel '%s' ~ Received motion event.",
383 getInputChannelName().c_str());
384 }
385 const MotionEvent& motionEvent = static_cast<const MotionEvent&>(*inputEvent);
386 if ((motionEvent.getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) {
387 *outConsumedBatch = true;
388 }
389 inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent);
390 break;
391 }
392 case InputEventType::FOCUS: {
393 FocusEvent* focusEvent = static_cast<FocusEvent*>(inputEvent);
394 if (kDebugDispatchCycle) {
395 ALOGD("channel '%s' ~ Received focus event: hasFocus=%s.",
396 getInputChannelName().c_str(), toString(focusEvent->getHasFocus()));
397 }
398 env->CallVoidMethod(receiverObj.get(),
399 gInputEventReceiverClassInfo.onFocusEvent,
400 jboolean(focusEvent->getHasFocus()));
401 finishInputEvent(seq, true /* handled */);
402 continue;
403 }
404 case InputEventType::CAPTURE: {
405 const CaptureEvent* captureEvent = static_cast<CaptureEvent*>(inputEvent);
406 if (kDebugDispatchCycle) {
407 ALOGD("channel '%s' ~ Received capture event: pointerCaptureEnabled=%s",
408 getInputChannelName().c_str(),
409 toString(captureEvent->getPointerCaptureEnabled()));
410 }
411 env->CallVoidMethod(receiverObj.get(),
412 gInputEventReceiverClassInfo.onPointerCaptureEvent,
413 jboolean(captureEvent->getPointerCaptureEnabled()));
414 finishInputEvent(seq, true /* handled */);
415 continue;
416 }
417 case InputEventType::DRAG: {
418 const DragEvent* dragEvent = static_cast<DragEvent*>(inputEvent);
419 if (kDebugDispatchCycle) {
420 ALOGD("channel '%s' ~ Received drag event: isExiting=%s",
421 getInputChannelName().c_str(), toString(dragEvent->isExiting()));
422 }
423 env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.onDragEvent,
424 jboolean(dragEvent->isExiting()), dragEvent->getX(),
425 dragEvent->getY());
426 finishInputEvent(seq, true /* handled */);
427 continue;
428 }
429 case InputEventType::TOUCH_MODE: {
430 const TouchModeEvent* touchModeEvent = static_cast<TouchModeEvent*>(inputEvent);
431 if (kDebugDispatchCycle) {
432 ALOGD("channel '%s' ~ Received touch mode event: isInTouchMode=%s",
433 getInputChannelName().c_str(),
434 toString(touchModeEvent->isInTouchMode()));
435 }
436 env->CallVoidMethod(receiverObj.get(),
437 gInputEventReceiverClassInfo.onTouchModeChanged,
438 jboolean(touchModeEvent->isInTouchMode()));
439 finishInputEvent(seq, true /* handled */);
440 continue;
441 }
442
443 default:
444 assert(false); // InputConsumer should prevent this from ever happening
445 inputEventObj = nullptr;
446 }
447
448 if (inputEventObj) {
449 if (kDebugDispatchCycle) {
450 ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName().c_str());
451 }
452 env->CallVoidMethod(receiverObj.get(),
453 gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
454 if (env->ExceptionCheck()) {
455 ALOGE("Exception dispatching input event.");
456 skipCallbacks = true;
457 }
458 env->DeleteLocalRef(inputEventObj);
459 } else {
460 ALOGW("channel '%s' ~ Failed to obtain event object.",
461 getInputChannelName().c_str());
462 skipCallbacks = true;
463 }
464 }
465 }
466 }
467
dump(const char * prefix)468 std::string NativeInputEventReceiver::dump(const char* prefix) {
469 std::string out;
470 std::string consumerDump = addPrefix(mInputConsumer.dump(), " ");
471 out = out + "mInputConsumer:\n" + consumerDump + "\n";
472
473 out += android::base::StringPrintf("mBatchedInputEventPending: %s\n",
474 toString(mBatchedInputEventPending));
475 out = out + "mOutboundQueue:\n";
476 for (const OutboundEvent& outbound : mOutboundQueue) {
477 if (std::holds_alternative<Finish>(outbound)) {
478 const Finish& finish = std::get<Finish>(outbound);
479 out += android::base::StringPrintf(" Finish: seq=%" PRIu32 " handled=%s\n", finish.seq,
480 toString(finish.handled));
481 } else if (std::holds_alternative<Timeline>(outbound)) {
482 const Timeline& timeline = std::get<Timeline>(outbound);
483 out += android::base::
484 StringPrintf(" Timeline: inputEventId=%" PRId32 " gpuCompletedTime=%" PRId64
485 ", presentTime=%" PRId64 "\n",
486 timeline.inputEventId,
487 timeline.timeline[GraphicsTimeline::GPU_COMPLETED_TIME],
488 timeline.timeline[GraphicsTimeline::PRESENT_TIME]);
489 }
490 }
491 if (mOutboundQueue.empty()) {
492 out = out + " <empty>\n";
493 }
494 return addPrefix(out, prefix);
495 }
496
nativeInit(JNIEnv * env,jclass clazz,jobject receiverWeak,jobject inputChannelObj,jobject messageQueueObj)497 static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
498 jobject inputChannelObj, jobject messageQueueObj) {
499 std::shared_ptr<InputChannel> inputChannel =
500 android_view_InputChannel_getInputChannel(env, inputChannelObj);
501 if (inputChannel == nullptr) {
502 jniThrowRuntimeException(env, "InputChannel is not initialized.");
503 return 0;
504 }
505
506 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
507 if (messageQueue == nullptr) {
508 jniThrowRuntimeException(env, "MessageQueue is not initialized.");
509 return 0;
510 }
511
512 sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
513 receiverWeak, inputChannel, messageQueue);
514 status_t status = receiver->initialize();
515 if (status) {
516 std::string message = android::base::
517 StringPrintf("Failed to initialize input event receiver. status=%s(%d)",
518 statusToString(status).c_str(), status);
519 jniThrowRuntimeException(env, message.c_str());
520 return 0;
521 }
522
523 receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
524 return reinterpret_cast<jlong>(receiver.get());
525 }
526
nativeDispose(JNIEnv * env,jclass clazz,jlong receiverPtr)527 static void nativeDispose(JNIEnv* env, jclass clazz, jlong receiverPtr) {
528 sp<NativeInputEventReceiver> receiver =
529 reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
530 receiver->dispose();
531 receiver->decStrong(gInputEventReceiverClassInfo.clazz); // drop reference held by the object
532 }
533
nativeFinishInputEvent(JNIEnv * env,jclass clazz,jlong receiverPtr,jint seq,jboolean handled)534 static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jlong receiverPtr,
535 jint seq, jboolean handled) {
536 sp<NativeInputEventReceiver> receiver =
537 reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
538 status_t status = receiver->finishInputEvent(seq, handled);
539 if (status == OK || status == WOULD_BLOCK) {
540 return; // normal operation
541 }
542 if (status != DEAD_OBJECT) {
543 std::string message =
544 android::base::StringPrintf("Failed to finish input event. status=%s(%d)",
545 statusToString(status).c_str(), status);
546 jniThrowRuntimeException(env, message.c_str());
547 }
548 }
549
nativeReportTimeline(JNIEnv * env,jclass clazz,jlong receiverPtr,jint inputEventId,jlong gpuCompletedTime,jlong presentTime)550 static void nativeReportTimeline(JNIEnv* env, jclass clazz, jlong receiverPtr, jint inputEventId,
551 jlong gpuCompletedTime, jlong presentTime) {
552 if (IdGenerator::getSource(inputEventId) != IdGenerator::Source::INPUT_READER) {
553 // skip this event, it did not originate from hardware
554 return;
555 }
556 sp<NativeInputEventReceiver> receiver =
557 reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
558 status_t status = receiver->reportTimeline(inputEventId, gpuCompletedTime, presentTime);
559 if (status == OK || status == WOULD_BLOCK) {
560 return; // normal operation
561 }
562 if (status != DEAD_OBJECT) {
563 std::string message = android::base::StringPrintf("Failed to send timeline. status=%s(%d)",
564 strerror(-status), status);
565 jniThrowRuntimeException(env, message.c_str());
566 }
567 }
568
nativeConsumeBatchedInputEvents(JNIEnv * env,jclass clazz,jlong receiverPtr,jlong frameTimeNanos)569 static jboolean nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jlong receiverPtr,
570 jlong frameTimeNanos) {
571 sp<NativeInputEventReceiver> receiver =
572 reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
573 bool consumedBatch;
574 status_t status = receiver->consumeEvents(env, true /*consumeBatches*/, frameTimeNanos,
575 &consumedBatch);
576 if (status && status != DEAD_OBJECT && !env->ExceptionCheck()) {
577 std::string message =
578 android::base::StringPrintf("Failed to consume batched input event. status=%s(%d)",
579 statusToString(status).c_str(), status);
580 jniThrowRuntimeException(env, message.c_str());
581 return JNI_FALSE;
582 }
583 return consumedBatch ? JNI_TRUE : JNI_FALSE;
584 }
585
nativeDump(JNIEnv * env,jclass clazz,jlong receiverPtr,jstring prefix)586 static jstring nativeDump(JNIEnv* env, jclass clazz, jlong receiverPtr, jstring prefix) {
587 sp<NativeInputEventReceiver> receiver =
588 reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
589 ScopedUtfChars prefixChars(env, prefix);
590 return env->NewStringUTF(receiver->dump(prefixChars.c_str()).c_str());
591 }
592
593 static const JNINativeMethod gMethods[] = {
594 /* name, signature, funcPtr */
595 {"nativeInit",
596 "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J",
597 (void*)nativeInit},
598 {"nativeDispose", "(J)V", (void*)nativeDispose},
599 {"nativeFinishInputEvent", "(JIZ)V", (void*)nativeFinishInputEvent},
600 {"nativeReportTimeline", "(JIJJ)V", (void*)nativeReportTimeline},
601 {"nativeConsumeBatchedInputEvents", "(JJ)Z", (void*)nativeConsumeBatchedInputEvents},
602 {"nativeDump", "(JLjava/lang/String;)Ljava/lang/String;", (void*)nativeDump},
603 };
604
register_android_view_InputEventReceiver(JNIEnv * env)605 int register_android_view_InputEventReceiver(JNIEnv* env) {
606 int res = RegisterMethodsOrDie(env, "android/view/InputEventReceiver",
607 gMethods, NELEM(gMethods));
608
609 jclass clazz = FindClassOrDie(env, "android/view/InputEventReceiver");
610 gInputEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
611
612 gInputEventReceiverClassInfo.dispatchInputEvent = GetMethodIDOrDie(env,
613 gInputEventReceiverClassInfo.clazz,
614 "dispatchInputEvent", "(ILandroid/view/InputEvent;)V");
615 gInputEventReceiverClassInfo.onFocusEvent =
616 GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onFocusEvent", "(Z)V");
617 gInputEventReceiverClassInfo.onPointerCaptureEvent =
618 GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onPointerCaptureEvent",
619 "(Z)V");
620 gInputEventReceiverClassInfo.onDragEvent =
621 GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onDragEvent", "(ZFF)V");
622 gInputEventReceiverClassInfo.onTouchModeChanged =
623 GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onTouchModeChanged", "(Z)V");
624 gInputEventReceiverClassInfo.onBatchedInputEventPending =
625 GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onBatchedInputEventPending",
626 "(I)V");
627
628 return res;
629 }
630
631 } // namespace android
632