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