1 /* 2 * Copyright (C) 2013 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 "InputEventSender" 18 19 //#define LOG_NDEBUG 0 20 21 #include <android_runtime/AndroidRuntime.h> 22 #include <input/InputTransport.h> 23 #include <log/log.h> 24 #include <nativehelper/JNIHelp.h> 25 #include <nativehelper/ScopedLocalRef.h> 26 #include <utils/Looper.h> 27 #include "android_os_MessageQueue.h" 28 #include "android_view_InputChannel.h" 29 #include "android_view_KeyEvent.h" 30 #include "android_view_MotionEvent.h" 31 #include "core_jni_helpers.h" 32 33 #include <inttypes.h> 34 #include <unordered_map> 35 36 37 using android::base::Result; 38 39 namespace android { 40 41 // Log debug messages about the dispatch cycle. 42 static constexpr bool kDebugDispatchCycle = false; 43 44 static struct { 45 jclass clazz; 46 47 jmethodID dispatchInputEventFinished; 48 jmethodID dispatchTimelineReported; 49 } gInputEventSenderClassInfo; 50 51 52 class NativeInputEventSender : public LooperCallback { 53 public: 54 NativeInputEventSender(JNIEnv* env, jobject senderWeak, 55 const std::shared_ptr<InputChannel>& inputChannel, 56 const sp<MessageQueue>& messageQueue); 57 58 status_t initialize(); 59 void dispose(); 60 status_t sendKeyEvent(uint32_t seq, const KeyEvent* event); 61 status_t sendMotionEvent(uint32_t seq, const MotionEvent* event); 62 63 protected: 64 virtual ~NativeInputEventSender(); 65 66 private: 67 jobject mSenderWeakGlobal; 68 InputPublisher mInputPublisher; 69 sp<MessageQueue> mMessageQueue; 70 std::unordered_map<uint32_t, uint32_t> mPublishedSeqMap; 71 72 uint32_t mNextPublishedSeq; 73 74 const std::string getInputChannelName() { 75 return mInputPublisher.getChannel()->getName(); 76 } 77 78 int handleEvent(int receiveFd, int events, void* data) override; 79 status_t processConsumerResponse(JNIEnv* env); 80 bool notifyConsumerResponse(JNIEnv* env, jobject sender, 81 const InputPublisher::ConsumerResponse& response, 82 bool skipCallbacks); 83 }; 84 85 NativeInputEventSender::NativeInputEventSender(JNIEnv* env, jobject senderWeak, 86 const std::shared_ptr<InputChannel>& inputChannel, 87 const sp<MessageQueue>& messageQueue) 88 : mSenderWeakGlobal(env->NewGlobalRef(senderWeak)), 89 mInputPublisher(inputChannel), 90 mMessageQueue(messageQueue), 91 mNextPublishedSeq(1) { 92 if (kDebugDispatchCycle) { 93 ALOGD("channel '%s' ~ Initializing input event sender.", getInputChannelName().c_str()); 94 } 95 } 96 97 NativeInputEventSender::~NativeInputEventSender() { 98 JNIEnv* env = AndroidRuntime::getJNIEnv(); 99 env->DeleteGlobalRef(mSenderWeakGlobal); 100 } 101 102 status_t NativeInputEventSender::initialize() { 103 int receiveFd = mInputPublisher.getChannel()->getFd(); 104 mMessageQueue->getLooper()->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, this, NULL); 105 return OK; 106 } 107 108 void NativeInputEventSender::dispose() { 109 if (kDebugDispatchCycle) { 110 ALOGD("channel '%s' ~ Disposing input event sender.", getInputChannelName().c_str()); 111 } 112 113 mMessageQueue->getLooper()->removeFd(mInputPublisher.getChannel()->getFd()); 114 } 115 116 status_t NativeInputEventSender::sendKeyEvent(uint32_t seq, const KeyEvent* event) { 117 if (kDebugDispatchCycle) { 118 ALOGD("channel '%s' ~ Sending key event, seq=%u.", getInputChannelName().c_str(), seq); 119 } 120 121 uint32_t publishedSeq = mNextPublishedSeq++; 122 status_t status = 123 mInputPublisher.publishKeyEvent(publishedSeq, event->getId(), event->getDeviceId(), 124 event->getSource(), event->getDisplayId(), 125 event->getHmac(), event->getAction(), event->getFlags(), 126 event->getKeyCode(), event->getScanCode(), 127 event->getMetaState(), event->getRepeatCount(), 128 event->getDownTime(), event->getEventTime()); 129 if (status) { 130 ALOGW("Failed to send key event on channel '%s'. status=%d", 131 getInputChannelName().c_str(), status); 132 return status; 133 } 134 mPublishedSeqMap.emplace(publishedSeq, seq); 135 return OK; 136 } 137 138 status_t NativeInputEventSender::sendMotionEvent(uint32_t seq, const MotionEvent* event) { 139 if (kDebugDispatchCycle) { 140 ALOGD("channel '%s' ~ Sending motion event, seq=%u.", getInputChannelName().c_str(), seq); 141 } 142 143 uint32_t publishedSeq; 144 for (size_t i = 0; i <= event->getHistorySize(); i++) { 145 publishedSeq = mNextPublishedSeq++; 146 status_t status = 147 mInputPublisher.publishMotionEvent(publishedSeq, event->getId(), 148 event->getDeviceId(), event->getSource(), 149 event->getDisplayId(), event->getHmac(), 150 event->getAction(), event->getActionButton(), 151 event->getFlags(), event->getEdgeFlags(), 152 event->getMetaState(), event->getButtonState(), 153 event->getClassification(), 154 event->getTransform(), event->getXPrecision(), 155 event->getYPrecision(), 156 event->getRawXCursorPosition(), 157 event->getRawYCursorPosition(), 158 event->getDisplaySize().x, 159 event->getDisplaySize().y, event->getDownTime(), 160 event->getHistoricalEventTime(i), 161 event->getPointerCount(), 162 event->getPointerProperties(), 163 event->getHistoricalRawPointerCoords(0, i)); 164 if (status) { 165 ALOGW("Failed to send motion event sample on channel '%s'. status=%d", 166 getInputChannelName().c_str(), status); 167 return status; 168 } 169 } 170 mPublishedSeqMap.emplace(publishedSeq, seq); 171 return OK; 172 } 173 174 int NativeInputEventSender::handleEvent(int receiveFd, int events, void* data) { 175 if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { 176 // This error typically occurs when the consumer has closed the input channel 177 // as part of finishing an IME session, in which case the publisher will 178 // soon be disposed as well. 179 if (kDebugDispatchCycle) { 180 ALOGD("channel '%s' ~ Consumer closed input channel or an error occurred. events=0x%x", 181 getInputChannelName().c_str(), events); 182 } 183 184 return 0; // remove the callback 185 } 186 187 if (!(events & ALOOPER_EVENT_INPUT)) { 188 ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. events=0x%x", 189 getInputChannelName().c_str(), events); 190 return 1; 191 } 192 193 JNIEnv* env = AndroidRuntime::getJNIEnv(); 194 status_t status = processConsumerResponse(env); 195 mMessageQueue->raiseAndClearException(env, "handleReceiveCallback"); 196 return status == OK || status == NO_MEMORY ? 1 : 0; 197 } 198 199 status_t NativeInputEventSender::processConsumerResponse(JNIEnv* env) { 200 if (kDebugDispatchCycle) { 201 ALOGD("channel '%s' ~ Receiving finished signals.", getInputChannelName().c_str()); 202 } 203 204 ScopedLocalRef<jobject> senderObj(env, jniGetReferent(env, mSenderWeakGlobal)); 205 if (!senderObj.get()) { 206 ALOGW("channel '%s' ~ Sender object was finalized without being disposed.", 207 getInputChannelName().c_str()); 208 return DEAD_OBJECT; 209 } 210 bool skipCallbacks = false; // stop calling Java functions after an exception occurs 211 for (;;) { 212 Result<InputPublisher::ConsumerResponse> result = mInputPublisher.receiveConsumerResponse(); 213 if (!result.ok()) { 214 const status_t status = result.error().code(); 215 if (status == WOULD_BLOCK) { 216 return OK; 217 } 218 ALOGE("channel '%s' ~ Failed to process consumer response. status=%d", 219 getInputChannelName().c_str(), status); 220 return status; 221 } 222 223 const bool notified = notifyConsumerResponse(env, senderObj.get(), *result, skipCallbacks); 224 if (!notified) { 225 skipCallbacks = true; 226 } 227 } 228 } 229 230 /** 231 * Invoke the corresponding Java function for the different variants of response. 232 * If the response is a Finished object, invoke dispatchInputEventFinished. 233 * If the response is a Timeline object, invoke dispatchTimelineReported. 234 * Set 'skipCallbacks' to 'true' if a Java exception occurred. 235 * Java function will only be called if 'skipCallbacks' is originally 'false'. 236 * 237 * Return "false" if an exception occurred while calling the Java function 238 * "true" otherwise 239 */ 240 bool NativeInputEventSender::notifyConsumerResponse( 241 JNIEnv* env, jobject sender, const InputPublisher::ConsumerResponse& response, 242 bool skipCallbacks) { 243 if (std::holds_alternative<InputPublisher::Timeline>(response)) { 244 const InputPublisher::Timeline& timeline = std::get<InputPublisher::Timeline>(response); 245 246 if (kDebugDispatchCycle) { 247 ALOGD("channel '%s' ~ Received timeline, inputEventId=%" PRId32 248 ", gpuCompletedTime=%" PRId64 ", presentTime=%" PRId64, 249 getInputChannelName().c_str(), timeline.inputEventId, 250 timeline.graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME], 251 timeline.graphicsTimeline[GraphicsTimeline::PRESENT_TIME]); 252 } 253 254 if (skipCallbacks) { 255 ALOGW("Java exception occurred. Skipping dispatchTimelineReported for " 256 "inputEventId=%" PRId32, 257 timeline.inputEventId); 258 return true; 259 } 260 261 env->CallVoidMethod(sender, gInputEventSenderClassInfo.dispatchTimelineReported, 262 timeline.inputEventId, timeline.graphicsTimeline); 263 if (env->ExceptionCheck()) { 264 ALOGE("Exception dispatching timeline, inputEventId=%" PRId32, timeline.inputEventId); 265 return false; 266 } 267 268 return true; 269 } 270 271 // Must be a Finished event 272 const InputPublisher::Finished& finished = std::get<InputPublisher::Finished>(response); 273 274 auto it = mPublishedSeqMap.find(finished.seq); 275 if (it == mPublishedSeqMap.end()) { 276 ALOGW("Received 'finished' signal for unknown seq number = %" PRIu32, finished.seq); 277 // Since this is coming from the receiver (typically app), it's possible that an app 278 // does something wrong and sends bad data. Just ignore and process other events. 279 return true; 280 } 281 const uint32_t seq = it->second; 282 mPublishedSeqMap.erase(it); 283 284 if (kDebugDispatchCycle) { 285 ALOGD("channel '%s' ~ Received finished signal, seq=%u, handled=%s, pendingEvents=%zu.", 286 getInputChannelName().c_str(), seq, finished.handled ? "true" : "false", 287 mPublishedSeqMap.size()); 288 } 289 if (skipCallbacks) { 290 return true; 291 } 292 293 env->CallVoidMethod(sender, gInputEventSenderClassInfo.dispatchInputEventFinished, 294 static_cast<jint>(seq), static_cast<jboolean>(finished.handled)); 295 if (env->ExceptionCheck()) { 296 ALOGE("Exception dispatching finished signal for seq=%" PRIu32, seq); 297 return false; 298 } 299 return true; 300 } 301 302 static jlong nativeInit(JNIEnv* env, jclass clazz, jobject senderWeak, 303 jobject inputChannelObj, jobject messageQueueObj) { 304 std::shared_ptr<InputChannel> inputChannel = 305 android_view_InputChannel_getInputChannel(env, inputChannelObj); 306 if (inputChannel == NULL) { 307 jniThrowRuntimeException(env, "InputChannel is not initialized."); 308 return 0; 309 } 310 311 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); 312 if (messageQueue == NULL) { 313 jniThrowRuntimeException(env, "MessageQueue is not initialized."); 314 return 0; 315 } 316 317 sp<NativeInputEventSender> sender = new NativeInputEventSender(env, 318 senderWeak, inputChannel, messageQueue); 319 status_t status = sender->initialize(); 320 if (status) { 321 String8 message; 322 message.appendFormat("Failed to initialize input event sender. status=%d", status); 323 jniThrowRuntimeException(env, message.string()); 324 return 0; 325 } 326 327 sender->incStrong(gInputEventSenderClassInfo.clazz); // retain a reference for the object 328 return reinterpret_cast<jlong>(sender.get()); 329 } 330 331 static void nativeDispose(JNIEnv* env, jclass clazz, jlong senderPtr) { 332 sp<NativeInputEventSender> sender = 333 reinterpret_cast<NativeInputEventSender*>(senderPtr); 334 sender->dispose(); 335 sender->decStrong(gInputEventSenderClassInfo.clazz); // drop reference held by the object 336 } 337 338 static jboolean nativeSendKeyEvent(JNIEnv* env, jclass clazz, jlong senderPtr, 339 jint seq, jobject eventObj) { 340 sp<NativeInputEventSender> sender = 341 reinterpret_cast<NativeInputEventSender*>(senderPtr); 342 KeyEvent event; 343 android_view_KeyEvent_toNative(env, eventObj, &event); 344 status_t status = sender->sendKeyEvent(seq, &event); 345 return !status; 346 } 347 348 static jboolean nativeSendMotionEvent(JNIEnv* env, jclass clazz, jlong senderPtr, 349 jint seq, jobject eventObj) { 350 sp<NativeInputEventSender> sender = 351 reinterpret_cast<NativeInputEventSender*>(senderPtr); 352 MotionEvent* event = android_view_MotionEvent_getNativePtr(env, eventObj); 353 status_t status = sender->sendMotionEvent(seq, event); 354 return !status; 355 } 356 357 358 static const JNINativeMethod gMethods[] = { 359 /* name, signature, funcPtr */ 360 { "nativeInit", 361 "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J", 362 (void*)nativeInit }, 363 { "nativeDispose", "(J)V", 364 (void*)nativeDispose }, 365 { "nativeSendKeyEvent", "(JILandroid/view/KeyEvent;)Z", 366 (void*)nativeSendKeyEvent }, 367 { "nativeSendMotionEvent", "(JILandroid/view/MotionEvent;)Z", 368 (void*)nativeSendMotionEvent }, 369 }; 370 371 int register_android_view_InputEventSender(JNIEnv* env) { 372 int res = RegisterMethodsOrDie(env, "android/view/InputEventSender", gMethods, NELEM(gMethods)); 373 374 jclass clazz = FindClassOrDie(env, "android/view/InputEventSender"); 375 gInputEventSenderClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); 376 377 gInputEventSenderClassInfo.dispatchInputEventFinished = GetMethodIDOrDie( 378 env, gInputEventSenderClassInfo.clazz, "dispatchInputEventFinished", "(IZ)V"); 379 gInputEventSenderClassInfo.dispatchTimelineReported = 380 GetMethodIDOrDie(env, gInputEventSenderClassInfo.clazz, "dispatchTimelineReported", 381 "(IJJ)V"); 382 383 return res; 384 } 385 386 } // namespace android 387