android_view_InputEventSender.cpp revision a4ca8ea0ad14c509d1ced46482e83c1b8a518982
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 <androidfw/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 40namespace android { 41 42static struct { 43 jclass clazz; 44 45 jmethodID dispatchInputEventFinished; 46} gInputEventSenderClassInfo; 47 48 49class NativeInputEventSender : public LooperCallback { 50public: 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 60protected: 61 virtual ~NativeInputEventSender(); 62 63private: 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 79NativeInputEventSender::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 90NativeInputEventSender::~NativeInputEventSender() { 91 JNIEnv* env = AndroidRuntime::getJNIEnv(); 92 env->DeleteGlobalRef(mSenderWeakGlobal); 93} 94 95status_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 101void 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 109status_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 128status_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 154int 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 178status_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 233static jint 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<jint>(sender.get()); 260} 261 262static void nativeDispose(JNIEnv* env, jclass clazz, jint 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 269static jboolean nativeSendKeyEvent(JNIEnv* env, jclass clazz, jint 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 279static jboolean nativeSendMotionEvent(JNIEnv* env, jclass clazz, jint 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 289static JNINativeMethod gMethods[] = { 290 /* name, signature, funcPtr */ 291 { "nativeInit", 292 "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)I", 293 (void*)nativeInit }, 294 { "nativeDispose", "(I)V", 295 (void*)nativeDispose }, 296 { "nativeSendKeyEvent", "(IILandroid/view/KeyEvent;)Z", 297 (void*)nativeSendKeyEvent }, 298 { "nativeSendMotionEvent", "(IILandroid/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 311int 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