diff -r 8d541aa4e1da src/core/android/SDL_android.cpp --- a/src/core/android/SDL_android.cpp mar jun 19 18:25:04 2012 -0300 +++ b/src/core/android/SDL_android.cpp mar jun 19 20:17:38 2012 -0300 @@ -33,6 +33,7 @@ #include "../../video/android/SDL_androidvideo.h" #include +#include #define LOG_TAG "SDL_android" //#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) //#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) @@ -54,8 +55,7 @@ /******************************************************************************* Globals *******************************************************************************/ -static JNIEnv* mEnv = NULL; -static JNIEnv* mAudioEnv = NULL; +static pthread_key_t mThreadKey; static JavaVM* mJavaVM; // Main activity @@ -73,6 +73,8 @@ static float fLastAccelerometer[3]; static bool bHasNewData; +static void Android_JNI_ThreadDestroyed(void*); + /******************************************************************************* Functions called by JNI *******************************************************************************/ @@ -87,17 +89,28 @@ LOGE("Failed to get the environment using GetEnv()"); return -1; } + /* + * Create mThreadKey so we can keep track of the JNIEnv assigned to each thread + * Refer to http://developer.android.com/guide/practices/design/jni.html for the rationale behind this + */ + if (!pthread_key_create(&mThreadKey, Android_JNI_ThreadDestroyed)) { + __android_log_print(ANDROID_LOG_ERROR, "SDL", "Error initializing pthread key"); + } + else { + pthread_setspecific(mThreadKey, (void *) env); + } return JNI_VERSION_1_4; } // Called before SDL_main() to initialize JNI bindings -extern "C" void SDL_Android_Init(JNIEnv* env, jclass cls) +extern "C" void SDL_Android_Init(JNIEnv* mEnv, jclass cls) { __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init()"); - mEnv = env; - mActivityClass = (jclass)env->NewGlobalRef(cls); + pthread_setspecific(mThreadKey, (void *) mEnv); + + mActivityClass = (jclass)mEnv->NewGlobalRef(cls); midCreateGLContext = mEnv->GetStaticMethodID(mActivityClass, "createGLContext","(II)Z"); @@ -202,7 +215,7 @@ JNIEnv* env, jclass cls) { /* This is the audio thread, with a different environment */ - mAudioEnv = env; + pthread_setspecific(mThreadKey, (void *) env); Android_RunAudioThread(); } @@ -248,6 +261,7 @@ extern "C" SDL_bool Android_JNI_CreateContext(int majorVersion, int minorVersion) { + JNIEnv *mEnv = (JNIEnv*) pthread_getspecific(mThreadKey); if (mEnv->CallStaticBooleanMethod(mActivityClass, midCreateGLContext, majorVersion, minorVersion)) { return SDL_TRUE; } else { @@ -257,13 +271,14 @@ extern "C" void Android_JNI_SwapWindow() { + JNIEnv *mEnv = (JNIEnv*) pthread_getspecific(mThreadKey); mEnv->CallStaticVoidMethod(mActivityClass, midFlipBuffers); } extern "C" void Android_JNI_SetActivityTitle(const char *title) { jmethodID mid; - + JNIEnv *mEnv = (JNIEnv*) pthread_getspecific(mThreadKey); mid = mEnv->GetStaticMethodID(mActivityClass,"setActivityTitle","(Ljava/lang/String;)V"); if (mid) { jstring jtitle = reinterpret_cast(mEnv->NewStringUTF(title)); @@ -288,6 +303,15 @@ return retval; } +static void Android_JNI_ThreadDestroyed(void* value) { + /* The thread is being destroyed, detach it from the Java VM and set the mThreadKey value to NULL as required */ + JNIEnv *env = (JNIEnv*) value; + if (env != NULL) { + mJavaVM->DetachCurrentThread(); + pthread_setspecific(mThreadKey, NULL); + } +} + // // Audio support // @@ -312,6 +336,7 @@ return 0; } isAttached = true; + pthread_setspecific(mThreadKey, (void *) env); } @@ -353,6 +378,8 @@ extern "C" void Android_JNI_WriteAudioBuffer() { + JNIEnv *mAudioEnv = (JNIEnv*) pthread_getspecific(mThreadKey); + if (audioBuffer16Bit) { mAudioEnv->ReleaseShortArrayElements((jshortArray)audioBuffer, (jshort *)audioBufferPinned, JNI_COMMIT); mAudioEnv->CallStaticVoidMethod(mActivityClass, midAudioWriteShortBuffer, (jshortArray)audioBuffer); @@ -378,6 +405,7 @@ return; } isAttached = true; + pthread_setspecific(mThreadKey, (void *) env); } env->CallStaticVoidMethod(mActivityClass, midAudioQuit); @@ -397,6 +425,7 @@ static bool Android_JNI_ExceptionOccurred() { SDL_assert(LocalReferenceHolder::IsActive()); + JNIEnv *mEnv = (JNIEnv*) pthread_getspecific(mThreadKey); jthrowable exception = mEnv->ExceptionOccurred(); if (exception != NULL) { @@ -445,6 +474,7 @@ jobject readableByteChannel; jstring fileNameJString; + JNIEnv *mEnv = (JNIEnv*) pthread_getspecific(mThreadKey); if (!refs.init(mEnv)) { goto failure; } @@ -529,6 +559,7 @@ const char* fileName, const char*) { LocalReferenceHolder refs; + JNIEnv *mEnv = (JNIEnv*) pthread_getspecific(mThreadKey); if (!refs.init(mEnv)) { return -1; @@ -552,6 +583,7 @@ int bytesRemaining = size * maxnum; int bytesRead = 0; + JNIEnv *mEnv = (JNIEnv*) pthread_getspecific(mThreadKey); if (!refs.init(mEnv)) { return -1; } @@ -591,6 +623,7 @@ { LocalReferenceHolder refs; int result = 0; + JNIEnv *mEnv = (JNIEnv*) pthread_getspecific(mThreadKey); if (!refs.init(mEnv)) { SDL_SetError("Failed to allocate enough JVM local references"); diff -r 8d541aa4e1da src/main/android/SDL_android_main.cpp --- a/src/main/android/SDL_android_main.cpp mar jun 19 18:25:04 2012 -0300 +++ b/src/main/android/SDL_android_main.cpp mar jun 19 20:17:38 2012 -0300 @@ -5,6 +5,7 @@ /* Include the SDL main definition header */ #include "SDL_main.h" +#include /******************************************************************************* Functions called by JNI @@ -14,12 +15,6 @@ // Called before SDL_main() to initialize JNI bindings in SDL library extern "C" void SDL_Android_Init(JNIEnv* env, jclass cls); -// Library init -extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) -{ - return JNI_VERSION_1_4; -} - // Start up the SDL app extern "C" void Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject obj) {