Commit 3f0781af authored by Ryan C. Gordon's avatar Ryan C. Gordon

Don't use a global JNIEnv across threads; it's not thread safe.

Obtain the correct environment in a thread-safe way when appropriate instead.

Fixes Bugzilla #1312.

Thanks to Bill Chenbin for the patch!
parent 84848501
...@@ -29,6 +29,14 @@ extern "C" { ...@@ -29,6 +29,14 @@ extern "C" {
#include "../../video/android/SDL_androidtouch.h" #include "../../video/android/SDL_androidtouch.h"
#include "../../video/android/SDL_androidvideo.h" #include "../../video/android/SDL_androidvideo.h"
#include <android/log.h>
#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__)
#define LOGI(...) do {} while (false)
#define LOGE(...) do {} while (false)
/* Impelemented in audio/android/SDL_androidaudio.c */ /* Impelemented in audio/android/SDL_androidaudio.c */
extern void Android_RunAudioThread(); extern void Android_RunAudioThread();
} // C } // C
...@@ -45,6 +53,7 @@ extern void Android_RunAudioThread(); ...@@ -45,6 +53,7 @@ extern void Android_RunAudioThread();
*******************************************************************************/ *******************************************************************************/
static JNIEnv* mEnv = NULL; static JNIEnv* mEnv = NULL;
static JNIEnv* mAudioEnv = NULL; static JNIEnv* mAudioEnv = NULL;
static JavaVM* mJavaVM;
// Main activity // Main activity
static jclass mActivityClass; static jclass mActivityClass;
...@@ -68,6 +77,14 @@ static float fLastAccelerometer[3]; ...@@ -68,6 +77,14 @@ static float fLastAccelerometer[3];
// Library init // Library init
extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
{ {
JNIEnv *env;
mJavaVM = vm;
LOGI("JNI_OnLoad called");
if (mJavaVM->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE("Failed to get the environment using GetEnv()");
return -1;
}
return JNI_VERSION_1_4; return JNI_VERSION_1_4;
} }
...@@ -96,6 +113,7 @@ extern "C" void SDL_Android_Init(JNIEnv* env, jclass cls) ...@@ -96,6 +113,7 @@ extern "C" void SDL_Android_Init(JNIEnv* env, jclass cls)
!midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit) { !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit) {
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly"); __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly");
} }
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init() finished!");
} }
// Resize // Resize
...@@ -204,30 +222,49 @@ extern "C" int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int chan ...@@ -204,30 +222,49 @@ extern "C" int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int chan
{ {
int audioBufferFrames; int audioBufferFrames;
int status;
JNIEnv *env;
static bool isAttached = false;
status = mJavaVM->GetEnv((void **) &env, JNI_VERSION_1_4);
if(status < 0) {
LOGE("callback_handler: failed to get JNI environment, assuming native thread");
status = mJavaVM->AttachCurrentThread(&env, NULL);
if(status < 0) {
LOGE("callback_handler: failed to attach current thread");
return 0;
}
isAttached = true;
}
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device"); __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device");
audioBuffer16Bit = is16Bit; audioBuffer16Bit = is16Bit;
audioBufferStereo = channelCount > 1; audioBufferStereo = channelCount > 1;
audioBuffer = mEnv->CallStaticObjectMethod(mActivityClass, midAudioInit, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames); audioBuffer = env->CallStaticObjectMethod(mActivityClass, midAudioInit, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames);
if (audioBuffer == NULL) { if (audioBuffer == NULL) {
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: didn't get back a good audio buffer!"); __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: didn't get back a good audio buffer!");
return 0; return 0;
} }
audioBuffer = mEnv->NewGlobalRef(audioBuffer); audioBuffer = env->NewGlobalRef(audioBuffer);
jboolean isCopy = JNI_FALSE; jboolean isCopy = JNI_FALSE;
if (audioBuffer16Bit) { if (audioBuffer16Bit) {
audioBufferPinned = mEnv->GetShortArrayElements((jshortArray)audioBuffer, &isCopy); audioBufferPinned = env->GetShortArrayElements((jshortArray)audioBuffer, &isCopy);
audioBufferFrames = mEnv->GetArrayLength((jshortArray)audioBuffer); audioBufferFrames = env->GetArrayLength((jshortArray)audioBuffer);
} else { } else {
audioBufferPinned = mEnv->GetByteArrayElements((jbyteArray)audioBuffer, &isCopy); audioBufferPinned = env->GetByteArrayElements((jbyteArray)audioBuffer, &isCopy);
audioBufferFrames = mEnv->GetArrayLength((jbyteArray)audioBuffer); audioBufferFrames = env->GetArrayLength((jbyteArray)audioBuffer);
} }
if (audioBufferStereo) { if (audioBufferStereo) {
audioBufferFrames /= 2; audioBufferFrames /= 2;
} }
if (isAttached) {
mJavaVM->DetachCurrentThread();
}
return audioBufferFrames; return audioBufferFrames;
} }
...@@ -251,13 +288,31 @@ extern "C" void Android_JNI_WriteAudioBuffer() ...@@ -251,13 +288,31 @@ extern "C" void Android_JNI_WriteAudioBuffer()
extern "C" void Android_JNI_CloseAudioDevice() extern "C" void Android_JNI_CloseAudioDevice()
{ {
mEnv->CallStaticVoidMethod(mActivityClass, midAudioQuit); int status;
JNIEnv *env;
static bool isAttached = false;
status = mJavaVM->GetEnv((void **) &env, JNI_VERSION_1_4);
if(status < 0) {
LOGE("callback_handler: failed to get JNI environment, assuming native thread");
status = mJavaVM->AttachCurrentThread(&env, NULL);
if(status < 0) {
LOGE("callback_handler: failed to attach current thread");
return;
}
isAttached = true;
}
env->CallStaticVoidMethod(mActivityClass, midAudioQuit);
if (audioBuffer) { if (audioBuffer) {
mEnv->DeleteGlobalRef(audioBuffer); env->DeleteGlobalRef(audioBuffer);
audioBuffer = NULL; audioBuffer = NULL;
audioBufferPinned = NULL; audioBufferPinned = NULL;
} }
if (isAttached) {
mJavaVM->DetachCurrentThread();
}
} }
// Test for an exception and call SDL_SetError with its detail if one occurs // Test for an exception and call SDL_SetError with its detail if one occurs
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment