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 "JNIHelp.h"
     20 
     21 #include <utils/Looper.h>
     22 #include <utils/Log.h>
     23 #include "android_os_MessageQueue.h"
     24 
     25 namespace android {
     26 
     27 // ----------------------------------------------------------------------------
     28 
     29 static struct {
     30     jclass clazz;
     31 
     32     jfieldID mPtr;   // native object attached to the DVM MessageQueue
     33 } gMessageQueueClassInfo;
     34 
     35 // ----------------------------------------------------------------------------
     36 
     37 class NativeMessageQueue {
     38 public:
     39     NativeMessageQueue();
     40     ~NativeMessageQueue();
     41 
     42     inline sp<Looper> getLooper() { return mLooper; }
     43 
     44     void pollOnce(int timeoutMillis);
     45     void wake();
     46 
     47 private:
     48     sp<Looper> mLooper;
     49 };
     50 
     51 // ----------------------------------------------------------------------------
     52 
     53 NativeMessageQueue::NativeMessageQueue() {
     54     mLooper = Looper::getForThread();
     55     if (mLooper == NULL) {
     56         mLooper = new Looper(false);
     57         Looper::setForThread(mLooper);
     58     }
     59 }
     60 
     61 NativeMessageQueue::~NativeMessageQueue() {
     62 }
     63 
     64 void NativeMessageQueue::pollOnce(int timeoutMillis) {
     65     mLooper->pollOnce(timeoutMillis);
     66 }
     67 
     68 void NativeMessageQueue::wake() {
     69     mLooper->wake();
     70 }
     71 
     72 // ----------------------------------------------------------------------------
     73 
     74 static NativeMessageQueue* android_os_MessageQueue_getNativeMessageQueue(JNIEnv* env,
     75         jobject messageQueueObj) {
     76     jint intPtr = env->GetIntField(messageQueueObj, gMessageQueueClassInfo.mPtr);
     77     return reinterpret_cast<NativeMessageQueue*>(intPtr);
     78 }
     79 
     80 static void android_os_MessageQueue_setNativeMessageQueue(JNIEnv* env, jobject messageQueueObj,
     81         NativeMessageQueue* nativeMessageQueue) {
     82     env->SetIntField(messageQueueObj, gMessageQueueClassInfo.mPtr,
     83              reinterpret_cast<jint>(nativeMessageQueue));
     84 }
     85 
     86 sp<Looper> android_os_MessageQueue_getLooper(JNIEnv* env, jobject messageQueueObj) {
     87     NativeMessageQueue* nativeMessageQueue =
     88             android_os_MessageQueue_getNativeMessageQueue(env, messageQueueObj);
     89     return nativeMessageQueue != NULL ? nativeMessageQueue->getLooper() : NULL;
     90 }
     91 
     92 static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {
     93     NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
     94     if (! nativeMessageQueue) {
     95         jniThrowRuntimeException(env, "Unable to allocate native queue");
     96         return;
     97     }
     98 
     99     android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue);
    100 }
    101 
    102 static void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jobject obj) {
    103     NativeMessageQueue* nativeMessageQueue =
    104             android_os_MessageQueue_getNativeMessageQueue(env, obj);
    105     if (nativeMessageQueue) {
    106         android_os_MessageQueue_setNativeMessageQueue(env, obj, NULL);
    107         delete nativeMessageQueue;
    108     }
    109 }
    110 
    111 static void throwQueueNotInitialized(JNIEnv* env) {
    112     jniThrowException(env, "java/lang/IllegalStateException", "Message queue not initialized");
    113 }
    114 
    115 static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
    116         jint ptr, jint timeoutMillis) {
    117     NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    118     nativeMessageQueue->pollOnce(timeoutMillis);
    119 }
    120 
    121 static void android_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj, jint ptr) {
    122     NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    123     return nativeMessageQueue->wake();
    124 }
    125 
    126 // ----------------------------------------------------------------------------
    127 
    128 static JNINativeMethod gMessageQueueMethods[] = {
    129     /* name, signature, funcPtr */
    130     { "nativeInit", "()V", (void*)android_os_MessageQueue_nativeInit },
    131     { "nativeDestroy", "()V", (void*)android_os_MessageQueue_nativeDestroy },
    132     { "nativePollOnce", "(II)V", (void*)android_os_MessageQueue_nativePollOnce },
    133     { "nativeWake", "(I)V", (void*)android_os_MessageQueue_nativeWake }
    134 };
    135 
    136 #define FIND_CLASS(var, className) \
    137         var = env->FindClass(className); \
    138         LOG_FATAL_IF(! var, "Unable to find class " className); \
    139         var = jclass(env->NewGlobalRef(var));
    140 
    141 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
    142         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
    143         LOG_FATAL_IF(! var, "Unable to find field " fieldName);
    144 
    145 int register_android_os_MessageQueue(JNIEnv* env) {
    146     int res = jniRegisterNativeMethods(env, "android/os/MessageQueue",
    147             gMessageQueueMethods, NELEM(gMessageQueueMethods));
    148     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
    149 
    150     FIND_CLASS(gMessageQueueClassInfo.clazz, "android/os/MessageQueue");
    151 
    152     GET_FIELD_ID(gMessageQueueClassInfo.mPtr, gMessageQueueClassInfo.clazz,
    153             "mPtr", "I");
    154 
    155     return 0;
    156 }
    157 
    158 } // namespace android
    159