golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
123.85k stars 17.65k forks source link

x/mobile/cmd/gomobile: RunOnJVM is not available from init functions #25255

Open hajimehoshi opened 6 years ago

hajimehoshi commented 6 years ago

In my library, JNI functions are called from Go side. JVM is accessed via a global C variable current_vm. I admit depending this variable is not a good way, but there is no other way to access JNI from Go. Actual code is https://github.com/hajimehoshi/ebiten/blob/master/internal/jni/jni_android.go

I realized that current_vm is not initialized yet when init functions are called. IIUC, current_vm is initialized at SetCurrentContext when the activity's onCreate is called, and this onCreate is called after all init functions are called and before main is called.

Wouldn't it be possible to make JVM available even from init functions? For gomobile-bind, as init functions are automatically called before calling SetCurrentContext, then it might be impossible. If this is impossible, is there other way to call JNI functions from Go side?

As for iOS, Objective-C binding via cgo is available and there is not such problem.

hajimehoshi commented 6 years ago

https://github.com/golang/mobile/commit/56e3592fa7a0582e84d783579d2eb8e6114e0312 makes it impossible to access current_vm, which means that calling JNI functions directly is no longer available... :-/

hajimehoshi commented 6 years ago

The above problem was solved https://github.com/golang/go/issues/26815

BTW, to use JNI in init() function, I also tried to use JNI_GetCreatedJavaVMs, but failed due to the below message. Adding #cgo LDFLAGS: -ljvm didn't help since libjvm couldn't be found.

gomobile: go build -buildmode=c-shared -o=/var/folders/b7/w11sqqrx7kx6fqfbn24wdsmh0000gn/T/gomobile-work-277134993/android/src/main/jniLibs/armeabi-v7a/libgojni.so gobind failed: exit status 2                                             
# github.com/hajimehoshi/ebiten/internal/devicescale
../ebiten/internal/devicescale/impl_android.go:25: error: undefined reference to 'JNI_GetCreatedJavaVMs'
clang60: error: linker command failed with exit code 1 (use -v to see invocation)
hajimehoshi commented 4 years ago

My understanding is that Seq.setContext (gomobile-bind case) tries to initialize the context and invokes a Go function, but this invocation provokes all the init function before setting the context. Then, in order to solve this issue, we'd need to set the context without Go. Is that correct?

CC @hyangah @timcooijmans

timcooijmans commented 3 years ago

Sorry I missed this issue.

Yes that's the way it works at the moment. This change was needed because older versions of gomobile used reflection that was blacklisted by Android. Do you really have to use init() functions? Can't you use your own initX() functions?

You don't have to bind to an activity, you can also do it from a Service or even from the Application. But I guess that doesn't solve your problem.

hajimehoshi commented 3 years ago

Hi,

Do you really have to use init() functions? Can't you use your own initX() functions?

I might not, but other people might. I'm developing a library working with gomobile. If a function uses RunOnJVM, the function can be called from main and after but not from init, and this is not a good user experience.

hajimehoshi commented 11 months ago

https://github.com/golang/mobile/blob/35478a0c49da882188b186a3893d45be6ff74327/app/android.go#L72