8230857: Avoid reflection in sun.tools.common.ProcessHelper

Reviewed-by: sspitsyn, dholmes
This commit is contained in:
Christoph Langer 2019-09-23 12:32:13 +02:00
parent f92526e6fd
commit 8551294077
4 changed files with 55 additions and 70 deletions
src/jdk.jcmd
linux/classes/sun/tools/common
share/classes/sun/tools/common
test/jdk/sun/tools/jcmd

@ -23,29 +23,21 @@
* questions.
*/
package sun.tools;
package sun.tools.common;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.stream.Stream;
/**
* A helper class that retrieves the main class name for
* a running Java process using the proc filesystem (procfs)
*/
public class ProcessHelper implements sun.tools.common.ProcessHelper {
final class ProcessHelper {
private static final String CMD_PREFIX = "cmd:";
private static final ProcessHelper INSTANCE = new ProcessHelper();
public static ProcessHelper getInstance() {
return INSTANCE;
}
/**
* Gets the main class name for the given Java process by parsing the
@ -57,8 +49,7 @@ public class ProcessHelper implements sun.tools.common.ProcessHelper {
* @return the main class name or null if the process no longer exists or
* was started with a native launcher (e.g. jcmd etc)
*/
public String getMainClass(String pid) {
static String getMainClass(String pid) {
String cmdLine = getCommandLine(pid);
if (cmdLine == null) {
return null;
@ -69,7 +60,7 @@ public class ProcessHelper implements sun.tools.common.ProcessHelper {
String[] parts = cmdLine.split("\0");
String mainClass = null;
if(parts.length == 0) {
if (parts.length == 0) {
return null;
}
@ -120,7 +111,6 @@ public class ProcessHelper implements sun.tools.common.ProcessHelper {
mainClass = parts[i];
}
return mainClass;
}
private static String getCommandLine(String pid) {
@ -134,16 +124,13 @@ public class ProcessHelper implements sun.tools.common.ProcessHelper {
private static boolean isModuleWhiteSpaceOption(String option) {
return option.equals("-p") ||
option.equals("--module-path") ||
option.equals("--upgrade-module-path") ||
option.equals("--add-modules") ||
option.equals("--limit-modules") ||
option.equals("--add-exports") ||
option.equals("--add-opens") ||
option.equals("--add-reads") ||
option.equals("--patch-module");
option.equals("--module-path") ||
option.equals("--upgrade-module-path") ||
option.equals("--add-modules") ||
option.equals("--limit-modules") ||
option.equals("--add-exports") ||
option.equals("--add-opens") ||
option.equals("--add-reads") ||
option.equals("--patch-module");
}
}

@ -79,15 +79,10 @@ public class ProcessArgumentMatcher {
private static boolean check(VirtualMachineDescriptor vmd, String excludeClass, String partialMatch) {
String mainClass = null;
// Try to get the main class name using (platform specific) ProcessHelper
String mainClass = ProcessHelper.getMainClass(vmd.id());
// Get the main class name using platform specific helper
ProcessHelper helper = ProcessHelper.platformProcessHelper();
if (helper != null) {
mainClass = helper.getMainClass(vmd.id());
}
// If the main class name is still unset then retrieve it with the attach mechanism
// If the main class name could not be retrieved by ProcessHelper, get it with the attach mechanism
if (mainClass == null) {
try {
VmIdentifier vmId = new VmIdentifier(vmd.id());

@ -25,33 +25,12 @@
package sun.tools.common;
import java.lang.reflect.Method;
/**
* A helper class to retrieve the main class name for a running
* Java process.
* Java process. Default implementation returns null. Platform specific
* implementation currently available for Linux only.
*/
public interface ProcessHelper {
/**
* Returns an instance of the ProcessHelper class.
*
* @return ProcessHelper object or null if not supported on this platform.
*/
public static ProcessHelper platformProcessHelper() {
try {
Class<?> c = Class.forName("sun.tools.ProcessHelper");
@SuppressWarnings("unchecked")
Method m = c.getMethod("getInstance");
return (ProcessHelper) m.invoke(null);
} catch (ClassNotFoundException e) {
return null;
} catch (ReflectiveOperationException e) {
throw new InternalError(e);
}
}
final class ProcessHelper {
/**
* Returns the main class name for the given Java process
@ -59,6 +38,7 @@ public interface ProcessHelper {
* @param pid - process ID (pid)
* @return main class name or null if the main class could not be retrieved
*/
String getMainClass(String pid);
static String getMainClass(String pid) {
return null;
}
}

@ -21,16 +21,13 @@
* questions.
*/
import jdk.internal.module.ModuleInfoWriter;
import jdk.test.lib.JDKToolFinder;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.util.JarUtils;
import sun.tools.common.ProcessHelper;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.module.ModuleDescriptor;
import java.lang.reflect.Method;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
@ -44,6 +41,11 @@ import java.util.jar.Manifest;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.internal.module.ModuleInfoWriter;
import jdk.test.lib.JDKToolFinder;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.util.JarUtils;
/*
* @test
* @bug 8205654
@ -52,15 +54,13 @@ import java.util.stream.Stream;
*
* @requires os.family == "linux"
* @library /test/lib
* @modules jdk.jcmd/sun.tools.common
* @modules jdk.jcmd/sun.tools.common:+open
* java.base/jdk.internal.module
* @build test.TestProcess
* @run main/othervm TestProcessHelper
*/
public class TestProcessHelper {
private ProcessHelper PROCESS_HELPER = ProcessHelper.platformProcessHelper();
private static final String TEST_PROCESS_MAIN_CLASS_NAME = "TestProcess";
private static final String TEST_PROCESS_MAIN_CLASS_PACKAGE = "test";
private static final String TEST_PROCESS_MAIN_CLASS = TEST_PROCESS_MAIN_CLASS_PACKAGE + "."
@ -89,6 +89,29 @@ public class TestProcessHelper {
private static final String[] PATCH_MODULE_OPTIONS = {"--patch-module", null};
private static final MethodHandle MH_GET_MAIN_CLASS = resolveMainClassMH();
private static MethodHandle resolveMainClassMH() {
try {
Method getMainClassMethod = Class
.forName("sun.tools.common.ProcessHelper")
.getDeclaredMethod("getMainClass", String.class);
getMainClassMethod.setAccessible(true);
return MethodHandles.lookup().unreflect(getMainClassMethod);
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private static String callGetMainClass(Process p) {
try {
return (String)MH_GET_MAIN_CLASS.invoke(Long.toString(p.pid()));
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws Exception {
new TestProcessHelper().runTests();
}
@ -188,7 +211,7 @@ public class TestProcessHelper {
}
private void checkMainClass(Process p, String expectedMainClass) {
String mainClass = PROCESS_HELPER.getMainClass(Long.toString(p.pid()));
String mainClass = callGetMainClass(p);
// getMainClass() may return null, e.g. due to timing issues.
// Attempt some limited retries.
if (mainClass == null) {
@ -204,7 +227,7 @@ public class TestProcessHelper {
} catch (InterruptedException e) {
// ignore
}
mainClass = PROCESS_HELPER.getMainClass(Long.toString(p.pid()));
mainClass = callGetMainClass(p);
retrycount++;
sleepms *= 2;
}