github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/mobile/internal/mobileinit/ctx_android.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package mobileinit 6 7 /* 8 #include <jni.h> 9 #include <stdlib.h> 10 11 // current_vm is stored to initialize other cgo packages. 12 // 13 // As all the Go packages in a program form a single shared library, 14 // there can only be one JNI_OnLoad function for initialization. In 15 // OpenJDK there is JNI_GetCreatedJavaVMs, but this is not available 16 // on android. 17 JavaVM* current_vm; 18 19 // current_ctx is Android's android.context.Context. May be NULL. 20 jobject current_ctx; 21 22 char* lockJNI(uintptr_t* envp, int* attachedp) { 23 JNIEnv* env; 24 25 if (current_vm == NULL) { 26 return "no current JVM"; 27 } 28 29 *attachedp = 0; 30 switch ((*current_vm)->GetEnv(current_vm, (void**)&env, JNI_VERSION_1_6)) { 31 case JNI_OK: 32 break; 33 case JNI_EDETACHED: 34 if ((*current_vm)->AttachCurrentThread(current_vm, &env, 0) != 0) { 35 return "cannot attach to JVM"; 36 } 37 *attachedp = 1; 38 break; 39 case JNI_EVERSION: 40 return "bad JNI version"; 41 default: 42 return "unknown JNI error from GetEnv"; 43 } 44 45 *envp = (uintptr_t)env; 46 return NULL; 47 } 48 49 char* checkException(uintptr_t jnienv) { 50 jthrowable exc; 51 JNIEnv* env = (JNIEnv*)jnienv; 52 53 if (!(*env)->ExceptionCheck(env)) { 54 return NULL; 55 } 56 57 exc = (*env)->ExceptionOccurred(env); 58 (*env)->ExceptionClear(env); 59 60 jclass clazz = (*env)->FindClass(env, "java/lang/Throwable"); 61 jmethodID toString = (*env)->GetMethodID(env, clazz, "toString", "()Ljava/lang/String;"); 62 jobject msgStr = (*env)->CallObjectMethod(env, exc, toString); 63 return (char*)(*env)->GetStringUTFChars(env, msgStr, 0); 64 } 65 66 void unlockJNI() { 67 (*current_vm)->DetachCurrentThread(current_vm); 68 } 69 */ 70 import "C" 71 72 import ( 73 "errors" 74 "runtime" 75 "unsafe" 76 ) 77 78 // SetCurrentContext populates the global Context object with the specified 79 // current JavaVM instance (vm) and android.context.Context object (ctx). 80 // The android.context.Context object must be a global reference. 81 func SetCurrentContext(vm, ctx unsafe.Pointer) { 82 C.current_vm = (*C.JavaVM)(vm) 83 C.current_ctx = (C.jobject)(ctx) 84 } 85 86 // RunOnJVM runs fn on a new goroutine locked to an OS thread with a JNIEnv. 87 // 88 // RunOnJVM blocks until the call to fn is complete. Any Java 89 // exception or failure to attach to the JVM is returned as an error. 90 // 91 // The function fn takes vm, the current JavaVM*, 92 // env, the current JNIEnv*, and 93 // ctx, a jobject representing the global android.context.Context. 94 func RunOnJVM(fn func(vm, env, ctx uintptr) error) error { 95 errch := make(chan error) 96 go func() { 97 runtime.LockOSThread() 98 defer runtime.UnlockOSThread() 99 100 env := C.uintptr_t(0) 101 attached := C.int(0) 102 if errStr := C.lockJNI(&env, &attached); errStr != nil { 103 errch <- errors.New(C.GoString(errStr)) 104 return 105 } 106 if attached != 0 { 107 defer C.unlockJNI() 108 } 109 110 vm := uintptr(unsafe.Pointer(C.current_vm)) 111 if err := fn(vm, uintptr(env), uintptr(C.current_ctx)); err != nil { 112 errch <- err 113 return 114 } 115 116 if exc := C.checkException(env); exc != nil { 117 errch <- errors.New(C.GoString(exc)) 118 C.free(unsafe.Pointer(exc)) 119 return 120 } 121 errch <- nil 122 }() 123 return <-errch 124 }