android_os_MessageQueue.cpp revision 415d8c38199e258dfce92cdb0c69e056b3b51ef8
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    void 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
64void NativeMessageQueue::pollOnce(int timeoutMillis) {
65    mLooper->pollOnce(timeoutMillis);
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 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
121static 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
128static 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
145int 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