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