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