Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2010 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 "MessageQueue-JNI"
     18 
     19 #include <nativehelper/JNIHelp.h>
     20 #include <android_runtime/AndroidRuntime.h>
     21 
     22 #include <utils/Looper.h>
     23 #include <utils/Log.h>
     24 #include "android_os_MessageQueue.h"
     25 
     26 #include "core_jni_helpers.h"
     27 
     28 namespace android {
     29 
     30 static struct {
     31     jfieldID mPtr;   // native object attached to the DVM MessageQueue
     32     jmethodID dispatchEvents;
     33 } gMessageQueueClassInfo;
     34 
     35 // Must be kept in sync with the constants in Looper.FileDescriptorCallback
     36 static const int CALLBACK_EVENT_INPUT = 1 << 0;
     37 static const int CALLBACK_EVENT_OUTPUT = 1 << 1;
     38 static const int CALLBACK_EVENT_ERROR = 1 << 2;
     39 
     40 
     41 class NativeMessageQueue : public MessageQueue, public LooperCallback {
     42 public:
     43     NativeMessageQueue();
     44     virtual ~NativeMessageQueue();
     45 
     46     virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj);
     47 
     48     void pollOnce(JNIEnv* env, jobject obj, int timeoutMillis);
     49     void wake();
     50     void setFileDescriptorEvents(int fd, int events);
     51 
     52     virtual int handleEvent(int fd, int events, void* data);
     53 
     54 private:
     55     JNIEnv* mPollEnv;
     56     jobject mPollObj;
     57     jthrowable mExceptionObj;
     58 };
     59 
     60 
     61 MessageQueue::MessageQueue() {
     62 }
     63 
     64 MessageQueue::~MessageQueue() {
     65 }
     66 
     67 bool MessageQueue::raiseAndClearException(JNIEnv* env, const char* msg) {
     68     if (env->ExceptionCheck()) {
     69         jthrowable exceptionObj = env->ExceptionOccurred();
     70         env->ExceptionClear();
     71         raiseException(env, msg, exceptionObj);
     72         env->DeleteLocalRef(exceptionObj);
     73         return true;
     74     }
     75     return false;
     76 }
     77 
     78 NativeMessageQueue::NativeMessageQueue() :
     79         mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
     80     mLooper = Looper::getForThread();
     81     if (mLooper == NULL) {
     82         mLooper = new Looper(false);
     83         Looper::setForThread(mLooper);
     84     }
     85 }
     86 
     87 NativeMessageQueue::~NativeMessageQueue() {
     88 }
     89 
     90 void NativeMessageQueue::raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj) {
     91     if (exceptionObj) {
     92         if (mPollEnv == env) {
     93             if (mExceptionObj) {
     94                 env->DeleteLocalRef(mExceptionObj);
     95             }
     96             mExceptionObj = jthrowable(env->NewLocalRef(exceptionObj));
     97             ALOGE("Exception in MessageQueue callback: %s", msg);
     98             jniLogException(env, ANDROID_LOG_ERROR, LOG_TAG, exceptionObj);
     99         } else {
    100             ALOGE("Exception: %s", msg);
    101             jniLogException(env, ANDROID_LOG_ERROR, LOG_TAG, exceptionObj);
    102             LOG_ALWAYS_FATAL("raiseException() was called when not in a callback, exiting.");
    103         }
    104     }
    105 }
    106 
    107 void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
    108     mPollEnv = env;
    109     mPollObj = pollObj;
    110     mLooper->pollOnce(timeoutMillis);
    111     mPollObj = NULL;
    112     mPollEnv = NULL;
    113 
    114     if (mExceptionObj) {
    115         env->Throw(mExceptionObj);
    116         env->DeleteLocalRef(mExceptionObj);
    117         mExceptionObj = NULL;
    118     }
    119 }
    120 
    121 void NativeMessageQueue::wake() {
    122     mLooper->wake();
    123 }
    124 
    125 void NativeMessageQueue::setFileDescriptorEvents(int fd, int events) {
    126     if (events) {
    127         int looperEvents = 0;
    128         if (events & CALLBACK_EVENT_INPUT) {
    129             looperEvents |= Looper::EVENT_INPUT;
    130         }
    131         if (events & CALLBACK_EVENT_OUTPUT) {
    132             looperEvents |= Looper::EVENT_OUTPUT;
    133         }
    134         mLooper->addFd(fd, Looper::POLL_CALLBACK, looperEvents, this,
    135                 reinterpret_cast<void*>(events));
    136     } else {
    137         mLooper->removeFd(fd);
    138     }
    139 }
    140 
    141 int NativeMessageQueue::handleEvent(int fd, int looperEvents, void* data) {
    142     int events = 0;
    143     if (looperEvents & Looper::EVENT_INPUT) {
    144         events |= CALLBACK_EVENT_INPUT;
    145     }
    146     if (looperEvents & Looper::EVENT_OUTPUT) {
    147         events |= CALLBACK_EVENT_OUTPUT;
    148     }
    149     if (looperEvents & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP | Looper::EVENT_INVALID)) {
    150         events |= CALLBACK_EVENT_ERROR;
    151     }
    152     int oldWatchedEvents = reinterpret_cast<intptr_t>(data);
    153     int newWatchedEvents = mPollEnv->CallIntMethod(mPollObj,
    154             gMessageQueueClassInfo.dispatchEvents, fd, events);
    155     if (!newWatchedEvents) {
    156         return 0; // unregister the fd
    157     }
    158     if (newWatchedEvents != oldWatchedEvents) {
    159         setFileDescriptorEvents(fd, newWatchedEvents);
    160     }
    161     return 1;
    162 }
    163 
    164 
    165 // ----------------------------------------------------------------------------
    166 
    167 sp<MessageQueue> android_os_MessageQueue_getMessageQueue(JNIEnv* env, jobject messageQueueObj) {
    168     jlong ptr = env->GetLongField(messageQueueObj, gMessageQueueClassInfo.mPtr);
    169     return reinterpret_cast<NativeMessageQueue*>(ptr);
    170 }
    171 
    172 static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
    173     NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
    174     if (!nativeMessageQueue) {
    175         jniThrowRuntimeException(env, "Unable to allocate native queue");
    176         return 0;
    177     }
    178 
    179     nativeMessageQueue->incStrong(env);
    180     return reinterpret_cast<jlong>(nativeMessageQueue);
    181 }
    182 
    183 static void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
    184     NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    185     nativeMessageQueue->decStrong(env);
    186 }
    187 
    188 static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
    189         jlong ptr, jint timeoutMillis) {
    190     NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    191     nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
    192 }
    193 
    194 static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
    195     NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    196     nativeMessageQueue->wake();
    197 }
    198 
    199 static jboolean android_os_MessageQueue_nativeIsPolling(JNIEnv* env, jclass clazz, jlong ptr) {
    200     NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    201     return nativeMessageQueue->getLooper()->isPolling();
    202 }
    203 
    204 static void android_os_MessageQueue_nativeSetFileDescriptorEvents(JNIEnv* env, jclass clazz,
    205         jlong ptr, jint fd, jint events) {
    206     NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    207     nativeMessageQueue->setFileDescriptorEvents(fd, events);
    208 }
    209 
    210 // ----------------------------------------------------------------------------
    211 
    212 static const JNINativeMethod gMessageQueueMethods[] = {
    213     /* name, signature, funcPtr */
    214     { "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit },
    215     { "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy },
    216     { "nativePollOnce", "(JI)V", (void*)android_os_MessageQueue_nativePollOnce },
    217     { "nativeWake", "(J)V", (void*)android_os_MessageQueue_nativeWake },
    218     { "nativeIsPolling", "(J)Z", (void*)android_os_MessageQueue_nativeIsPolling },
    219     { "nativeSetFileDescriptorEvents", "(JII)V",
    220             (void*)android_os_MessageQueue_nativeSetFileDescriptorEvents },
    221 };
    222 
    223 int register_android_os_MessageQueue(JNIEnv* env) {
    224     int res = RegisterMethodsOrDie(env, "android/os/MessageQueue", gMessageQueueMethods,
    225                                    NELEM(gMessageQueueMethods));
    226 
    227     jclass clazz = FindClassOrDie(env, "android/os/MessageQueue");
    228     gMessageQueueClassInfo.mPtr = GetFieldIDOrDie(env, clazz, "mPtr", "J");
    229     gMessageQueueClassInfo.dispatchEvents = GetMethodIDOrDie(env, clazz,
    230             "dispatchEvents", "(II)I");
    231 
    232     return res;
    233 }
    234 
    235 } // namespace android
    236