android_os_MessageQueue.cpp revision 4fe6c3e51be77e35f40872cdbca6c80f8f8b7ecb
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
25namespace android {
26
27// ----------------------------------------------------------------------------
28
29static struct {
30    jclass clazz;
31
32    jfieldID mPtr;   // native object attached to the DVM MessageQueue
33} gMessageQueueClassInfo;
34
35// ----------------------------------------------------------------------------
36
37class NativeMessageQueue {
38public:
39    NativeMessageQueue();
40    ~NativeMessageQueue();
41
42    inline sp<Looper> getLooper() { return mLooper; }
43
44    bool pollOnce(int timeoutMillis);
45    void wake();
46
47private:
48    sp<Looper> mLooper;
49};
50
51// ----------------------------------------------------------------------------
52
53NativeMessageQueue::NativeMessageQueue() {
54    mLooper = Looper::getForThread();
55    if (mLooper == NULL) {
56        mLooper = new Looper(false);
57        Looper::setForThread(mLooper);
58    }
59}
60
61NativeMessageQueue::~NativeMessageQueue() {
62}
63
64bool NativeMessageQueue::pollOnce(int timeoutMillis) {
65    return mLooper->pollOnce(timeoutMillis) != ALOOPER_POLL_TIMEOUT;
66}
67
68void NativeMessageQueue::wake() {
69    mLooper->wake();
70}
71
72// ----------------------------------------------------------------------------
73
74static 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
80static 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
86sp<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
92static 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
102static 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
111static void throwQueueNotInitialized(JNIEnv* env) {
112    jniThrowException(env, "java/lang/IllegalStateException", "Message queue not initialized");
113}
114
115static jboolean android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
116        jint timeoutMillis) {
117    NativeMessageQueue* nativeMessageQueue =
118            android_os_MessageQueue_getNativeMessageQueue(env, obj);
119    if (! nativeMessageQueue) {
120        throwQueueNotInitialized(env);
121        return false;
122    }
123    return nativeMessageQueue->pollOnce(timeoutMillis);
124}
125
126static void android_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj) {
127    NativeMessageQueue* nativeMessageQueue =
128            android_os_MessageQueue_getNativeMessageQueue(env, obj);
129    if (! nativeMessageQueue) {
130        throwQueueNotInitialized(env);
131        return;
132    }
133    return nativeMessageQueue->wake();
134}
135
136// ----------------------------------------------------------------------------
137
138static JNINativeMethod gMessageQueueMethods[] = {
139    /* name, signature, funcPtr */
140    { "nativeInit", "()V", (void*)android_os_MessageQueue_nativeInit },
141    { "nativeDestroy", "()V", (void*)android_os_MessageQueue_nativeDestroy },
142    { "nativePollOnce", "(I)Z", (void*)android_os_MessageQueue_nativePollOnce },
143    { "nativeWake", "()V", (void*)android_os_MessageQueue_nativeWake }
144};
145
146#define FIND_CLASS(var, className) \
147        var = env->FindClass(className); \
148        LOG_FATAL_IF(! var, "Unable to find class " className); \
149        var = jclass(env->NewGlobalRef(var));
150
151#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
152        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
153        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
154
155int register_android_os_MessageQueue(JNIEnv* env) {
156    int res = jniRegisterNativeMethods(env, "android/os/MessageQueue",
157            gMessageQueueMethods, NELEM(gMessageQueueMethods));
158    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
159
160    FIND_CLASS(gMessageQueueClassInfo.clazz, "android/os/MessageQueue");
161
162    GET_FIELD_ID(gMessageQueueClassInfo.mPtr, gMessageQueueClassInfo.clazz,
163            "mPtr", "I");
164
165    return 0;
166}
167
168} // namespace android
169