diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 3d557a79699f..813f14b37b8a 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -243,7 +243,7 @@ "java.compiler", "jdk.jfr", "jdk.management", - "jdk.management.jfr", + "jdk.zipfs", ], "requiresConcealed" : { "java.base" : [ @@ -283,9 +283,6 @@ "jdk.management": [ "com.sun.management.internal" ], - "jdk.management.agent": [ - "jdk.internal.agent", - ], "jdk.jfr": [ "jdk.jfr.events", "jdk.jfr.internal", @@ -1327,8 +1324,6 @@ "requires": [ "java.management", "jdk.management", - "jdk.management.agent", - "jdk.management.jfr", ], "uses" : [ "org.graalvm.nativeimage.Platform", diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspectionOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspectionOptions.java index 0d17f5adb6b6..eedc7b934325 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspectionOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspectionOptions.java @@ -37,6 +37,7 @@ import org.graalvm.nativeimage.Platform.WINDOWS; import org.graalvm.nativeimage.Platforms; +import com.oracle.svm.core.jdk.management.ManagementAgentModule; import com.oracle.svm.core.option.APIOption; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.option.LocatableMultiOptionValue; @@ -121,7 +122,7 @@ public static boolean hasJvmstatSupport() { @Fold public static boolean hasJmxServerSupport() { - return hasAllOrKeywordMonitoringSupport(MONITORING_JMXSERVER_NAME) && !Platform.includedIn(WINDOWS.class); + return hasAllOrKeywordMonitoringSupport(MONITORING_JMXSERVER_NAME) && !Platform.includedIn(WINDOWS.class) && ManagementAgentModule.isPresent(); } @Fold diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaUtilSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaUtilSubstitutions.java index c4c736e884ef..5feb7f6b421a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaUtilSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaUtilSubstitutions.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.jdk; +import java.lang.reflect.Method; import java.util.Collection; import java.util.Currency; import java.util.NavigableMap; @@ -31,7 +32,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.logging.LogManager; +import java.util.function.BooleanSupplier; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Alias; @@ -41,6 +42,7 @@ import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.util.ReflectionUtil; /* * Lazily initialized cache fields of collection classes need to be reset. They are not needed in @@ -208,30 +210,29 @@ final class Target_java_util_Currency { * so that during runtime the first time the log handler is accessed the equivalent shutdown hook is * added. */ -@TargetClass(value = LogManager.class) +@TargetClass(className = "java.util.logging.LogManager", onlyWith = JavaLoggingModule.IsPresent.class) final class Target_java_util_logging_LogManager { @Inject @RecomputeFieldValue(kind = Kind.NewInstance, declClass = AtomicBoolean.class) private AtomicBoolean addedShutdownHook = new AtomicBoolean(); - @Alias static LogManager manager; + @Alias static Target_java_util_logging_LogManager manager; @Alias native void ensureLogManagerInitialized(); @Substitute - public static LogManager getLogManager() { + public static Target_java_util_logging_LogManager getLogManager() { /* First performing logic originally in getLogManager. */ if (manager == null) { return manager; } - Target_java_util_logging_LogManager managerAlias = SubstrateUtil.cast(manager, Target_java_util_logging_LogManager.class); - managerAlias.ensureLogManagerInitialized(); + manager.ensureLogManagerInitialized(); /* Logic for adding shutdown hook. */ - if (!managerAlias.addedShutdownHook.getAndSet(true)) { + if (!manager.addedShutdownHook.getAndSet(true)) { /* Add a shutdown hook to close the global handlers. */ try { - Runtime.getRuntime().addShutdownHook(SubstrateUtil.cast(new Target_java_util_logging_LogManager_Cleaner(managerAlias), Thread.class)); + Runtime.getRuntime().addShutdownHook(SubstrateUtil.cast(new Target_java_util_logging_LogManager_Cleaner(manager), Thread.class)); } catch (IllegalStateException e) { /* If the VM is already shutting down, we do not need to register shutdownHook. */ } @@ -241,7 +242,7 @@ public static LogManager getLogManager() { } } -@TargetClass(value = LogManager.class, innerClass = "Cleaner") +@TargetClass(className = "java.util.logging.LogManager", innerClass = "Cleaner", onlyWith = JavaLoggingModule.IsPresent.class) final class Target_java_util_logging_LogManager_Cleaner { @Alias @@ -251,6 +252,48 @@ final class Target_java_util_logging_LogManager_Cleaner { } } +class JavaLoggingModule { + + private static final Object logManager; + private static final Method logManagerGetProperty; + + static { + var javaLoggingModule = ModuleLayer.boot().findModule("java.logging"); + if (javaLoggingModule.isPresent() && JavaLoggingModule.class.getModule().canRead(javaLoggingModule.get())) { + var logManagerClass = ReflectionUtil.lookupClass(false, "java.util.logging.LogManager"); + var logManagerGetLogManagerMethod = ReflectionUtil.lookupMethod(logManagerClass, "getLogManager"); + logManagerGetProperty = ReflectionUtil.lookupMethod(logManagerClass, "getProperty", String.class); + try { + logManager = logManagerGetLogManagerMethod.invoke(null); + } catch (ReflectiveOperationException e) { + throw VMError.shouldNotReachHere("Unable to reflectively invoke java.util.logging.LogManager.getLogManager()", e); + } + } else { + logManager = null; + logManagerGetProperty = null; + } + } + + static String logManagerGetProperty(String name) { + try { + return (String) logManagerGetProperty.invoke(logManager, name); + } catch (ReflectiveOperationException e) { + throw VMError.shouldNotReachHere("Unable to reflectively invoke java.util.logging.LogManager.getProperty(String)", e); + } + } + + private static boolean isPresent() { + return logManager != null; + } + + static class IsPresent implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return isPresent(); + } + } +} + /** Dummy class to have a class with the file's name. */ public final class JavaUtilSubstitutions { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_util_logging_SimpleFormatter.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_util_logging_SimpleFormatter.java index 57fb9f12ab41..343b844ba690 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_util_logging_SimpleFormatter.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_util_logging_SimpleFormatter.java @@ -24,8 +24,6 @@ */ package com.oracle.svm.core.jdk; -import java.util.logging.LogManager; - import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.InjectAccessors; import com.oracle.svm.core.annotate.TargetClass; @@ -36,13 +34,13 @@ class FormatAccessors { // format string for printing the log record private static String getLoggingProperty(String name) { - return LogManager.getLogManager().getProperty(name); + return JavaLoggingModule.logManagerGetProperty(name); } private static String format = null; @SuppressWarnings("unused") - public static String getFormat(java.util.logging.SimpleFormatter parent) { + public static String getFormat(Object parent) { if (format == null) { /* * If multiple threads are doing the initialization at the same time it is not a problem @@ -55,12 +53,12 @@ public static String getFormat(java.util.logging.SimpleFormatter parent) { } @SuppressWarnings("unused") - public static void setFormat(java.util.logging.SimpleFormatter parent, String f) { + public static void setFormat(Object parent, String f) { format = f; } } -@TargetClass(value = java.util.logging.SimpleFormatter.class) +@TargetClass(className = "java.util.logging.SimpleFormatter", onlyWith = JavaLoggingModule.IsPresent.class) public final class Target_java_util_logging_SimpleFormatter { @Alias @InjectAccessors(FormatAccessors.class)// diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_rmi_transport_GC.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_rmi_transport_GC.java index 73eef6313ea5..e8bf7757025b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_rmi_transport_GC.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_rmi_transport_GC.java @@ -26,6 +26,8 @@ package com.oracle.svm.core.jdk; +import java.util.function.BooleanSupplier; + import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.Substitute; @@ -37,8 +39,8 @@ * which is not needed as it only implements the native maxObjectInspectionAge() method, which in * turn is {@link Target_sun_rmi_transport_GC#maxObjectInspectionAge substituted in here}. */ -@TargetClass(className = "sun.rmi.transport.GC") -final class Target_sun_rmi_transport_GC { +@TargetClass(className = "sun.rmi.transport.GC", onlyWith = JavaRMIModuleAvailable.class) +public final class Target_sun_rmi_transport_GC { @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset)// private static Thread daemon = null; @@ -47,3 +49,21 @@ public static long maxObjectInspectionAge() { return Heap.getHeap().getMillisSinceLastWholeHeapExamined(); } } + +class JavaRMIModuleAvailable implements BooleanSupplier { + + private static final boolean hasModule; + + static { + var module = ModuleLayer.boot().findModule("java.rmi"); + if (module.isPresent()) { + JavaRMIModuleAvailable.class.getModule().addReads(module.get()); + } + hasModule = module.isPresent(); + } + + @Override + public boolean getAsBoolean() { + return hasModule; + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/ManagementAgentModule.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/ManagementAgentModule.java new file mode 100644 index 000000000000..e71655d76941 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/ManagementAgentModule.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.jdk.management; + +import java.lang.reflect.Method; +import java.util.Optional; +import java.util.function.BooleanSupplier; + +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.util.ReflectionUtil; + +public class ManagementAgentModule { + + private static final Method agentStartAgent; + private static final Method agentError; + + static final String CONFIG_FILE_ACCESS_DENIED; + static final String CONFIG_FILE_CLOSE_FAILED; + static final String CONFIG_FILE_NOT_FOUND; + static final String CONFIG_FILE_OPEN_FAILED; + + static { + Optional agentModule = ModuleLayer.boot().findModule("jdk.management.agent"); + if (agentModule.isPresent()) { + ManagementAgentModule.class.getModule().addReads(agentModule.get()); + var agentClass = ReflectionUtil.lookupClass(false, "jdk.internal.agent.Agent"); + agentStartAgent = ReflectionUtil.lookupMethod(agentClass, "startAgent"); + agentError = ReflectionUtil.lookupMethod(agentClass, "error", String.class, String.class); + var agentConfigurationErrorClass = ReflectionUtil.lookupClass(false, "jdk.internal.agent.AgentConfigurationError"); + CONFIG_FILE_ACCESS_DENIED = ReflectionUtil.readStaticField(agentConfigurationErrorClass, "CONFIG_FILE_ACCESS_DENIED"); + CONFIG_FILE_CLOSE_FAILED = ReflectionUtil.readStaticField(agentConfigurationErrorClass, "CONFIG_FILE_CLOSE_FAILED"); + CONFIG_FILE_NOT_FOUND = ReflectionUtil.readStaticField(agentConfigurationErrorClass, "CONFIG_FILE_NOT_FOUND"); + CONFIG_FILE_OPEN_FAILED = ReflectionUtil.readStaticField(agentConfigurationErrorClass, "CONFIG_FILE_OPEN_FAILED"); + } else { + agentStartAgent = null; + agentError = null; + CONFIG_FILE_ACCESS_DENIED = null; + CONFIG_FILE_CLOSE_FAILED = null; + CONFIG_FILE_NOT_FOUND = null; + CONFIG_FILE_OPEN_FAILED = null; + } + } + + public static boolean isPresent() { + return agentStartAgent != null; + } + + static class IsPresent implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return isPresent(); + } + } + + static void agentError(String key, String message) { + try { + agentError.invoke(null, key, message); + } catch (ReflectiveOperationException e) { + throw VMError.shouldNotReachHere("Unable to reflectively invoke jdk.internal.agent.Agent.error(String, String)", e); + } + } + + static void agentStartAgent() { + try { + agentStartAgent.invoke(null); + } catch (ReflectiveOperationException e) { + throw VMError.shouldNotReachHere("Unable to reflectively invoke jdk.internal.agent.Agent.startAgent()", e); + } + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/ManagementAgentStartupHook.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/ManagementAgentStartupHook.java index 3e32649c4496..bdeb2bd7dddf 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/ManagementAgentStartupHook.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/ManagementAgentStartupHook.java @@ -33,7 +33,7 @@ public class ManagementAgentStartupHook implements com.oracle.svm.core.jdk.Runti @Override public void execute(boolean isFirstIsolate) { try { - jdk.internal.agent.Agent.startAgent(); + ManagementAgentModule.agentStartAgent(); } catch (Exception e) { throw VMError.shouldNotReachHere("ManagementFeature start-up hook failed: " + e); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/ManagementSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/ManagementSupport.java index 4de1b3950499..5d9de38d6944 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/ManagementSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/ManagementSupport.java @@ -34,6 +34,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.BooleanSupplier; import java.util.function.Supplier; import javax.management.DynamicMBean; @@ -62,8 +63,6 @@ import com.oracle.svm.core.util.VMError; import com.sun.jmx.mbeanserver.MXBeanLookup; -import jdk.management.jfr.FlightRecorderMXBean; - /** * This class provides the SVM support implementation for the MXBean that provide VM introspection, * which is accessible in the JDK via {@link ManagementFactory}. There are two mostly independent @@ -105,6 +104,23 @@ */ public final class ManagementSupport implements ThreadListener { + private static final boolean isJdkManagementJfrModulePresent; + + static { + var loggingModule = ModuleLayer.boot().findModule("jdk.management.jfr"); + if (loggingModule.isPresent()) { + ManagementSupport.class.getModule().addReads(loggingModule.get()); + } + isJdkManagementJfrModulePresent = loggingModule.isPresent(); + } + + static class JdkManagementJfrModulePresent implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return isJdkManagementJfrModulePresent; + } + } + /** * All {@link PlatformManagedObject} structured by their interface. The same object can be * contained multiple times under different keys. The value is either the @@ -123,7 +139,7 @@ public final class ManagementSupport implements ThreadListener { /* Initialized lazily at run time. */ private OperatingSystemMXBean osMXBean; - private FlightRecorderMXBean flightRecorderMXBean; + private PlatformManagedObject flightRecorderMXBean; /** The singleton MBean server for the platform, initialized lazily at run time. */ MBeanServer platformMBeanServer; @@ -150,7 +166,7 @@ public final class ManagementSupport implements ThreadListener { * run time. */ doAddPlatformManagedObjectSingleton(getOsMXBeanInterface(), (PlatformManagedObjectSupplier) this::getOsMXBean); - doAddPlatformManagedObjectSingleton(FlightRecorderMXBean.class, (PlatformManagedObjectSupplier) this::getFlightRecorderMXBean); + doAddPlatformManagedObjectSingleton(PlatformManagedObject.class, (PlatformManagedObjectSupplier) this::getFlightRecorderMXBean); } private static Class getOsMXBeanInterface() { @@ -172,7 +188,7 @@ private synchronized OperatingSystemMXBean getOsMXBean() { return osMXBean; } - private synchronized FlightRecorderMXBean getFlightRecorderMXBean() { + private synchronized PlatformManagedObject getFlightRecorderMXBean() { /** * Requires JFR support and that JMX is user-enabled because * {@code jdk.management.jfr.FlightRecorderMXBeanImpl} makes @@ -182,7 +198,7 @@ private synchronized FlightRecorderMXBean getFlightRecorderMXBean() { return null; } if (flightRecorderMXBean == null) { - flightRecorderMXBean = SubstrateUtil.cast(new Target_jdk_management_jfr_FlightRecorderMXBeanImpl(), FlightRecorderMXBean.class); + flightRecorderMXBean = SubstrateUtil.cast(new Target_jdk_management_jfr_FlightRecorderMXBeanImpl(), PlatformManagedObject.class); } return flightRecorderMXBean; } @@ -384,7 +400,7 @@ private static PlatformManagedObject handleLazyPlatformManagedObjectSingleton(Ob } // This is required because FlightRecorderMXBeanImpl is only accessible within its package. -@TargetClass(className = "jdk.management.jfr.FlightRecorderMXBeanImpl") +@TargetClass(className = "jdk.management.jfr.FlightRecorderMXBeanImpl", onlyWith = ManagementSupport.JdkManagementJfrModulePresent.class) final class Target_jdk_management_jfr_FlightRecorderMXBeanImpl { @Alias Target_jdk_management_jfr_FlightRecorderMXBeanImpl() { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/Target_jdk_internal_agent_Agent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/Target_jdk_internal_agent_Agent.java index 8e52ed52fe4d..a6f5f876c5f6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/Target_jdk_internal_agent_Agent.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/Target_jdk_internal_agent_Agent.java @@ -25,26 +25,19 @@ */ package com.oracle.svm.core.jdk.management; -import com.oracle.svm.core.annotate.Substitute; -import com.oracle.svm.core.annotate.TargetClass; -import com.oracle.svm.core.annotate.TargetElement; -import jdk.internal.agent.Agent; - import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.io.FileInputStream; - import java.util.Properties; -import static jdk.internal.agent.AgentConfigurationError.CONFIG_FILE_NOT_FOUND; -import static jdk.internal.agent.AgentConfigurationError.CONFIG_FILE_OPEN_FAILED; -import static jdk.internal.agent.AgentConfigurationError.CONFIG_FILE_ACCESS_DENIED; -import static jdk.internal.agent.AgentConfigurationError.CONFIG_FILE_CLOSE_FAILED; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.TargetElement; -@TargetClass(jdk.internal.agent.Agent.class) -final class Target_jdk_internal_agent_Agent { +@TargetClass(className = "jdk.internal.agent.Agent", onlyWith = ManagementAgentModule.IsPresent.class) +public final class Target_jdk_internal_agent_Agent { /** * This method is substituted to avoid throwing an exception if java.home is null. If a config @@ -64,7 +57,7 @@ public static void readConfiguration(String fname, Properties p) { } final File configFile = new File(fname); if (!configFile.exists()) { - Agent.error(CONFIG_FILE_NOT_FOUND, fname); + ManagementAgentModule.agentError(ManagementAgentModule.CONFIG_FILE_NOT_FOUND, fname); } InputStream in = null; @@ -72,17 +65,17 @@ public static void readConfiguration(String fname, Properties p) { in = new FileInputStream(configFile); p.load(in); } catch (FileNotFoundException e) { - Agent.error(CONFIG_FILE_OPEN_FAILED, e.getMessage()); + ManagementAgentModule.agentError(ManagementAgentModule.CONFIG_FILE_OPEN_FAILED, e.getMessage()); } catch (IOException e) { - Agent.error(CONFIG_FILE_OPEN_FAILED, e.getMessage()); + ManagementAgentModule.agentError(ManagementAgentModule.CONFIG_FILE_OPEN_FAILED, e.getMessage()); } catch (SecurityException e) { - Agent.error(CONFIG_FILE_ACCESS_DENIED, fname); + ManagementAgentModule.agentError(ManagementAgentModule.CONFIG_FILE_ACCESS_DENIED, fname); } finally { if (in != null) { try { in.close(); } catch (IOException e) { - Agent.error(CONFIG_FILE_CLOSE_FAILED, fname); + ManagementAgentModule.agentError(ManagementAgentModule.CONFIG_FILE_CLOSE_FAILED, fname); } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/LoggingFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/LoggingFeature.java index e78b7bcbdcac..656786efba0e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/LoggingFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/LoggingFeature.java @@ -73,8 +73,12 @@ public boolean isInConfiguration(IsInConfigurationAccess access) { } @Override - public void duringSetup(DuringSetupAccess access) { + public void afterRegistration(AfterRegistrationAccess access) { LoggingFeature.class.getModule().addReads(requiredModule().get()); + } + + @Override + public void duringSetup(DuringSetupAccess access) { try { /* Ensure that the log manager is initialized and the initial configuration is read. */ ReflectionUtil.lookupMethod(access.findClassByName("java.util.logging.LogManager"), "getLogManager").invoke(null); @@ -115,5 +119,4 @@ private void trace(String msg) { System.out.println("LoggingFeature: " + msg); } } - } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java index 785737b0952f..e80ff0afbb99 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java @@ -193,15 +193,10 @@ private static void checkBootModuleDependencies(boolean verbose) { "java.base", "java.management", "jdk.management", - "jdk.management.agent", // READ-BY org.graalvm.nativeimage.builder - "java.management.rmi", // READ-BY jdk.management.agent - "java.rmi", - "java.logging", // READ-BY java.rmi READ-BY java.management.rmi - "java.naming", - "java.security.sasl", // READ-BY java.naming READ-BY java.management.rmi "java.compiler", - "jdk.management.jfr", - "jdk.jfr"); + "jdk.jfr", + "jdk.zipfs", + "jdk.management.jfr"); Set unexpectedBuilderDependencies = modulesBuilderDependsOn.stream().map(Module::getName).collect(Collectors.toSet()); unexpectedBuilderDependencies.removeAll(expectedBuilderDependencies); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java index 6b4ada7eeac5..b9eb482136af 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java @@ -154,6 +154,8 @@ public static class Options { /** The list of known service classes defined by the JCA. */ private static final List> knownServices; + private static final boolean isMscapiModulePresent; + static { List> classList = new ArrayList<>(List.of( AlgorithmParameterGenerator.class, AlgorithmParameters.class, @@ -175,6 +177,9 @@ public static class Options { if (ModuleLayer.boot().findModule("java.smartcardio").isPresent()) { classList.add(ReflectionUtil.lookupClass(false, "javax.smartcardio.TerminalFactory")); } + + isMscapiModulePresent = ModuleLayer.boot().findModule("jdk.crypto.mscapi").isPresent(); + knownServices = Collections.unmodifiableList(classList); } @@ -254,7 +259,7 @@ public void duringSetup(DuringSetupAccess a) { * SeedGenerator.getSystemEntropy(). */ rci.rerunInitialization(clazz(access, "sun.security.provider.AbstractDrbg$SeederHolder"), "for substitutions"); - if (isWindows()) { + if (isMscapiModulePresent) { /* PRNG. creates a Cleaner (see JDK-8210476), which starts its thread. */ rci.rerunInitialization(clazz(access, "sun.security.mscapi.PRNG"), "for substitutions"); } @@ -338,7 +343,7 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { }); } - if (isWindows()) { + if (isMscapiModulePresent) { access.registerReachabilityHandler(SecurityServicesFeature::registerSunMSCAPIConfig, clazz(access, "sun.security.mscapi.SunMSCAPI")); /* Resolve calls to sun_security_mscapi* as builtIn. */ PlatformNativeLibrarySupport.singleton().addBuiltinPkgNativePrefix("sun_security_mscapi"); @@ -419,20 +424,23 @@ private static void registerSunMSCAPIConfig(BeforeAnalysisAccess a) { "java.security.KeyException", "java.security.KeyStoreException", "java.security.ProviderException", "java.security.SignatureException", "java.lang.OutOfMemoryError"); - /* - * JDK-6782021 changed the `loadKeysOrCertificateChains` method signature, so we try the new - * signature first and fall back to the old one in case we're on a JDK without the change. - */ - a.registerReachabilityHandler(SecurityServicesFeature::registerLoadKeysOrCertificateChains, - optionalMethod(a, "sun.security.mscapi.CKeyStore", "loadKeysOrCertificateChains", String.class, int.class) - .orElseGet(() -> method(a, "sun.security.mscapi.CKeyStore", "loadKeysOrCertificateChains", String.class))); - a.registerReachabilityHandler(SecurityServicesFeature::registerGenerateCKeyPair, - method(a, "sun.security.mscapi.CKeyPairGenerator$RSA", "generateCKeyPair", String.class, int.class, String.class)); - a.registerReachabilityHandler(SecurityServicesFeature::registerCPrivateKeyOf, - method(a, "sun.security.mscapi.CKeyStore", "storePrivateKey", String.class, byte[].class, String.class, int.class)); - a.registerReachabilityHandler(SecurityServicesFeature::registerCPublicKeyOf, - method(a, "sun.security.mscapi.CSignature", "importECPublicKey", String.class, byte[].class, int.class), - method(a, "sun.security.mscapi.CSignature", "importPublicKey", String.class, byte[].class, int.class)); + if (isMscapiModulePresent) { + /* + * JDK-6782021 changed the `loadKeysOrCertificateChains` method signature, so we try the + * new signature first and fall back to the old one in case we're on a JDK without the + * change. + */ + a.registerReachabilityHandler(SecurityServicesFeature::registerLoadKeysOrCertificateChains, + optionalMethod(a, "sun.security.mscapi.CKeyStore", "loadKeysOrCertificateChains", String.class, int.class) + .orElseGet(() -> method(a, "sun.security.mscapi.CKeyStore", "loadKeysOrCertificateChains", String.class))); + a.registerReachabilityHandler(SecurityServicesFeature::registerGenerateCKeyPair, + method(a, "sun.security.mscapi.CKeyPairGenerator$RSA", "generateCKeyPair", String.class, int.class, String.class)); + a.registerReachabilityHandler(SecurityServicesFeature::registerCPrivateKeyOf, + method(a, "sun.security.mscapi.CKeyStore", "storePrivateKey", String.class, byte[].class, String.class, int.class)); + a.registerReachabilityHandler(SecurityServicesFeature::registerCPublicKeyOf, + method(a, "sun.security.mscapi.CSignature", "importECPublicKey", String.class, byte[].class, int.class), + method(a, "sun.security.mscapi.CSignature", "importPublicKey", String.class, byte[].class, int.class)); + } } private static void registerLoadKeysOrCertificateChains(DuringAnalysisAccess a) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNio.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNio.java index f7d4073a47f0..9dbb0d7e48f9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNio.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNio.java @@ -27,7 +27,6 @@ import java.net.InetAddress; import java.net.SocketAddress; import java.nio.ByteBuffer; -import java.util.Optional; import java.util.function.Consumer; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; @@ -47,8 +46,22 @@ @AutomaticallyRegisteredFeature public class JNIRegistrationJavaNio extends JNIRegistrationUtil implements InternalFeature { - private static Optional jdkSctpModule() { - return ModuleLayer.boot().findModule("jdk.sctp"); + private static final boolean isJdkSctpModulePresent; + private static final boolean isJavaNamingModulePresent; + + static { + Module thisModule = JNIRegistrationJavaNio.class.getModule(); + var sctpModule = ModuleLayer.boot().findModule("jdk.sctp"); + if (sctpModule.isPresent()) { + thisModule.addReads(sctpModule.get()); + } + isJdkSctpModulePresent = sctpModule.isPresent(); + + var namingModule = ModuleLayer.boot().findModule("java.naming"); + if (namingModule.isPresent()) { + thisModule.addReads(namingModule.get()); + } + isJavaNamingModulePresent = namingModule.isPresent(); } @Override @@ -64,7 +77,7 @@ public void duringSetup(DuringSetupAccess a) { rerunClassInit(a, "sun.nio.ch.SimpleAsynchronousFileChannelImpl", "sun.nio.ch.SimpleAsynchronousFileChannelImpl$DefaultExecutorHolder", "sun.nio.ch.SinkChannelImpl", "sun.nio.ch.SourceChannelImpl"); rerunClassInit(a, "sun.nio.fs.UnixNativeDispatcher", "sun.nio.ch.UnixAsynchronousServerSocketChannelImpl"); - if (isLinux() && jdkSctpModule().isPresent()) { + if (isLinux() && isJdkSctpModulePresent) { rerunClassInit(a, "sun.nio.ch.sctp.SctpChannelImpl"); } } else if (isWindows()) { @@ -93,7 +106,7 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { if (isPosix()) { a.registerReachabilityHandler(JNIRegistrationJavaNio::registerUnixNativeDispatcherInit, method(a, "sun.nio.fs.UnixNativeDispatcher", "init")); - if (isLinux() && jdkSctpModule().isPresent()) { + if (isLinux() && isJdkSctpModulePresent) { a.registerReachabilityHandler(JNIRegistrationJavaNio::registerSctpChannelImplInitIDs, method(a, "sun.nio.ch.sctp.SctpChannelImpl", "initIDs")); } @@ -102,7 +115,10 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { a.registerReachabilityHandler(JNIRegistrationJavaNio::registerIocpInitIDs, method(a, "sun.nio.ch.Iocp", "initIDs")); } - a.registerReachabilityHandler(JNIRegistrationJavaNio::registerConnectionCreateInetSocketAddress, method(a, "com.sun.jndi.ldap.Connection", "createInetSocketAddress", String.class, int.class)); + if (isJavaNamingModulePresent) { + a.registerReachabilityHandler(JNIRegistrationJavaNio::registerConnectionCreateInetSocketAddress, + method(a, "com.sun.jndi.ldap.Connection", "createInetSocketAddress", String.class, int.class)); + } Consumer registerInitInetAddressIDs = JNIRegistrationJavaNet::registerInitInetAddressIDs; a.registerReachabilityHandler(registerInitInetAddressIDs, method(a, "sun.nio.ch.Net", "initIDs")); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationSupport.java index 7d4620762e6a..30046cf2acd1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationSupport.java @@ -102,7 +102,8 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { @Override public void afterAnalysis(AfterAnalysisAccess access) { if (isWindows()) { - isSunMSCAPIProviderReachable = access.isReachable(clazz(access, "sun.security.mscapi.SunMSCAPI")); + var optSunMSCAPIClass = optionalClazz(access, "sun.security.mscapi.SunMSCAPI"); + isSunMSCAPIProviderReachable = optSunMSCAPIClass.isPresent() && access.isReachable(optSunMSCAPIClass.get()); } }