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