package main /* #cgo LDFLAGS: -landroid -llog #include #include #include static jobject gClassLoader; static jmethodID gFindClassMethod; jobject CreateObject(JNIEnv* env, jclass cls) { jmethodID init = (*env)->GetMethodID(env, cls, "", "()V"); return (*env)->NewObject(env, cls, init); } jmethodID GetMethodID(JNIEnv *env, jclass cls, const char *name, const char *sig) { return (*env)->GetMethodID(env, cls, name, sig); } jclass FindClass(JNIEnv* env, char* name) { jstring strClassName = (*env)->NewStringUTF(env, name); return (*env)->CallObjectMethod(env, gClassLoader, gFindClassMethod, strClassName); } void SetupJVM(JNIEnv* env, jobject context, void* buf, int len) { jclass cls = (*env)->GetObjectClass(env, context); jmethodID mid = (*env)->GetMethodID(env, cls, "getClassLoader", "()Ljava/lang/ClassLoader;"); jobject loader = (*env)->CallObjectMethod(env, context, mid); gClassLoader = (*env)->NewGlobalRef(env, loader); cls = (*env)->GetObjectClass(env, loader); gFindClassMethod = (*env)->GetMethodID(env, cls, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;"); __android_log_write(ANDROID_LOG_DEBUG, "gio", "Looking for InMemoryDexClassLoader"); cls = (*env)->FindClass(env, "dalvik/system/InMemoryDexClassLoader"); if (cls == NULL) { __android_log_write(ANDROID_LOG_DEBUG, "gio", "not found"); return; } __android_log_write(ANDROID_LOG_DEBUG, "gio", "NewDirectByteBuffer"); jobject bbuf = (*env)->NewDirectByteBuffer(env, buf, (jlong)len); if (bbuf == NULL) { __android_log_write(ANDROID_LOG_DEBUG, "gio", "failed"); return; } __android_log_write(ANDROID_LOG_DEBUG, "gio", "looking for "); mid = (*env)->GetMethodID(env, cls, "", "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); if (mid == NULL) { __android_log_write(ANDROID_LOG_DEBUG, "gio", "not found"); return; } __android_log_write(ANDROID_LOG_DEBUG, "gio", "calling "); jobject dexLoader = (*env)->NewObject(env, cls, mid, bbuf, gClassLoader); // make the dexLoader our new class loader gClassLoader = (*env)->NewGlobalRef(env, dexLoader); } // __android_log_write(ANDROID_LOG_DEBUG, "gio", "looking for AClass"); // cls = FindClass(env, "st/wow/git/dex/AClass"); // if (cls == NULL) { // __android_log_write(ANDROID_LOG_DEBUG, "gio", "not found"); // return; // } // // __android_log_write(ANDROID_LOG_DEBUG, "gio", "calling CreateObject"); // jobject obj = CreateObject(env, cls); // if (obj == NULL) { // __android_log_write(ANDROID_LOG_DEBUG, "gio", "failed"); // return; // } // // __android_log_write(ANDROID_LOG_DEBUG, "gio", "looking for "); // mid = (*env)->GetMethodID(env, cls, "", "()V"); // if (mid == NULL) { // __android_log_write(ANDROID_LOG_DEBUG, "gio", "not found"); // return; // } // __android_log_write(ANDROID_LOG_DEBUG, "gio", "creating object"); // obj = (*env)->NewObject(env, cls, mid); // if (obj == NULL) { // __android_log_write(ANDROID_LOG_DEBUG, "gio", "failed"); // return; // } // // __android_log_write(ANDROID_LOG_DEBUG, "gio", "looking for Num"); // mid = (*env)->GetMethodID(env, cls, "Num", "()I"); // if (mid == NULL) { // __android_log_write(ANDROID_LOG_DEBUG, "gio", "not found"); // return; // } // jint val = (*env)->CallIntMethod(env, obj, mid); // __android_log_print(ANDROID_LOG_DEBUG, "gio", "value = %d", val); jint CallIntMethod(JNIEnv *env, jobject obj, jmethodID methodID) { return (*env)->CallIntMethod(env, obj, methodID); } jint GetEnv(JavaVM *vm, JNIEnv **env, jint version) { return (*vm)->GetEnv(vm, (void **)env, version); } jint AttachCurrentThread(JavaVM *vm, JNIEnv **p_env, void *thr_args) { return (*vm)->AttachCurrentThread(vm, p_env, thr_args); } jint DetachCurrentThread(JavaVM *vm) { return (*vm)->DetachCurrentThread(vm); } */ import "C" import ( "errors" "fmt" "runtime" "unsafe" "gioui.org/app" ) var theJVM *C.JavaVM func SetJVM() { h := app.PlatformHandle() theJVM = (*C.JavaVM)(unsafe.Pointer(h.JVM)) dex := MustAsset("java/classes.dex") RunInJVM(func(env *C.JNIEnv) { labchan <- "Set up JVM" C.SetupJVM( env, (C.jobject)(h.Context), unsafe.Pointer(&dex[0]), C.int(len(dex)), ) }) } func CallJNI() { labchan <- "Call JNI" RunInJVM(func(env *C.JNIEnv) { labchan <- "FindClass" cls := JniFindClass(env, "st/wow/git/dex/AClass") labchan <- "GetMethodID" mid := JniGetMethodID(env, cls, "Num", "()I") labchan <- "CreateObject" obj := JniCreateObject(env, cls) val := JniCallIntMethod(env, obj, mid) labchan <- fmt.Sprintf("val = %d", val) }) } func JniFindClass(env *C.JNIEnv, name string) C.jclass { cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) return C.FindClass((*C.JNIEnv)(env), cname) } func JniCreateObject(env *C.JNIEnv, cls C.jclass) C.jobject { return C.CreateObject(env, (C.jclass)(cls)) } func JniCallIntMethod(env *C.JNIEnv, obj C.jobject, methodID C.jmethodID) int { return (int)(C.CallIntMethod(env, obj, methodID)) } func JniGetMethodID(env *C.JNIEnv, cls C.jclass, name, sig string) C.jmethodID { cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) csig := C.CString(sig) defer C.free(unsafe.Pointer(csig)) return C.GetMethodID(env, cls, cname, csig) } func RunInJVM(f func(env *C.JNIEnv)) { runtime.LockOSThread() defer runtime.UnlockOSThread() var env *C.JNIEnv var detach bool if res := C.GetEnv(theJVM, &env, C.JNI_VERSION_1_6); res != C.JNI_OK { if res != C.JNI_EDETACHED { panic(fmt.Errorf("JNI GetEnv failed with error %d", res)) } if C.AttachCurrentThread(theJVM, &env, nil) != C.JNI_OK { panic(errors.New("runInJVM: AttachCurrentThread failed")) } detach = true } if detach { defer func() { C.DetachCurrentThread(theJVM) }() } f(env) }