android_os_MessageQueue.cpp revision 864693461b6223a995038847591b17abe2de647e
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
112864693461b6223a995038847591b17abe2de647eJeff Brownsp<MessageQueue> android_os_MessageQueue_getMessageQueue(JNIEnv* env, jobject messageQueueObj) {
11346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jint intPtr = env->GetIntField(messageQueueObj, gMessageQueueClassInfo.mPtr);
11446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    return reinterpret_cast<NativeMessageQueue*>(intPtr);
115fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
116fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
117864693461b6223a995038847591b17abe2de647eJeff Brownstatic jint android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
11846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
119603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    if (!nativeMessageQueue) {
12046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        jniThrowRuntimeException(env, "Unable to allocate native queue");
121864693461b6223a995038847591b17abe2de647eJeff Brown        return 0;
122fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate    }
123fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
124603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    nativeMessageQueue->incStrong(env);
125864693461b6223a995038847591b17abe2de647eJeff Brown    return reinterpret_cast<jint>(nativeMessageQueue);
126fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
127fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
128864693461b6223a995038847591b17abe2de647eJeff Brownstatic void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jclass clazz, jint ptr) {
129864693461b6223a995038847591b17abe2de647eJeff Brown    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
130864693461b6223a995038847591b17abe2de647eJeff Brown    nativeMessageQueue->decStrong(env);
131fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
132fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
133864693461b6223a995038847591b17abe2de647eJeff Brownstatic void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jclass clazz,
134415d8c38199e258dfce92cdb0c69e056b3b51ef8Jeff Brown        jint ptr, jint timeoutMillis) {
135415d8c38199e258dfce92cdb0c69e056b3b51ef8Jeff Brown    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
136603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    nativeMessageQueue->pollOnce(env, timeoutMillis);
137fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
138fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
139864693461b6223a995038847591b17abe2de647eJeff Brownstatic void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jint ptr) {
140415d8c38199e258dfce92cdb0c69e056b3b51ef8Jeff Brown    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
14146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    return nativeMessageQueue->wake();
142fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
143fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
144fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate// ----------------------------------------------------------------------------
145fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
146fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tatestatic JNINativeMethod gMessageQueueMethods[] = {
147fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate    /* name, signature, funcPtr */
148864693461b6223a995038847591b17abe2de647eJeff Brown    { "nativeInit", "()I", (void*)android_os_MessageQueue_nativeInit },
149864693461b6223a995038847591b17abe2de647eJeff Brown    { "nativeDestroy", "(I)V", (void*)android_os_MessageQueue_nativeDestroy },
150415d8c38199e258dfce92cdb0c69e056b3b51ef8Jeff Brown    { "nativePollOnce", "(II)V", (void*)android_os_MessageQueue_nativePollOnce },
151415d8c38199e258dfce92cdb0c69e056b3b51ef8Jeff Brown    { "nativeWake", "(I)V", (void*)android_os_MessageQueue_nativeWake }
152fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate};
153fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
15446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#define FIND_CLASS(var, className) \
15546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        var = env->FindClass(className); \
15617cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro        LOG_FATAL_IF(! var, "Unable to find class " className);
15746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
15846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
15946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
16046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
16146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
162fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tateint register_android_os_MessageQueue(JNIEnv* env) {
16346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    int res = jniRegisterNativeMethods(env, "android/os/MessageQueue",
16446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            gMessageQueueMethods, NELEM(gMessageQueueMethods));
16546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
16646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
16717cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro    jclass clazz;
16817cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro    FIND_CLASS(clazz, "android/os/MessageQueue");
169fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
17017cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro    GET_FIELD_ID(gMessageQueueClassInfo.mPtr, clazz,
17146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            "mPtr", "I");
172fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
17346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    return 0;
174fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
175fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
17646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown} // namespace android
177