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