1.1 --- a/src/core/android/SDL_android.cpp Tue Feb 07 19:34:24 2012 -0500
1.2 +++ b/src/core/android/SDL_android.cpp Sun Feb 12 20:57:32 2012 -0500
1.3 @@ -20,6 +20,7 @@
1.4 */
1.5 #include "SDL_config.h"
1.6 #include "SDL_stdinc.h"
1.7 +#include "SDL_assert.h"
1.8
1.9 #ifdef __ANDROID__
1.10
1.11 @@ -203,6 +204,41 @@
1.12 /*******************************************************************************
1.13 Functions called by SDL into Java
1.14 *******************************************************************************/
1.15 +
1.16 +class LocalReferenceHolder
1.17 +{
1.18 +private:
1.19 + static int s_active;
1.20 +
1.21 +public:
1.22 + static bool IsActive() {
1.23 + return s_active > 0;
1.24 + }
1.25 +
1.26 +public:
1.27 + LocalReferenceHolder() : m_env(NULL) { }
1.28 + ~LocalReferenceHolder() {
1.29 + if (m_env) {
1.30 + m_env->PopLocalFrame(NULL);
1.31 + --s_active;
1.32 + }
1.33 + }
1.34 +
1.35 + bool init(JNIEnv *env, jint capacity = 16) {
1.36 + if (env->PushLocalFrame(capacity) < 0) {
1.37 + SDL_SetError("Failed to allocate enough JVM local references");
1.38 + return false;
1.39 + }
1.40 + ++s_active;
1.41 + m_env = env;
1.42 + return true;
1.43 + }
1.44 +
1.45 +protected:
1.46 + JNIEnv *m_env;
1.47 +};
1.48 +int LocalReferenceHolder::s_active;
1.49 +
1.50 extern "C" SDL_bool Android_JNI_CreateContext(int majorVersion, int minorVersion)
1.51 {
1.52 if (mEnv->CallStaticBooleanMethod(mActivityClass, midCreateGLContext, majorVersion, minorVersion)) {
1.53 @@ -351,6 +387,8 @@
1.54 // Test for an exception and call SDL_SetError with its detail if one occurs
1.55 static bool Android_JNI_ExceptionOccurred()
1.56 {
1.57 + SDL_assert(LocalReferenceHolder::IsActive());
1.58 +
1.59 jthrowable exception = mEnv->ExceptionOccurred();
1.60 if (exception != NULL) {
1.61 jmethodID mid;
1.62 @@ -373,16 +411,11 @@
1.63 exceptionMessage, 0);
1.64 SDL_SetError("%s: %s", exceptionNameUTF8, exceptionMessageUTF8);
1.65 mEnv->ReleaseStringUTFChars(exceptionMessage, exceptionMessageUTF8);
1.66 - mEnv->DeleteLocalRef(exceptionMessage);
1.67 } else {
1.68 SDL_SetError("%s", exceptionNameUTF8);
1.69 }
1.70
1.71 mEnv->ReleaseStringUTFChars(exceptionName, exceptionNameUTF8);
1.72 - mEnv->DeleteLocalRef(exceptionName);
1.73 - mEnv->DeleteLocalRef(classClass);
1.74 - mEnv->DeleteLocalRef(exceptionClass);
1.75 - mEnv->DeleteLocalRef(exception);
1.76
1.77 return true;
1.78 }
1.79 @@ -392,6 +425,7 @@
1.80
1.81 static int Android_JNI_FileOpen(SDL_RWops* ctx)
1.82 {
1.83 + LocalReferenceHolder refs;
1.84 int result = 0;
1.85
1.86 jmethodID mid;
1.87 @@ -402,13 +436,8 @@
1.88 jobject readableByteChannel;
1.89 jstring fileNameJString;
1.90
1.91 - bool allocatedLocalFrame = false;
1.92 -
1.93 - if (mEnv->PushLocalFrame(16) < 0) {
1.94 - SDL_SetError("Failed to allocate enough JVM local references");
1.95 + if (!refs.init(mEnv)) {
1.96 goto failure;
1.97 - } else {
1.98 - allocatedLocalFrame = true;
1.99 }
1.100
1.101 fileNameJString = (jstring)ctx->hidden.androidio.fileName;
1.102 @@ -481,16 +510,18 @@
1.103 }
1.104 }
1.105
1.106 - if (allocatedLocalFrame) {
1.107 - mEnv->PopLocalFrame(NULL);
1.108 - }
1.109 -
1.110 return result;
1.111 }
1.112
1.113 extern "C" int Android_JNI_FileOpen(SDL_RWops* ctx,
1.114 const char* fileName, const char*)
1.115 {
1.116 + LocalReferenceHolder refs;
1.117 +
1.118 + if (!refs.init(mEnv)) {
1.119 + return -1;
1.120 + }
1.121 +
1.122 if (!ctx) {
1.123 return -1;
1.124 }
1.125 @@ -499,7 +530,6 @@
1.126 ctx->hidden.androidio.fileName = fileNameJString;
1.127 ctx->hidden.androidio.fileNameRef = mEnv->NewGlobalRef(fileNameJString);
1.128 ctx->hidden.androidio.inputStreamRef = NULL;
1.129 - mEnv->DeleteLocalRef(fileNameJString);
1.130
1.131 return Android_JNI_FileOpen(ctx);
1.132 }
1.133 @@ -507,9 +537,14 @@
1.134 extern "C" size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer,
1.135 size_t size, size_t maxnum)
1.136 {
1.137 + LocalReferenceHolder refs;
1.138 int bytesRemaining = size * maxnum;
1.139 int bytesRead = 0;
1.140
1.141 + if (!refs.init(mEnv)) {
1.142 + return -1;
1.143 + }
1.144 +
1.145 jobject readableByteChannel = (jobject)ctx->hidden.androidio.readableByteChannel;
1.146 jmethodID readMethod = (jmethodID)ctx->hidden.androidio.readMethod;
1.147 jobject byteBuffer = mEnv->NewDirectByteBuffer(buffer, bytesRemaining);
1.148 @@ -519,7 +554,6 @@
1.149 int result = mEnv->CallIntMethod(readableByteChannel, readMethod, byteBuffer);
1.150
1.151 if (Android_JNI_ExceptionOccurred()) {
1.152 - mEnv->DeleteLocalRef(byteBuffer);
1.153 return 0;
1.154 }
1.155
1.156 @@ -532,8 +566,6 @@
1.157 ctx->hidden.androidio.position += result;
1.158 }
1.159
1.160 - mEnv->DeleteLocalRef(byteBuffer);
1.161 -
1.162 return bytesRead / size;
1.163 }
1.164
1.165 @@ -546,8 +578,14 @@
1.166
1.167 static int Android_JNI_FileClose(SDL_RWops* ctx, bool release)
1.168 {
1.169 + LocalReferenceHolder refs;
1.170 int result = 0;
1.171
1.172 + if (!refs.init(mEnv)) {
1.173 + SDL_SetError("Failed to allocate enough JVM local references");
1.174 + return -1;
1.175 + }
1.176 +
1.177 if (ctx) {
1.178 if (release) {
1.179 mEnv->DeleteGlobalRef((jobject)ctx->hidden.androidio.fileNameRef);