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