android-go/examples/dex/dex_android.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)
}