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