package passgo /* #cgo LDFLAGS: -landroid -llog #include #include "jni_android.h" */ import "C" import ( "errors" "fmt" "log" "runtime" "unsafe" "sync" ) var theJVM *C.JavaVM type JNIEnv = C.JNIEnv func SetJVM(jvm, context uintptr) { log.Print("set theJVM") theJVM = (*C.JavaVM)(unsafe.Pointer(jvm)) RunInJVM(func(env *C.JNIEnv) { C.SetLoader(env, (C.jobject)(context)) }) } func FindClass(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 JniCallVoidMethod(env *C.JNIEnv, obj C.jobject, methodID C.jmethodID) { C.CallVoidMethod(env, obj, methodID) } func JniCallVoidMethod1(env *C.JNIEnv, obj C.jobject, methodID C.jmethodID, arg uintptr) { C.CallVoidMethod1(env, obj, methodID, C.jobject(unsafe.Pointer(arg))) } 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 CreateObject(env *C.JNIEnv, cls C.jclass) C.jobject { return C.CreateObject(env, (C.jclass)(cls)) } type PGP C.jobject func InitPgpConnect(env uintptr) { C.InitPgpConnect((*C.JNIEnv)(unsafe.Pointer(env))) } //func NewPgpConnect(env uintptr, act uintptr) PGP { // return (PGP)(C.NewPgpConnect((*C.JNIEnv)(unsafe.Pointer(env)), (C.jobject)(unsafe.Pointer(act)))) //} var ( fragChans map[int]chan string chmux sync.Mutex chint int ) func (p PGP) GetId() (string, error) { ch := make(chan string) chmux.Lock() if fragChans == nil { fragChans = make(map[int]chan string) } fragChans[chint] = ch curint := chint chint++ chmux.Unlock() RunInJVM(func(env *JNIEnv) { C.GetId(env, (C.jobject)(p), C.int(curint)) }) log.Printf("GetId(): waiting for response") switch x := <-ch; { case x == "": log.Printf("GetId(): failed") return "", fmt.Errorf("GetId failed") default: log.Printf("GetId(): got %s", x) return x, nil } } func (p PGP) Decrypt(data string) (string, error) { ch := make(chan string) chmux.Lock() if fragChans == nil { fragChans = make(map[int]chan string) } fragChans[chint] = ch curint := chint chint++ chmux.Unlock() cdata := C.CString(data) defer C.free(unsafe.Pointer(cdata)) RunInJVM(func(env *JNIEnv) { C.Decrypt(env, (C.jobject)(p), (*C.char)(unsafe.Pointer(cdata)), (C.int)(len(data)), C.int(curint)) }) switch x := <-ch; { case x == "": return "", fmt.Errorf("Decryption failed") default: return x, nil } } func (p PGP) Encrypt(id, data string) (string, error) { ch := make(chan string) chmux.Lock() if fragChans == nil { fragChans = make(map[int]chan string) } fragChans[chint] = ch curint := chint chint++ chmux.Unlock() cid := C.CString(id) defer C.free(unsafe.Pointer(cid)) cdata := C.CString(data) defer C.free(unsafe.Pointer(cdata)) RunInJVM(func(env *JNIEnv) { C.Encrypt(env, (C.jobject)(p), (*C.char)(unsafe.Pointer(cid)), (C.int)(len(id)), (*C.char)(unsafe.Pointer(cdata)), (C.int)(len(data)), C.int(curint)) }) switch x := <-ch; { case x == "": return "", fmt.Errorf("Encryption failed") default: return x, nil } } func (p PGP) Clip(data string) { cdata := C.CString(data) defer C.free(unsafe.Pointer(cdata)) RunInJVM(func(env *JNIEnv) { C.Clip(env, (C.jobject)(p), (*C.char)(unsafe.Pointer(cdata)), (C.int)(len(data))) }) } 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) } //export activityResult func activityResult(env *C.JNIEnv, class C.jclass, request, result C.jint) { log.Printf("activityResult (%d): %d", request, result) } //export goStringResult func goStringResult(env *C.JNIEnv, class C.jclass, request C.jint, str *C.char) { fragChans[int(request)] <- C.GoString(str) C.free(unsafe.Pointer(str)) chmux.Lock() delete(fragChans, int(request)) chmux.Unlock() }