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 "JNIHelp.h" 22 23 #include <android_runtime/AndroidRuntime.h> 24 #include <utils/Log.h> 25 #include <utils/Looper.h> 26 #include <utils/threads.h> 27 #include <utils/KeyedVector.h> 28 #include <input/InputTransport.h> 29 #include "android_os_MessageQueue.h" 30 #include "android_view_InputChannel.h" 31 #include "android_view_KeyEvent.h" 32 #include "android_view_MotionEvent.h" 33 34 #include <ScopedLocalRef.h> 35 36 #include "core_jni_helpers.h" 37 38 namespace android { 39 40 // Log debug messages about the dispatch cycle. 41 static const bool kDebugDispatchCycle = false; 42 43 static struct { 44 jclass clazz; 45 46 jmethodID dispatchInputEventFinished; 47 } gInputEventSenderClassInfo; 48 49 50 class NativeInputEventSender : public LooperCallback { 51 public: 52 NativeInputEventSender(JNIEnv* env, 53 jobject senderWeak, const sp<InputChannel>& inputChannel, 54 const sp<MessageQueue>& messageQueue); 55 56 status_t initialize(); 57 void dispose(); 58 status_t sendKeyEvent(uint32_t seq, const KeyEvent* event); 59 status_t sendMotionEvent(uint32_t seq, const MotionEvent* event); 60 61 protected: 62 virtual ~NativeInputEventSender(); 63 64 private: 65 jobject mSenderWeakGlobal; 66 InputPublisher mInputPublisher; 67 sp<MessageQueue> mMessageQueue; 68 KeyedVector<uint32_t, uint32_t> mPublishedSeqMap; 69 uint32_t mNextPublishedSeq; 70 71 const char* getInputChannelName() { 72 return mInputPublisher.getChannel()->getName().string(); 73 } 74 75 virtual int handleEvent(int receiveFd, int events, void* data); 76 status_t receiveFinishedSignals(JNIEnv* env); 77 }; 78 79 80 NativeInputEventSender::NativeInputEventSender(JNIEnv* env, 81 jobject senderWeak, const sp<InputChannel>& inputChannel, 82 const sp<MessageQueue>& messageQueue) : 83 mSenderWeakGlobal(env->NewGlobalRef(senderWeak)), 84 mInputPublisher(inputChannel), mMessageQueue(messageQueue), 85 mNextPublishedSeq(1) { 86 if (kDebugDispatchCycle) { 87 ALOGD("channel '%s' ~ Initializing input event sender.", getInputChannelName()); 88 } 89 } 90 91 NativeInputEventSender::~NativeInputEventSender() { 92 JNIEnv* env = AndroidRuntime::getJNIEnv(); 93 env->DeleteGlobalRef(mSenderWeakGlobal); 94 } 95 96 status_t NativeInputEventSender::initialize() { 97 int receiveFd = mInputPublisher.getChannel()->getFd(); 98 mMessageQueue->getLooper()->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, this, NULL); 99 return OK; 100 } 101 102 void NativeInputEventSender::dispose() { 103 if (kDebugDispatchCycle) { 104 ALOGD("channel '%s' ~ Disposing input event sender.", getInputChannelName()); 105 } 106 107 mMessageQueue->getLooper()->removeFd(mInputPublisher.getChannel()->getFd()); 108 } 109 110 status_t NativeInputEventSender::sendKeyEvent(uint32_t seq, const KeyEvent* event) { 111 if (kDebugDispatchCycle) { 112 ALOGD("channel '%s' ~ Sending key event, seq=%u.", getInputChannelName(), seq); 113 } 114 115 uint32_t publishedSeq = mNextPublishedSeq++; 116 status_t status = mInputPublisher.publishKeyEvent(publishedSeq, 117 event->getDeviceId(), event->getSource(), event->getAction(), event->getFlags(), 118 event->getKeyCode(), event->getScanCode(), event->getMetaState(), 119 event->getRepeatCount(), event->getDownTime(), event->getEventTime()); 120 if (status) { 121 ALOGW("Failed to send key event on channel '%s'. status=%d", 122 getInputChannelName(), status); 123 return status; 124 } 125 mPublishedSeqMap.add(publishedSeq, seq); 126 return OK; 127 } 128 129 status_t NativeInputEventSender::sendMotionEvent(uint32_t seq, const MotionEvent* event) { 130 if (kDebugDispatchCycle) { 131 ALOGD("channel '%s' ~ Sending motion event, seq=%u.", getInputChannelName(), seq); 132 } 133 134 uint32_t publishedSeq; 135 for (size_t i = 0; i <= event->getHistorySize(); i++) { 136 publishedSeq = mNextPublishedSeq++; 137 status_t status = mInputPublisher.publishMotionEvent(publishedSeq, 138 event->getDeviceId(), event->getSource(), 139 event->getAction(), event->getActionButton(), event->getFlags(), 140 event->getEdgeFlags(), event->getMetaState(), event->getButtonState(), 141 event->getXOffset(), event->getYOffset(), 142 event->getXPrecision(), event->getYPrecision(), 143 event->getDownTime(), event->getHistoricalEventTime(i), 144 event->getPointerCount(), event->getPointerProperties(), 145 event->getHistoricalRawPointerCoords(0, i)); 146 if (status) { 147 ALOGW("Failed to send motion event sample on channel '%s'. status=%d", 148 getInputChannelName(), status); 149 return status; 150 } 151 } 152 mPublishedSeqMap.add(publishedSeq, seq); 153 return OK; 154 } 155 156 int NativeInputEventSender::handleEvent(int receiveFd, int events, void* data) { 157 if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { 158 // This error typically occurs when the consumer has closed the input channel 159 // as part of finishing an IME session, in which case the publisher will 160 // soon be disposed as well. 161 if (kDebugDispatchCycle) { 162 ALOGD("channel '%s' ~ Consumer closed input channel or an error occurred. " 163 "events=0x%x", getInputChannelName(), events); 164 } 165 166 return 0; // remove the callback 167 } 168 169 if (!(events & ALOOPER_EVENT_INPUT)) { 170 ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " 171 "events=0x%x", getInputChannelName(), events); 172 return 1; 173 } 174 175 JNIEnv* env = AndroidRuntime::getJNIEnv(); 176 status_t status = receiveFinishedSignals(env); 177 mMessageQueue->raiseAndClearException(env, "handleReceiveCallback"); 178 return status == OK || status == NO_MEMORY ? 1 : 0; 179 } 180 181 status_t NativeInputEventSender::receiveFinishedSignals(JNIEnv* env) { 182 if (kDebugDispatchCycle) { 183 ALOGD("channel '%s' ~ Receiving finished signals.", getInputChannelName()); 184 } 185 186 ScopedLocalRef<jobject> senderObj(env, NULL); 187 bool skipCallbacks = false; 188 for (;;) { 189 uint32_t publishedSeq; 190 bool handled; 191 status_t status = mInputPublisher.receiveFinishedSignal(&publishedSeq, &handled); 192 if (status) { 193 if (status == WOULD_BLOCK) { 194 return OK; 195 } 196 ALOGE("channel '%s' ~ Failed to consume finished signals. status=%d", 197 getInputChannelName(), status); 198 return status; 199 } 200 201 ssize_t index = mPublishedSeqMap.indexOfKey(publishedSeq); 202 if (index >= 0) { 203 uint32_t seq = mPublishedSeqMap.valueAt(index); 204 mPublishedSeqMap.removeItemsAt(index); 205 206 if (kDebugDispatchCycle) { 207 ALOGD("channel '%s' ~ Received finished signal, seq=%u, handled=%s, " 208 "pendingEvents=%zu.", 209 getInputChannelName(), seq, handled ? "true" : "false", 210 mPublishedSeqMap.size()); 211 } 212 213 if (!skipCallbacks) { 214 if (!senderObj.get()) { 215 senderObj.reset(jniGetReferent(env, mSenderWeakGlobal)); 216 if (!senderObj.get()) { 217 ALOGW("channel '%s' ~ Sender object was finalized " 218 "without being disposed.", getInputChannelName()); 219 return DEAD_OBJECT; 220 } 221 } 222 223 env->CallVoidMethod(senderObj.get(), 224 gInputEventSenderClassInfo.dispatchInputEventFinished, 225 jint(seq), jboolean(handled)); 226 if (env->ExceptionCheck()) { 227 ALOGE("Exception dispatching finished signal."); 228 skipCallbacks = true; 229 } 230 } 231 } 232 } 233 } 234 235 236 static jlong nativeInit(JNIEnv* env, jclass clazz, jobject senderWeak, 237 jobject inputChannelObj, jobject messageQueueObj) { 238 sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, 239 inputChannelObj); 240 if (inputChannel == NULL) { 241 jniThrowRuntimeException(env, "InputChannel is not initialized."); 242 return 0; 243 } 244 245 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); 246 if (messageQueue == NULL) { 247 jniThrowRuntimeException(env, "MessageQueue is not initialized."); 248 return 0; 249 } 250 251 sp<NativeInputEventSender> sender = new NativeInputEventSender(env, 252 senderWeak, inputChannel, messageQueue); 253 status_t status = sender->initialize(); 254 if (status) { 255 String8 message; 256 message.appendFormat("Failed to initialize input event sender. status=%d", status); 257 jniThrowRuntimeException(env, message.string()); 258 return 0; 259 } 260 261 sender->incStrong(gInputEventSenderClassInfo.clazz); // retain a reference for the object 262 return reinterpret_cast<jlong>(sender.get()); 263 } 264 265 static void nativeDispose(JNIEnv* env, jclass clazz, jlong senderPtr) { 266 sp<NativeInputEventSender> sender = 267 reinterpret_cast<NativeInputEventSender*>(senderPtr); 268 sender->dispose(); 269 sender->decStrong(gInputEventSenderClassInfo.clazz); // drop reference held by the object 270 } 271 272 static jboolean nativeSendKeyEvent(JNIEnv* env, jclass clazz, jlong senderPtr, 273 jint seq, jobject eventObj) { 274 sp<NativeInputEventSender> sender = 275 reinterpret_cast<NativeInputEventSender*>(senderPtr); 276 KeyEvent event; 277 android_view_KeyEvent_toNative(env, eventObj, &event); 278 status_t status = sender->sendKeyEvent(seq, &event); 279 return !status; 280 } 281 282 static jboolean nativeSendMotionEvent(JNIEnv* env, jclass clazz, jlong senderPtr, 283 jint seq, jobject eventObj) { 284 sp<NativeInputEventSender> sender = 285 reinterpret_cast<NativeInputEventSender*>(senderPtr); 286 MotionEvent* event = android_view_MotionEvent_getNativePtr(env, eventObj); 287 status_t status = sender->sendMotionEvent(seq, event); 288 return !status; 289 } 290 291 292 static const JNINativeMethod gMethods[] = { 293 /* name, signature, funcPtr */ 294 { "nativeInit", 295 "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J", 296 (void*)nativeInit }, 297 { "nativeDispose", "(J)V", 298 (void*)nativeDispose }, 299 { "nativeSendKeyEvent", "(JILandroid/view/KeyEvent;)Z", 300 (void*)nativeSendKeyEvent }, 301 { "nativeSendMotionEvent", "(JILandroid/view/MotionEvent;)Z", 302 (void*)nativeSendMotionEvent }, 303 }; 304 305 int register_android_view_InputEventSender(JNIEnv* env) { 306 int res = RegisterMethodsOrDie(env, "android/view/InputEventSender", gMethods, NELEM(gMethods)); 307 308 jclass clazz = FindClassOrDie(env, "android/view/InputEventSender"); 309 gInputEventSenderClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); 310 311 gInputEventSenderClassInfo.dispatchInputEventFinished = GetMethodIDOrDie( 312 env, gInputEventSenderClassInfo.clazz, "dispatchInputEventFinished", "(IZ)V"); 313 314 return res; 315 } 316 317 } // namespace android 318