package com.oracle.svm.hosted.jdk;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
import org.graalvm.compiler.phases.util.Providers;
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.impl.InternalPlatform;
import com.oracle.svm.core.annotate.AutomaticFeature;
import com.oracle.svm.core.graal.GraalFeature;
import com.oracle.svm.core.jdk.JNIRegistrationUtil;
import com.oracle.svm.core.jdk.PlatformNativeLibrarySupport;
import com.oracle.svm.core.jni.JNIRuntimeAccess;
import com.oracle.svm.hosted.FeatureImpl;
import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl;
import com.oracle.svm.hosted.c.NativeLibraries;
@Platforms({InternalPlatform.PLATFORM_JNI.class})
@AutomaticFeature
class JNIRegistrationJava extends JNIRegistrationUtil implements GraalFeature {
private static final Consumer<DuringAnalysisAccess> CORESERVICES_LINKER = (duringAnalysisAccess -> {
FeatureImpl.DuringAnalysisAccessImpl accessImpl = (FeatureImpl.DuringAnalysisAccessImpl) duringAnalysisAccess;
accessImpl.getNativeLibraries().addDynamicNonJniLibrary("-framework CoreServices");
});
@Override
public void registerGraphBuilderPlugins(Providers providers, Plugins plugins, boolean analysis, boolean hosted) {
JNIRegistrationSupport.singleton().registerNativeLibrary(providers, plugins, System.class, "loadLibrary");
}
@Override
public void duringSetup(DuringSetupAccess a) {
ImageSingletons.add(JNIRegistrationSupport.class, new JNIRegistrationSupport());
}
@Override
public void beforeAnalysis(BeforeAnalysisAccess a) {
NativeLibraries nativeLibraries = ((BeforeAnalysisAccessImpl) a).getNativeLibraries();
JNIRegistrationSupport.singleton().setNativeLibraries(nativeLibraries);
registerForThrowNew(a, "java.lang.Exception", "java.lang.Error", "java.lang.OutOfMemoryError",
"java.lang.RuntimeException", "java.lang.NullPointerException", "java.lang.ArrayIndexOutOfBoundsException",
"java.lang.IllegalArgumentException", "java.lang.IllegalAccessException", "java.lang.IllegalAccessError", "java.lang.InternalError",
"java.lang.NoSuchFieldException", "java.lang.NoSuchMethodException", "java.lang.ClassNotFoundException", "java.lang.NumberFormatException",
"java.lang.NoSuchFieldError", "java.lang.NoSuchMethodError", "java.lang.UnsatisfiedLinkError", "java.lang.StringIndexOutOfBoundsException",
"java.lang.InstantiationException", "java.lang.UnsupportedOperationException",
"java.io.IOException", "java.io.FileNotFoundException", "java.io.SyncFailedException", "java.io.InterruptedIOException",
"java.util.zip.DataFormatException");
JNIRuntimeAccess.register(constructor(a, "java.io.FileNotFoundException", String.class, String.class));
JNIRuntimeAccess.register(clazz(a, "java.lang.Integer"));
JNIRuntimeAccess.register(constructor(a, "java.lang.Integer", int.class));
JNIRuntimeAccess.register(fields(a, "java.lang.Integer", "value"));
JNIRuntimeAccess.register(clazz(a, "java.lang.Boolean"));
JNIRuntimeAccess.register(constructor(a, "java.lang.Boolean", boolean.class));
JNIRuntimeAccess.register(fields(a, "java.lang.Boolean", "value"));
JNIRuntimeAccess.register(method(a, "java.lang.Boolean", "getBoolean", String.class));
JNIRuntimeAccess.register(java.io.FileDescriptor.class);
JNIRuntimeAccess.register(fields(a, "java.io.FileDescriptor", "fd"));
if (isWindows()) {
JNIRuntimeAccess.register(fields(a, "java.io.FileDescriptor", "handle"));
}
if (JavaVersionUtil.JAVA_SPEC >= 11) {
JNIRuntimeAccess.register(fields(a, "java.io.FileDescriptor", "append"));
}
JNIRuntimeAccess.register(fields(a, "java.io.FileOutputStream", "fd"));
JNIRuntimeAccess.register(fields(a, "java.io.FileInputStream", "fd"));
JNIRuntimeAccess.register(java.io.File.class);
JNIRuntimeAccess.register(fields(a, "java.io.File", "path"));
JNIRuntimeAccess.register(byte[].class);
JNIRuntimeAccess.register(java.lang.String.class);
JNIRuntimeAccess.register(java.lang.System.class);
JNIRuntimeAccess.register(method(a, "java.lang.System", "getProperty", String.class));
JNIRuntimeAccess.register(java.nio.charset.Charset.class);
JNIRuntimeAccess.register(method(a, "java.nio.charset.Charset", "isSupported", String.class));
JNIRuntimeAccess.register(constructor(a, "java.lang.String", byte[].class, String.class));
JNIRuntimeAccess.register(method(a, "java.lang.String", "getBytes", String.class));
JNIRuntimeAccess.register(method(a, "java.lang.String", "getBytes"));
JNIRuntimeAccess.register(method(a, "java.lang.String", "concat", String.class));
if (JavaVersionUtil.JAVA_SPEC >= 11) {
JNIRuntimeAccess.register(fields(a, "java.lang.String", "coder", "value"));
}
a.registerReachabilityHandler(JNIRegistrationJava::registerRandomAccessFileInitIDs, method(a, "java.io.RandomAccessFile", "initIDs"));
if (isWindows()) {
PlatformNativeLibrarySupport.singleton().addBuiltinPkgNativePrefix("sun_security_provider_NativeSeedGenerator");
}
if (isDarwin()) {
List<Method> darwinMethods = Arrays.asList(
method(a, "apple.security.KeychainStore", "_scanKeychain"),
method(a, "apple.security.KeychainStore", "_releaseKeychainItemRef", long.class),
method(a, "apple.security.KeychainStore", "_addItemToKeychain", String.class, boolean.class, byte[].class, char[].class),
method(a, "apple.security.KeychainStore", "_removeItemFromKeychain", long.class),
method(a, "apple.security.KeychainStore", "_getEncodedKeyData", long.class, char[].class));
if (JavaVersionUtil.JAVA_SPEC >= 11) {
ArrayList<Method> methods = new ArrayList<>(darwinMethods);
methods.addAll(Arrays.asList(method(a, "sun.nio.fs.MacOSXFileSystemProvider", "getFileTypeDetector"),
method(a, "sun.net.spi.DefaultProxySelector", "getSystemProxies", String.class, String.class),
method(a, "sun.net.spi.DefaultProxySelector", "init")));
a.registerReachabilityHandler(CORESERVICES_LINKER, methods.toArray(new Object[]{}));
} else {
a.registerReachabilityHandler(CORESERVICES_LINKER, darwinMethods.toArray(new Object[]{}));
}
}
if (JavaVersionUtil.JAVA_SPEC >= 11) {
a.registerReachabilityHandler(JNIRegistrationJava::registerProcessHandleImplInfoInitIDs, method(a, "java.lang.ProcessHandleImpl$Info", "initIDs"));
}
}
private static void registerProcessHandleImplInfoInitIDs(DuringAnalysisAccess a) {
JNIRuntimeAccess.register(fields(a, "java.lang.ProcessHandleImpl$Info", "command", "commandLine", "arguments", "startTime", "totalTime", "user"));
}
private static void registerRandomAccessFileInitIDs(DuringAnalysisAccess a) {
JNIRuntimeAccess.register(fields(a, "java.io.RandomAccessFile", "fd"));
}
}