Currently, swift-java can crash runtime for Android API 28-30, if you try to use the JavaVirtualMachine class. This means that any JExtract generated sources (JNI mode) only works on API 31+, since we rely on JavaVirtualMachine.shared().environment().
This is due to the fact that Android first added official support for the JavaVM JNI functions, such as JNI_GetCreatedJavaVMs, in API 31+.
We rely on these methods for getting the active JavaVM, through for example JavaVirtualMachine.shared().
We have a shim for these JNI functions in https://github.com/swiftlang/swift-java/blob/main/Sources/CSwiftJavaJNI/AndroidSupport.cpp - this works on API 31+, because those Android versions have the libnativehelper.so. Previous versions did not. We cannot load libart.so or libdvm.so instead, since previous Android versions restricted dynamically loading these "private" libraries.
It seems like the recommended solution to this issue on Android, is to tap into JNI_OnLoad and store the VM from there. This would mean that we would need to update the shared VM at runtime:
|
private static let sharedJVM: LockedState<JavaVirtualMachine?> = .init(initialState: nil) |
We need to figure out which library to dynamically load, that contains the JNI_OnLoad and can set the shared VM. My concern is since we already statically link the SwiftJava package (the generated sources depend on it), it would not be OK to just also dynamically load it on the Java side, but I am not sure.
An alternative solution could be (if this works in practice):
- Define a function in
SwiftJava with @_silgen_name("_swift_java_setSharedVM"), which takes in a JavaVM and updates the shared one.
- Call that function in
JNI_OnLoad from the already dynamically loaded SwiftRuntimeFunctions target to set the shared VM.
Currently,
swift-javacan crash runtime for Android API 28-30, if you try to use theJavaVirtualMachineclass. This means that any JExtract generated sources (JNI mode) only works on API 31+, since we rely onJavaVirtualMachine.shared().environment().This is due to the fact that Android first added official support for the JavaVM JNI functions, such as
JNI_GetCreatedJavaVMs, in API 31+.We rely on these methods for getting the active JavaVM, through for example
JavaVirtualMachine.shared().We have a shim for these JNI functions in https://github.com/swiftlang/swift-java/blob/main/Sources/CSwiftJavaJNI/AndroidSupport.cpp - this works on API 31+, because those Android versions have the
libnativehelper.so. Previous versions did not. We cannot loadlibart.soorlibdvm.soinstead, since previous Android versions restricted dynamically loading these "private" libraries.It seems like the recommended solution to this issue on Android, is to tap into
JNI_OnLoadand store the VM from there. This would mean that we would need to update the shared VM at runtime:swift-java/Sources/SwiftJava/JavaKitVM/JavaVirtualMachine.swift
Line 223 in cc0ff8f
We need to figure out which library to dynamically load, that contains the
JNI_OnLoadand can set the shared VM. My concern is since we already statically link theSwiftJavapackage (the generated sources depend on it), it would not be OK to just also dynamically load it on the Java side, but I am not sure.An alternative solution could be (if this works in practice):
SwiftJavawith@_silgen_name("_swift_java_setSharedVM"), which takes in a JavaVM and updates the shared one.JNI_OnLoadfrom the already dynamically loadedSwiftRuntimeFunctionstarget to set the shared VM.