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