1fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate/*
2fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * Copyright (C) 2010 The Android Open Source Project
3fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate *
4fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * Licensed under the Apache License, Version 2.0 (the "License");
5fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * you may not use this file except in compliance with the License.
6fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * You may obtain a copy of the License at
7fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate *
8fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate *      http://www.apache.org/licenses/LICENSE-2.0
9fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate *
10fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * Unless required by applicable law or agreed to in writing, software
11fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * distributed under the License is distributed on an "AS IS" BASIS,
12fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * See the License for the specific language governing permissions and
14fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * limitations under the License.
15fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate */
16fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
1746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#define LOG_TAG "MessageQueue-JNI"
18fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
19fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate#include "JNIHelp.h"
20603b44589682db3ff33ade172facb0c5e309f1beJeff Brown#include <android_runtime/AndroidRuntime.h>
21fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
224fe6c3e51be77e35f40872cdbca6c80f8f8b7ecbJeff Brown#include <utils/Looper.h>
23fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate#include <utils/Log.h>
2446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#include "android_os_MessageQueue.h"
25fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
2646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownnamespace android {
27fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
28fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tatestatic struct {
2946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jfieldID mPtr;   // native object attached to the DVM MessageQueue
3046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown} gMessageQueueClassInfo;
31fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
32fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
33603b44589682db3ff33ade172facb0c5e309f1beJeff Brownclass NativeMessageQueue : public MessageQueue {
34fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tatepublic:
3546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    NativeMessageQueue();
36603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    virtual ~NativeMessageQueue();
37603b44589682db3ff33ade172facb0c5e309f1beJeff Brown
38603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj);
39fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
40603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    void pollOnce(JNIEnv* env, int timeoutMillis);
41fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
4246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    void wake();
43fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
44fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tateprivate:
45603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    bool mInCallback;
46603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    jthrowable mExceptionObj;
47fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate};
48fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
49fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
50603b44589682db3ff33ade172facb0c5e309f1beJeff BrownMessageQueue::MessageQueue() {
51603b44589682db3ff33ade172facb0c5e309f1beJeff Brown}
52603b44589682db3ff33ade172facb0c5e309f1beJeff Brown
53603b44589682db3ff33ade172facb0c5e309f1beJeff BrownMessageQueue::~MessageQueue() {
54603b44589682db3ff33ade172facb0c5e309f1beJeff Brown}
55603b44589682db3ff33ade172facb0c5e309f1beJeff Brown
56603b44589682db3ff33ade172facb0c5e309f1beJeff Brownbool MessageQueue::raiseAndClearException(JNIEnv* env, const char* msg) {
57603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    jthrowable exceptionObj = env->ExceptionOccurred();
58603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    if (exceptionObj) {
59603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        env->ExceptionClear();
60603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        raiseException(env, msg, exceptionObj);
61603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        env->DeleteLocalRef(exceptionObj);
62603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        return true;
63603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    }
64603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    return false;
65603b44589682db3ff33ade172facb0c5e309f1beJeff Brown}
66603b44589682db3ff33ade172facb0c5e309f1beJeff Brown
67603b44589682db3ff33ade172facb0c5e309f1beJeff BrownNativeMessageQueue::NativeMessageQueue() : mInCallback(false), mExceptionObj(NULL) {
684fe6c3e51be77e35f40872cdbca6c80f8f8b7ecbJeff Brown    mLooper = Looper::getForThread();
694fe6c3e51be77e35f40872cdbca6c80f8f8b7ecbJeff Brown    if (mLooper == NULL) {
704fe6c3e51be77e35f40872cdbca6c80f8f8b7ecbJeff Brown        mLooper = new Looper(false);
714fe6c3e51be77e35f40872cdbca6c80f8f8b7ecbJeff Brown        Looper::setForThread(mLooper);
72682674154e3fe88f6061245145f934f25f1a2eb8Dianne Hackborn    }
73fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
74fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
7546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff BrownNativeMessageQueue::~NativeMessageQueue() {
76fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
77fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
78603b44589682db3ff33ade172facb0c5e309f1beJeff Brownvoid NativeMessageQueue::raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj) {
79603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    if (exceptionObj) {
80603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        if (mInCallback) {
81603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            if (mExceptionObj) {
82603b44589682db3ff33ade172facb0c5e309f1beJeff Brown                env->DeleteLocalRef(mExceptionObj);
83603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            }
84603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            mExceptionObj = jthrowable(env->NewLocalRef(exceptionObj));
85603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            ALOGE("Exception in MessageQueue callback: %s", msg);
86603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            jniLogException(env, ANDROID_LOG_ERROR, LOG_TAG, exceptionObj);
87603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        } else {
88603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            ALOGE("Exception: %s", msg);
89603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            jniLogException(env, ANDROID_LOG_ERROR, LOG_TAG, exceptionObj);
90603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            LOG_ALWAYS_FATAL("raiseException() was called when not in a callback, exiting.");
91603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        }
92603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    }
93603b44589682db3ff33ade172facb0c5e309f1beJeff Brown}
94603b44589682db3ff33ade172facb0c5e309f1beJeff Brown
95603b44589682db3ff33ade172facb0c5e309f1beJeff Brownvoid NativeMessageQueue::pollOnce(JNIEnv* env, int timeoutMillis) {
96603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    mInCallback = true;
97415d8c38199e258dfce92cdb0c69e056b3b51ef8Jeff Brown    mLooper->pollOnce(timeoutMillis);
98603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    mInCallback = false;
99603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    if (mExceptionObj) {
100603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        env->Throw(mExceptionObj);
101603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        env->DeleteLocalRef(mExceptionObj);
102603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        mExceptionObj = NULL;
103603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    }
104fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
105fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
10646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownvoid NativeMessageQueue::wake() {
1074fe6c3e51be77e35f40872cdbca6c80f8f8b7ecbJeff Brown    mLooper->wake();
108fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
109fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
11046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown// ----------------------------------------------------------------------------
111fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
11246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownstatic NativeMessageQueue* android_os_MessageQueue_getNativeMessageQueue(JNIEnv* env,
11346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        jobject messageQueueObj) {
11446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jint intPtr = env->GetIntField(messageQueueObj, gMessageQueueClassInfo.mPtr);
11546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    return reinterpret_cast<NativeMessageQueue*>(intPtr);
116fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
117fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
11846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownstatic void android_os_MessageQueue_setNativeMessageQueue(JNIEnv* env, jobject messageQueueObj,
11946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        NativeMessageQueue* nativeMessageQueue) {
12046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    env->SetIntField(messageQueueObj, gMessageQueueClassInfo.mPtr,
12146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown             reinterpret_cast<jint>(nativeMessageQueue));
122fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
123fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
124603b44589682db3ff33ade172facb0c5e309f1beJeff Brownsp<MessageQueue> android_os_MessageQueue_getMessageQueue(JNIEnv* env, jobject messageQueueObj) {
12546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    NativeMessageQueue* nativeMessageQueue =
12646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            android_os_MessageQueue_getNativeMessageQueue(env, messageQueueObj);
127603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    return nativeMessageQueue;
12846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown}
129fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
13046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownstatic void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {
13146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
132603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    if (!nativeMessageQueue) {
13346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        jniThrowRuntimeException(env, "Unable to allocate native queue");
13446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        return;
135fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate    }
136fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
137603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    nativeMessageQueue->incStrong(env);
13846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue);
139fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
140fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
14146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownstatic void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jobject obj) {
14246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    NativeMessageQueue* nativeMessageQueue =
14346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            android_os_MessageQueue_getNativeMessageQueue(env, obj);
14446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    if (nativeMessageQueue) {
14546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        android_os_MessageQueue_setNativeMessageQueue(env, obj, NULL);
146603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        nativeMessageQueue->decStrong(env);
147fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate    }
148fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
149fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
15046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownstatic void throwQueueNotInitialized(JNIEnv* env) {
15146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jniThrowException(env, "java/lang/IllegalStateException", "Message queue not initialized");
152fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
153fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
154415d8c38199e258dfce92cdb0c69e056b3b51ef8Jeff Brownstatic void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
155415d8c38199e258dfce92cdb0c69e056b3b51ef8Jeff Brown        jint ptr, jint timeoutMillis) {
156415d8c38199e258dfce92cdb0c69e056b3b51ef8Jeff Brown    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
157603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    nativeMessageQueue->pollOnce(env, timeoutMillis);
158fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
159fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
160415d8c38199e258dfce92cdb0c69e056b3b51ef8Jeff Brownstatic void android_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj, jint ptr) {
161415d8c38199e258dfce92cdb0c69e056b3b51ef8Jeff Brown    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
16246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    return nativeMessageQueue->wake();
163fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
164fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
165fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate// ----------------------------------------------------------------------------
166fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
167fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tatestatic JNINativeMethod gMessageQueueMethods[] = {
168fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate    /* name, signature, funcPtr */
16946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    { "nativeInit", "()V", (void*)android_os_MessageQueue_nativeInit },
17046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    { "nativeDestroy", "()V", (void*)android_os_MessageQueue_nativeDestroy },
171415d8c38199e258dfce92cdb0c69e056b3b51ef8Jeff Brown    { "nativePollOnce", "(II)V", (void*)android_os_MessageQueue_nativePollOnce },
172415d8c38199e258dfce92cdb0c69e056b3b51ef8Jeff Brown    { "nativeWake", "(I)V", (void*)android_os_MessageQueue_nativeWake }
173fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate};
174fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
17546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#define FIND_CLASS(var, className) \
17646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        var = env->FindClass(className); \
17717cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro        LOG_FATAL_IF(! var, "Unable to find class " className);
17846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
17946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
18046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
18146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
18246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
183fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tateint register_android_os_MessageQueue(JNIEnv* env) {
18446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    int res = jniRegisterNativeMethods(env, "android/os/MessageQueue",
18546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            gMessageQueueMethods, NELEM(gMessageQueueMethods));
18646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
18746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
18817cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro    jclass clazz;
18917cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro    FIND_CLASS(clazz, "android/os/MessageQueue");
190fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
19117cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro    GET_FIELD_ID(gMessageQueueClassInfo.mPtr, clazz,
19246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            "mPtr", "I");
193fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
19446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    return 0;
195fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
196fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
19746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown} // namespace android
198