bind/java: initialize seq machinery from Java
This ensures that the java bindings are ready before any calls are made by user code. As a bonus, the JNIEnv* is from the Seq class so I believe no tricks are required to find the right class loader. Fixes golang/go#10903. Change-Id: I33b3b39cef6cc2da36e271de882ba8d26610ea34 Reviewed-on: https://go-review.googlesource.com/10296 Reviewed-by: Elias Naur <elias.naur@gmail.com> Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
This commit is contained in:
parent
d2634ce9c5
commit
64c20ce93d
|
@ -66,6 +66,12 @@ public class Seq {
|
||||||
return tracker.get(refnum);
|
return tracker.get(refnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
initSeq();
|
||||||
|
}
|
||||||
|
|
||||||
|
static native void initSeq();
|
||||||
|
|
||||||
// Informs the Go ref tracker that Java is done with this ref.
|
// Informs the Go ref tracker that Java is done with this ref.
|
||||||
static native void destroyRef(int refnum);
|
static native void destroyRef(int refnum);
|
||||||
|
|
||||||
|
|
|
@ -12,5 +12,7 @@ package java
|
||||||
// Init initializes communication with Java.
|
// Init initializes communication with Java.
|
||||||
// Typically called from the Start callback in app.Run.
|
// Typically called from the Start callback in app.Run.
|
||||||
func Init() {
|
func Init() {
|
||||||
initSeq()
|
close(running)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var running = make(chan struct{})
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
// Copyright 2015 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !android
|
|
||||||
|
|
||||||
package java
|
|
||||||
|
|
||||||
func initSeq() {}
|
|
|
@ -167,12 +167,8 @@ static void describe_exception(JNIEnv* 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) {
|
static jfieldID find_field(JNIEnv *env, const char *class_name, const char *field_name, const char *field_type) {
|
||||||
jclass clazz = find_class_fn(env, class_name);
|
jclass clazz = (*env)->FindClass(env, class_name);
|
||||||
if (clazz == NULL) {
|
if (clazz == NULL) {
|
||||||
describe_exception(env);
|
describe_exception(env);
|
||||||
LOG_FATAL("cannot find %s", class_name);
|
LOG_FATAL("cannot find %s", class_name);
|
||||||
|
@ -188,7 +184,7 @@ static jfieldID find_field(JNIEnv *env, const char *class_name, const char *fiel
|
||||||
}
|
}
|
||||||
|
|
||||||
static jclass find_class(JNIEnv *env, const char *class_name) {
|
static jclass find_class(JNIEnv *env, const char *class_name) {
|
||||||
jclass clazz = find_class_fn(env, class_name);
|
jclass clazz = (*env)->FindClass(env, class_name);
|
||||||
if (clazz == NULL) {
|
if (clazz == NULL) {
|
||||||
describe_exception(env);
|
describe_exception(env);
|
||||||
LOG_FATAL("cannot find %s", class_name);
|
LOG_FATAL("cannot find %s", class_name);
|
||||||
|
@ -197,19 +193,8 @@ static jclass find_class(JNIEnv *env, const char *class_name) {
|
||||||
return (*env)->NewGlobalRef(env, clazz);
|
return (*env)->NewGlobalRef(env, clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_seq(void *javavm, void *classfinder) {
|
JNIEXPORT void JNICALL
|
||||||
JavaVM *vm = (JavaVM*)javavm;
|
Java_go_Seq_initSeq(JNIEnv *env, jclass clazz) {
|
||||||
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) != JNI_OK) {
|
|
||||||
LOG_FATAL("cannot attach to current_vm");
|
|
||||||
}
|
|
||||||
} else if (res != JNI_OK) {
|
|
||||||
LOG_FATAL("bad vm env: %d", res);
|
|
||||||
}
|
|
||||||
memptr_id = find_field(env, "go/Seq", "memptr", "J");
|
memptr_id = find_field(env, "go/Seq", "memptr", "J");
|
||||||
receive_refnum_id = find_field(env, "go/Seq$Receive", "refnum", "I");
|
receive_refnum_id = find_field(env, "go/Seq$Receive", "refnum", "I");
|
||||||
receive_handle_id = find_field(env, "go/Seq$Receive", "handle", "I");
|
receive_handle_id = find_field(env, "go/Seq$Receive", "handle", "I");
|
||||||
|
@ -219,14 +204,10 @@ void init_seq(void *javavm, void *classfinder) {
|
||||||
// its class info, because finding the jbyteArray class ("[B") using
|
// its class info, because finding the jbyteArray class ("[B") using
|
||||||
// find_class_fn or JNIEnv's FindClass does not work on android-L.
|
// find_class_fn or JNIEnv's FindClass does not work on android-L.
|
||||||
jbyteArray a = (*env)->NewByteArray(env, 0);
|
jbyteArray a = (*env)->NewByteArray(env, 0);
|
||||||
jclass clazz = (*env)->GetObjectClass(env, a);
|
jclass bclazz = (*env)->GetObjectClass(env, a);
|
||||||
jbytearray_clazz = (*env)->NewGlobalRef(env, clazz);
|
jbytearray_clazz = (*env)->NewGlobalRef(env, bclazz);
|
||||||
|
|
||||||
LOG_INFO("loaded go/Seq");
|
LOG_INFO("loaded go/Seq");
|
||||||
|
|
||||||
if (res == JNI_EDETACHED) {
|
|
||||||
(*vm)->DetachCurrentThread(vm);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
|
|
|
@ -15,7 +15,6 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/mobile/app"
|
|
||||||
"golang.org/x/mobile/bind/seq"
|
"golang.org/x/mobile/bind/seq"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,6 +25,7 @@ const debug = false
|
||||||
// Send is called by Java to send a request to run a Go function.
|
// Send is called by Java to send a request to run a Go function.
|
||||||
//export Send
|
//export Send
|
||||||
func Send(descriptor string, code int, req *C.uint8_t, reqlen C.size_t, res **C.uint8_t, reslen *C.size_t) {
|
func Send(descriptor string, code int, req *C.uint8_t, reqlen C.size_t, res **C.uint8_t, reslen *C.size_t) {
|
||||||
|
<-running
|
||||||
fn := seq.Registry[descriptor][code]
|
fn := seq.Registry[descriptor][code]
|
||||||
if fn == nil {
|
if fn == nil {
|
||||||
panic(fmt.Sprintf("invalid descriptor(%s) and code(0x%x)", descriptor, code))
|
panic(fmt.Sprintf("invalid descriptor(%s) and code(0x%x)", descriptor, code))
|
||||||
|
@ -78,13 +78,6 @@ func init() {
|
||||||
res.out = make(map[int32]*seq.Buffer)
|
res.out = make(map[int32]*seq.Buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initSeq() {
|
|
||||||
vm := app.GetConfig().JavaVM()
|
|
||||||
classFinder := app.GetConfig().ClassFinder()
|
|
||||||
|
|
||||||
C.init_seq(vm, classFinder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func seqToBuf(bufptr **C.uint8_t, lenptr *C.size_t, buf *seq.Buffer) {
|
func seqToBuf(bufptr **C.uint8_t, lenptr *C.size_t, buf *seq.Buffer) {
|
||||||
if debug {
|
if debug {
|
||||||
fmt.Printf("seqToBuf tag 1, len(buf.Data)=%d, *lenptr=%d\n", len(buf.Data), *lenptr)
|
fmt.Printf("seqToBuf tag 1, len(buf.Data)=%d, *lenptr=%d\n", len(buf.Data), *lenptr)
|
||||||
|
|
Loading…
Reference in New Issue