github.com/luchsh/agentlib.go@v0.0.0-20221115155834-ffd0caec4d72/jgo/jvm.go (about) 1 // Copyright 2020 chuanshenglu@gmail.com 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package jgo 16 17 // #include <jni.h> 18 // #include <stdlib.h> 19 import "C" 20 21 import ( 22 "fmt" 23 "runtime" 24 "unsafe" 25 26 "github.com/ClarkGuan/jni" 27 ) 28 29 const ( 30 ptrSize = 8 31 ) 32 33 type JniEnv jni.Env 34 type JVM jni.VM 35 36 func (vm JVM) raw() jni.VM { 37 return jni.VM(vm) 38 } 39 40 func (vm JVM) VM() jni.VM { 41 return vm.raw() 42 } 43 44 func (e JniEnv) raw() jni.Env { 45 return jni.Env(e) 46 } 47 48 func (e JniEnv) Env() jni.Env { 49 return jni.Env(e) 50 } 51 52 func jniGetCreatedJavaVMs() (vms []jni.VM) { 53 l := 128 54 buf := C.malloc(C.size_t(l * ptrSize)) 55 defer C.free(buf) 56 var n C.jsize 57 if 0 == C.JNI_GetCreatedJavaVMs((**C.JavaVM)(buf), C.jsize(l), &n) { 58 for i := C.jsize(0); i < n; i++ { 59 p := uintptr(buf) + uintptr(i)*ptrSize 60 addr := *(*uintptr)(unsafe.Pointer(p)) 61 vms = append(vms, jni.VM(addr)) 62 } 63 } 64 return 65 } 66 67 // Create a Java VM 68 func jniCreateJavaVM(args []string) (vmp jni.VM, envp jni.Env) { 69 vmargs := C.malloc(C.sizeof_JavaVMOption) 70 defer C.free(vmargs) 71 jva := (*C.JavaVMInitArgs)(vmargs) 72 jva.version = jni.JNI_VERSION_1_6 73 jva.nOptions = 0 74 jva.ignoreUnrecognized = jni.JNI_TRUE 75 if len(args) > 0 { 76 opts := C.malloc(C.size_t(C.sizeof_JavaVMOption * len(args))) 77 defer C.free(opts) 78 jva.nOptions = C.jint(len(args)) 79 jva.options = (*C.JavaVMOption)(opts) 80 for i, a := range args { 81 o := (*C.JavaVMOption)(unsafe.Pointer(uintptr(opts) + uintptr(i)*C.sizeof_JavaVMOption)) 82 o.optionString = C.CString(a) 83 } 84 } 85 vmargs = unsafe.Pointer(jva) 86 87 e := C.JNI_CreateJavaVM((**C.JavaVM)(unsafe.Pointer(&vmp)), (*unsafe.Pointer)(unsafe.Pointer(&envp)), vmargs) 88 if e != jni.JNI_OK { 89 fmt.Printf("Failed to create Java VM, error=%d (%s)\n", e, describeJNIError(int(e))) 90 return 0, 0 91 } 92 93 return vmp, envp 94 } 95 96 // Lock the target OS thread to prevent goroutine scheduling 97 func (vm JVM) jniRun(f func(JniEnv)) { 98 if f != nil { 99 env, res := vm.raw().AttachCurrentThread() 100 if res != 0 { 101 panic("Failed to attach current thread") 102 } 103 runtime.LockOSThread() 104 defer runtime.UnlockOSThread() 105 f(JniEnv(env)) 106 } 107 } 108 109 var jniErrorTextMap = map[int]string{ 110 jni.JNI_ERR: "JNI_ERR", 111 jni.JNI_EDETACHED: "JNI_EDETACHED", 112 jni.JNI_EVERSION: "JNI_EVERSION", 113 jni.JNI_ENOMEM: "JNI_ENOMEM", 114 jni.JNI_EEXIST: "JNI_EEXIST", 115 jni.JNI_EINVAL: "JNI_EINVAL", 116 } 117 118 func describeJNIError(ev int) string { 119 if tv, ok := jniErrorTextMap[ev]; ok { 120 return tv 121 } 122 return "Unknown error" 123 }