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