Home | History | Annotate | Download | only in jni
      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 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 
    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 
    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 
    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 
    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