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