Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Commit

Permalink
Fixed bug 1417 - Android_JNI_FileClose local reference bug
Browse files Browse the repository at this point in the history
A better solution for automatic local reference management.
  • Loading branch information
slouken committed Feb 13, 2012
1 parent 1b40a1e commit 84bfe01
Showing 1 changed file with 57 additions and 19 deletions.
76 changes: 57 additions & 19 deletions src/core/android/SDL_android.cpp
Expand Up @@ -20,6 +20,7 @@
*/ */
#include "SDL_config.h" #include "SDL_config.h"
#include "SDL_stdinc.h" #include "SDL_stdinc.h"
#include "SDL_assert.h"


#ifdef __ANDROID__ #ifdef __ANDROID__


Expand Down Expand Up @@ -203,6 +204,41 @@ extern "C" void Java_org_libsdl_app_SDLActivity_nativeRunAudioThread(
/******************************************************************************* /*******************************************************************************
Functions called by SDL into Java Functions called by SDL into Java
*******************************************************************************/ *******************************************************************************/

class LocalReferenceHolder
{
private:
static int s_active;

public:
static bool IsActive() {
return s_active > 0;
}

public:
LocalReferenceHolder() : m_env(NULL) { }
~LocalReferenceHolder() {
if (m_env) {
m_env->PopLocalFrame(NULL);
--s_active;
}
}

bool init(JNIEnv *env, jint capacity = 16) {
if (env->PushLocalFrame(capacity) < 0) {
SDL_SetError("Failed to allocate enough JVM local references");
return false;
}
++s_active;
m_env = env;
return true;
}

protected:
JNIEnv *m_env;
};
int LocalReferenceHolder::s_active;

extern "C" SDL_bool Android_JNI_CreateContext(int majorVersion, int minorVersion) extern "C" SDL_bool Android_JNI_CreateContext(int majorVersion, int minorVersion)
{ {
if (mEnv->CallStaticBooleanMethod(mActivityClass, midCreateGLContext, majorVersion, minorVersion)) { if (mEnv->CallStaticBooleanMethod(mActivityClass, midCreateGLContext, majorVersion, minorVersion)) {
Expand Down Expand Up @@ -351,6 +387,8 @@ extern "C" void Android_JNI_CloseAudioDevice()
// 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
static bool Android_JNI_ExceptionOccurred() static bool Android_JNI_ExceptionOccurred()
{ {
SDL_assert(LocalReferenceHolder::IsActive());

jthrowable exception = mEnv->ExceptionOccurred(); jthrowable exception = mEnv->ExceptionOccurred();
if (exception != NULL) { if (exception != NULL) {
jmethodID mid; jmethodID mid;
Expand All @@ -373,16 +411,11 @@ static bool Android_JNI_ExceptionOccurred()
exceptionMessage, 0); exceptionMessage, 0);
SDL_SetError("%s: %s", exceptionNameUTF8, exceptionMessageUTF8); SDL_SetError("%s: %s", exceptionNameUTF8, exceptionMessageUTF8);
mEnv->ReleaseStringUTFChars(exceptionMessage, exceptionMessageUTF8); mEnv->ReleaseStringUTFChars(exceptionMessage, exceptionMessageUTF8);
mEnv->DeleteLocalRef(exceptionMessage);
} else { } else {
SDL_SetError("%s", exceptionNameUTF8); SDL_SetError("%s", exceptionNameUTF8);
} }


mEnv->ReleaseStringUTFChars(exceptionName, exceptionNameUTF8); mEnv->ReleaseStringUTFChars(exceptionName, exceptionNameUTF8);
mEnv->DeleteLocalRef(exceptionName);
mEnv->DeleteLocalRef(classClass);
mEnv->DeleteLocalRef(exceptionClass);
mEnv->DeleteLocalRef(exception);


return true; return true;
} }
Expand All @@ -392,6 +425,7 @@ static bool Android_JNI_ExceptionOccurred()


static int Android_JNI_FileOpen(SDL_RWops* ctx) static int Android_JNI_FileOpen(SDL_RWops* ctx)
{ {
LocalReferenceHolder refs;
int result = 0; int result = 0;


jmethodID mid; jmethodID mid;
Expand All @@ -402,13 +436,8 @@ static int Android_JNI_FileOpen(SDL_RWops* ctx)
jobject readableByteChannel; jobject readableByteChannel;
jstring fileNameJString; jstring fileNameJString;


bool allocatedLocalFrame = false; if (!refs.init(mEnv)) {

if (mEnv->PushLocalFrame(16) < 0) {
SDL_SetError("Failed to allocate enough JVM local references");
goto failure; goto failure;
} else {
allocatedLocalFrame = true;
} }


fileNameJString = (jstring)ctx->hidden.androidio.fileName; fileNameJString = (jstring)ctx->hidden.androidio.fileName;
Expand Down Expand Up @@ -481,16 +510,18 @@ static int Android_JNI_FileOpen(SDL_RWops* ctx)
} }
} }


if (allocatedLocalFrame) {
mEnv->PopLocalFrame(NULL);
}

return result; return result;
} }


extern "C" int Android_JNI_FileOpen(SDL_RWops* ctx, extern "C" int Android_JNI_FileOpen(SDL_RWops* ctx,
const char* fileName, const char*) const char* fileName, const char*)
{ {
LocalReferenceHolder refs;

if (!refs.init(mEnv)) {
return -1;
}

if (!ctx) { if (!ctx) {
return -1; return -1;
} }
Expand All @@ -499,17 +530,21 @@ extern "C" int Android_JNI_FileOpen(SDL_RWops* ctx,
ctx->hidden.androidio.fileName = fileNameJString; ctx->hidden.androidio.fileName = fileNameJString;
ctx->hidden.androidio.fileNameRef = mEnv->NewGlobalRef(fileNameJString); ctx->hidden.androidio.fileNameRef = mEnv->NewGlobalRef(fileNameJString);
ctx->hidden.androidio.inputStreamRef = NULL; ctx->hidden.androidio.inputStreamRef = NULL;
mEnv->DeleteLocalRef(fileNameJString);


return Android_JNI_FileOpen(ctx); return Android_JNI_FileOpen(ctx);
} }


extern "C" size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer, extern "C" size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer,
size_t size, size_t maxnum) size_t size, size_t maxnum)
{ {
LocalReferenceHolder refs;
int bytesRemaining = size * maxnum; int bytesRemaining = size * maxnum;
int bytesRead = 0; int bytesRead = 0;


if (!refs.init(mEnv)) {
return -1;
}

jobject readableByteChannel = (jobject)ctx->hidden.androidio.readableByteChannel; jobject readableByteChannel = (jobject)ctx->hidden.androidio.readableByteChannel;
jmethodID readMethod = (jmethodID)ctx->hidden.androidio.readMethod; jmethodID readMethod = (jmethodID)ctx->hidden.androidio.readMethod;
jobject byteBuffer = mEnv->NewDirectByteBuffer(buffer, bytesRemaining); jobject byteBuffer = mEnv->NewDirectByteBuffer(buffer, bytesRemaining);
Expand All @@ -519,7 +554,6 @@ extern "C" size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer,
int result = mEnv->CallIntMethod(readableByteChannel, readMethod, byteBuffer); int result = mEnv->CallIntMethod(readableByteChannel, readMethod, byteBuffer);


if (Android_JNI_ExceptionOccurred()) { if (Android_JNI_ExceptionOccurred()) {
mEnv->DeleteLocalRef(byteBuffer);
return 0; return 0;
} }


Expand All @@ -532,8 +566,6 @@ extern "C" size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer,
ctx->hidden.androidio.position += result; ctx->hidden.androidio.position += result;
} }


mEnv->DeleteLocalRef(byteBuffer);

return bytesRead / size; return bytesRead / size;
} }


Expand All @@ -546,8 +578,14 @@ extern "C" size_t Android_JNI_FileWrite(SDL_RWops* ctx, const void* buffer,


static int Android_JNI_FileClose(SDL_RWops* ctx, bool release) static int Android_JNI_FileClose(SDL_RWops* ctx, bool release)
{ {
LocalReferenceHolder refs;
int result = 0; int result = 0;


if (!refs.init(mEnv)) {
SDL_SetError("Failed to allocate enough JVM local references");
return -1;
}

if (ctx) { if (ctx) {
if (release) { if (release) {
mEnv->DeleteGlobalRef((jobject)ctx->hidden.androidio.fileNameRef); mEnv->DeleteGlobalRef((jobject)ctx->hidden.androidio.fileNameRef);
Expand Down

0 comments on commit 84bfe01

Please sign in to comment.