bind/java: use the class loader cached during JNI_OnLoad call.

This allows the application class loader to be used when
the bind/java package or other part of JNI dynamically
loads java classes from a non-Java thread.

http://developer.android.com/training/articles/perf-jni.html#faq_FindClass

Fixes golang/go#10668.

Change-Id: I44df3a9362617fa6dd26ddf88247e4fdaee7c7e8
Reviewed-on: https://go-review.googlesource.com/9732
Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
Hyang-Ah (Hana) Kim
2015-05-06 03:41:18 +00:00
committed by Hyang-Ah Hana Kim
parent 696139153c
commit 601608a0e0
6 changed files with 74 additions and 22 deletions
+21 -6
View File
@@ -159,15 +159,28 @@ static void unpin_arrays(JNIEnv *env, mem *m) {
m->pinned = NULL;
}
static void describe_exception(JNIEnv* env) {
jthrowable exc = (*env)->ExceptionOccurred(env);
if (exc) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
}
// find_class_fn finds a class with the given name using the app class loader.
// It is implemented in the app package and is initialized during the init_seq call.
static jclass (*find_class_fn)(JNIEnv*, const char*);
static jfieldID find_field(JNIEnv *env, const char *class_name, const char *field_name, const char *field_type) {
jclass clazz = (*env)->FindClass(env, class_name);
jclass clazz = find_class_fn(env, class_name);
if (clazz == NULL) {
describe_exception(env);
LOG_FATAL("cannot find %s", class_name);
return NULL;
}
jfieldID id = (*env)->GetFieldID(env, clazz, field_name , field_type);
if(id == NULL) {
describe_exception(env);
LOG_FATAL("no %s/%s field", field_name, field_type);
return NULL;
}
@@ -175,26 +188,28 @@ static jfieldID find_field(JNIEnv *env, const char *class_name, const char *fiel
}
static jclass find_class(JNIEnv *env, const char *class_name) {
jclass clazz = (*env)->FindClass(env, class_name);
jclass clazz = find_class_fn(env, class_name);
if (clazz == NULL) {
describe_exception(env);
LOG_FATAL("cannot find %s", class_name);
return NULL;
}
return (*env)->NewGlobalRef(env, clazz);
}
void init_seq(void *javavm) {
void init_seq(void *javavm, void *classfinder) {
JavaVM *vm = (JavaVM*)javavm;
find_class_fn = (jclass (*)(JNIEnv*, const char*))classfinder;
JNIEnv *env;
int res = (*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6);
if (res == JNI_EDETACHED) {
if ((*vm)->AttachCurrentThread(vm, &env, NULL) != 0) {
if ((*vm)->AttachCurrentThread(vm, &env, NULL) != JNI_OK) {
LOG_FATAL("cannot attach to current_vm");
}
} else if (res != 0) {
} else if (res != JNI_OK) {
LOG_FATAL("bad vm env: %d", res);
}
memptr_id = find_field(env, "go/Seq", "memptr", "J");
receive_refnum_id = find_field(env, "go/Seq$Receive", "refnum", "I");
receive_handle_id = find_field(env, "go/Seq$Receive", "handle", "I");
+5 -1
View File
@@ -82,7 +82,11 @@ func initSeq() {
vm := app.State.(interface {
JavaVM() unsafe.Pointer
}).JavaVM()
C.init_seq(vm)
classFinder := app.State.(interface {
ClassFinder() unsafe.Pointer
}).ClassFinder()
C.init_seq(vm, classFinder)
}
func seqToBuf(bufptr **C.uint8_t, lenptr *C.size_t, buf *seq.Buffer) {
+1 -1
View File
@@ -2,4 +2,4 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
void init_seq(void* vm);
void init_seq(void* vm, void* classfinder);