207 lines
5.9 KiB
Go
207 lines
5.9 KiB
Go
|
package main
|
||
|
|
||
|
/*
|
||
|
#cgo LDFLAGS: -landroid -llog
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <jni.h>
|
||
|
#include <android/log.h>
|
||
|
|
||
|
static jobject gClassLoader;
|
||
|
static jmethodID gFindClassMethod;
|
||
|
|
||
|
jobject
|
||
|
CreateObject(JNIEnv* env, jclass cls) {
|
||
|
jmethodID init = (*env)->GetMethodID(env, cls, "<init>", "()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 <init>");
|
||
|
mid = (*env)->GetMethodID(env, cls, "<init>", "(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 <init>");
|
||
|
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 <init>");
|
||
|
// mid = (*env)->GetMethodID(env, cls, "<init>", "()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)
|
||
|
}
|