25 #include "JNIHelper.h"
29 #define GET_PROCESS_ID() ((int32_t)getpid())
31 #define GET_PROCESS_ID() (0)
34 extern void VSJNI_MemoryManagerInit(JavaVM* aJVM);
36 namespace com {
namespace avpkit {
namespace ferry {
37 JNIHelper* JNIHelper::sSingleton = 0;
38 volatile bool JNIHelper::sDebuggerAttached =
false;
41 JNIHelper :: getHelper()
43 JNIHelper *retval = 0;
46 retval =
new JNIHelper();
53 JNIHelper :: shutdownHelper()
61 JNIHelper :: JNIHelper()
64 mVersion = JNI_VERSION_1_2;
65 mJNIPointerReference_class = 0;
67 mJNIPointerReference_setPointer_mid = 0;
68 mJNIPointerReference_getPointer_mid = 0;
69 mOutOfMemoryErrorSingleton = 0;
72 mThread_isInterrupted_mid = 0;
73 mThread_currentThread_mid = 0;
75 mInterruptedException_class = 0;
79 JNIHelper :: addCallback(std::list<CallbackHelper*>* list,
80 CallbackFunc callback,
83 CallbackHelper *helper =
new CallbackHelper;
86 helper->mCallback = callback;
87 helper->mClosure = closure;
88 list->push_back(helper);
94 JNIHelper :: processCallbacks(std::list<CallbackHelper*>* list,
98 while (!list->empty())
101 CallbackHelper *helper = list->front();
103 if (helper->mCallback && execFunc)
104 helper->mCallback(vm, helper->mClosure);
113 JNIHelper :: ~JNIHelper()
117 processCallbacks(&mInitializationCallbacks, 0,
false);
118 processCallbacks(&mTerminationCallbacks, mCachedVM,
true);
120 env = this->getEnv();
123 if (mOutOfMemoryErrorSingleton)
125 env->DeleteGlobalRef(mOutOfMemoryErrorSingleton);
126 mOutOfMemoryErrorSingleton = 0;
128 if (mJNIPointerReference_class)
131 env->DeleteWeakGlobalRef(mJNIPointerReference_class);
132 mJNIPointerReference_class = 0;
136 env->DeleteWeakGlobalRef(mThread_class);
139 if (mInterruptedException_class)
141 env->DeleteWeakGlobalRef(mInterruptedException_class);
142 mInterruptedException_class = 0;
149 JNIHelper :: setVM(JavaVM * jvm)
156 JNIEnv *env=this->getEnv();
161 waitForDebugger(env);
167 cls = env->FindClass(
"java/lang/OutOfMemoryError");
168 if (!cls || env->ExceptionCheck())
171 jmethodID constructor = env->GetMethodID(cls,
"<init>",
"(Ljava/lang/String;)V");
172 if (!constructor || env->ExceptionCheck())
175 jstring errorMessage = env->NewStringUTF(
176 "Sorry, but we're all out of native memory. How out"
177 " of native memory are we? Well, we're so out we're"
178 " throwing a exception we allocated at"
179 " the beginning of program time, so while the stack trace will"
180 " be wrong, at least you get some useful feedback");
183 jthrowable exception=
static_cast<jthrowable
>(
184 env->NewObject(cls, constructor, errorMessage));
185 env->DeleteLocalRef(errorMessage);
190 mOutOfMemoryErrorSingleton =
static_cast<jthrowable
>(env->NewGlobalRef(exception));
191 if (!mOutOfMemoryErrorSingleton || env->ExceptionCheck())
194 env->DeleteLocalRef(cls);
195 cls = env->FindClass(
"com/avpkit/ferry/JNIPointerReference");
196 if (!cls || env->ExceptionCheck())
199 mJNIPointerReference_class=env->NewWeakGlobalRef(cls);
200 if (!mJNIPointerReference_class || env->ExceptionCheck())
204 mJNIPointerReference_setPointer_mid = env->GetMethodID(cls,
"setPointer",
206 if (!mJNIPointerReference_setPointer_mid || env->ExceptionCheck())
209 mJNIPointerReference_getPointer_mid = env->GetMethodID(cls,
"getPointer",
211 if (!mJNIPointerReference_getPointer_mid || env->ExceptionCheck())
214 env->DeleteLocalRef(cls);
216 cls = env->FindClass(
"com/avpkit/ferry/JNIThreadProxy");
217 if (!cls || env->ExceptionCheck())
220 mThread_class=env->NewWeakGlobalRef(cls);
221 if (!mThread_class || env->ExceptionCheck())
225 mThread_currentThread_mid = env->GetStaticMethodID(cls,
226 "currentThread",
"()Ljava/lang/Thread;");
227 if (!mThread_currentThread_mid || env->ExceptionCheck())
230 mThread_isInterrupted_mid = env->GetMethodID(cls,
231 "isInterrupted",
"()Z");
232 if (!mThread_isInterrupted_mid || env->ExceptionCheck())
234 mThread_interrupt_mid = env->GetMethodID(cls,
236 if (!mThread_interrupt_mid || env->ExceptionCheck())
239 env->DeleteLocalRef(cls);
242 processCallbacks(&mInitializationCallbacks, mCachedVM,
true);
247 VSJNI_MemoryManagerInit(mCachedVM);
253 JNIHelper :: waitForDebugger(JNIEnv* env)
257 jstring jDebugKey = 0;
258 jstring jDebugVal = 0;
259 const char* debugKey =
"com.avpkit.ferry.WaitForDebugger";
260 const char* debugVal = 0;
264 cls = env->FindClass(
"java/lang/System");
266 throw std::runtime_error(
"could not find System class");
268 jmethodID getProperty = env->GetStaticMethodID(cls,
"getProperty",
269 "(Ljava/lang/String;)Ljava/lang/String;");
271 throw std::runtime_error(
"could not find getProperty class");
273 jDebugKey = env->NewStringUTF(debugKey);
275 throw std::runtime_error(
"could not create java string for the debug key");
277 jDebugVal = (jstring) env->CallStaticObjectMethod(cls, getProperty, jDebugKey);
280 debugVal = env->GetStringUTFChars(jDebugVal, 0);
281 if (debugVal && *debugVal)
285 int32_t pid = GET_PROCESS_ID();
287 std::cerr <<
"Process " << pid <<
" waiting for a debugger. Please attach and set \"JNIHelper::sDebuggerAttached\" to true"
288 <<
" (" << __FILE__ <<
":" << __LINE__+1 <<
")" << std::endl;
289 while (!sDebuggerAttached) ;
293 catch (std::exception e)
295 std::cerr <<
"Got exception while checking for debugger: "
302 env->DeleteLocalRef(jDebugKey);
304 if (jDebugVal && debugVal)
305 env->ReleaseStringUTFChars(jDebugVal, debugVal);
308 env->DeleteLocalRef(cls);
312 JNIHelper :: registerInitializationCallback(
313 CallbackFunc callback,
322 addCallback(&mInitializationCallbacks, callback, closure);
327 callback(mCachedVM, closure);
333 JNIHelper :: registerTerminationCallback(
334 CallbackFunc callback,
339 addCallback(&mTerminationCallbacks, callback, closure);
350 JNIHelper :: getPointer(jobject pointerRef)
352 JNIEnv *env = this->getEnv();
356 if (env->ExceptionCheck())
359 jlong pointerVal = env->CallLongMethod(pointerRef,
360 mJNIPointerReference_getPointer_mid);
372 void *retval = (
void*)(
size_t)pointerVal;
378 JNIHelper :: setPointer(jobject pointerRef,
void *newVal)
380 JNIEnv *env = this->getEnv();
383 if (env->ExceptionCheck())
388 jlong newPointerVal = (jlong)(
size_t)newVal;
390 jlong pointerVal = env->CallLongMethod(pointerRef,
391 mJNIPointerReference_setPointer_mid, newPointerVal);
393 void *retval = (
void*)(
size_t)pointerVal;
399 JNIHelper :: getEnv()
406 mCachedVM->GetEnv((
void**)(
void*)&env, mVersion);
408 mCachedVM->AttachCurrentThread((
void**)(
void*)&env, 0);
415 JNIHelper :: getJNIVersion()
421 JNIHelper :: newLocalRef(jobject ref)
424 JNIEnv *env = this->getEnv();
427 if (env->ExceptionCheck())
430 retval = env->NewLocalRef(ref);
432 throw std::runtime_error(
"could not get JVM LocalRef");
433 if (env->ExceptionCheck()) {
434 env->DeleteLocalRef(retval);
435 throw std::runtime_error(
"could not get JVM LocalRef");
441 JNIHelper :: deleteLocalRef(jobject ref)
443 JNIEnv *env = this->getEnv();
445 throw std::runtime_error(
"attempted to delete LocalRef without JVM");
446 env->DeleteLocalRef(ref);
450 JNIHelper :: newGlobalRef(jobject ref)
453 JNIEnv *env = this->getEnv();
456 if (env->ExceptionCheck())
459 retval = env->NewGlobalRef(ref);
461 throw std::runtime_error(
"could not get JVM GlobalRef");
462 if (env->ExceptionCheck())
464 env->DeleteGlobalRef(retval);
465 throw std::runtime_error(
"could not get JVM GlobalRef");
471 JNIHelper :: deleteGlobalRef(jobject ref)
473 JNIEnv *env = this->getEnv();
475 throw std::runtime_error(
"attempted to delete GlobalRef without JVM");
476 env->DeleteGlobalRef(ref);
480 JNIHelper :: newWeakGlobalRef(jobject ref)
484 JNIEnv *env = this->getEnv();
487 if (env->ExceptionCheck())
491 retval = env->NewWeakGlobalRef(ref);
493 throw std::runtime_error(
"could not get JVM WeakGlobal ref");
494 if (env->ExceptionCheck())
496 env->DeleteWeakGlobalRef(retval);
497 throw std::runtime_error(
"could not get JVM WeakGlobal ref");
503 JNIHelper :: deleteWeakGlobalRef(jweak ref)
507 JNIEnv *env = this->getEnv();
509 throw std::runtime_error(
"attempted to delete WeakGlobalRef without JVM");
510 env->DeleteWeakGlobalRef(ref);
522 JNIEnv *env = this->getEnv();
526 if (env->ExceptionCheck())
532 cls = env->FindClass(
"java/lang/OutOfMemoryError");
535 int retval = env->ThrowNew(cls,
"out of native memory");
536 env->DeleteLocalRef(cls);
541 if (!mOutOfMemoryErrorSingleton)
543 env->Throw(mOutOfMemoryErrorSingleton);
547 JNIHelper :: isInterrupted()
549 JNIEnv * env = this->getEnv();
552 if (env->ExceptionCheck())
554 if (!mThread_class ||
555 !mThread_isInterrupted_mid ||
556 !mThread_currentThread_mid)
561 jclass cls =
static_cast<jclass
>(env->NewLocalRef(mThread_class));
565 jobject thread = env->CallStaticObjectMethod(
567 mThread_currentThread_mid);
568 env->DeleteLocalRef(cls);
569 if (!thread || env->ExceptionCheck())
571 jboolean result = env->CallBooleanMethod(thread,
572 mThread_isInterrupted_mid);
573 env->DeleteLocalRef(thread);
574 if (env->ExceptionCheck())
576 if (result != JNI_FALSE)
582 JNIHelper :: interrupt()
584 JNIEnv * env = this->getEnv();
587 if (env->ExceptionCheck())
589 if (!mThread_class ||
590 !mThread_interrupt_mid ||
591 !mThread_currentThread_mid)
596 jclass cls =
static_cast<jclass
>(env->NewLocalRef(mThread_class));
600 jobject thread = env->CallStaticObjectMethod(
602 mThread_currentThread_mid);
603 env->DeleteLocalRef(cls);
604 if (!thread || env->ExceptionCheck())
606 env->CallVoidMethod(thread,
607 mThread_interrupt_mid);
608 env->DeleteLocalRef(thread);
613 JNIHelper :: isInterruptedException(jthrowable exception)
615 JNIEnv * env = this->getEnv();
618 if (env->ExceptionCheck())
620 if (!mInterruptedException_class)
624 jclass cls =
static_cast<jclass
>(env->NewLocalRef(mInterruptedException_class));
628 jboolean retval = env->IsInstanceOf(
630 static_cast<jclass
>(cls)
632 env->DeleteLocalRef(cls);
633 if (retval != JNI_FALSE)
VS_API_FERRY void throwOutOfMemoryError()
WARNING: Do not use logging in this class, and do not set any static file variables to values other t...