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
getInputChannelName()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
NativeInputEventSender(JNIEnv * env,jobject senderWeak,const sp<InputChannel> & inputChannel,const sp<MessageQueue> & messageQueue)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
~NativeInputEventSender()90 NativeInputEventSender::~NativeInputEventSender() {
91 JNIEnv* env = AndroidRuntime::getJNIEnv();
92 env->DeleteGlobalRef(mSenderWeakGlobal);
93 }
94
initialize()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
dispose()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
sendKeyEvent(uint32_t seq,const KeyEvent * event)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
sendMotionEvent(uint32_t seq,const MotionEvent * event)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
handleEvent(int receiveFd,int events,void * data)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
receiveFinishedSignals(JNIEnv * env)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
nativeInit(JNIEnv * env,jclass clazz,jobject senderWeak,jobject inputChannelObj,jobject messageQueueObj)233 static 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
nativeDispose(JNIEnv * env,jclass clazz,jint senderPtr)262 static 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
nativeSendKeyEvent(JNIEnv * env,jclass clazz,jint senderPtr,jint seq,jobject eventObj)269 static 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
nativeSendMotionEvent(JNIEnv * env,jclass clazz,jint senderPtr,jint seq,jobject eventObj)279 static 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
289 static 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
register_android_view_InputEventSender(JNIEnv * env)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