From 273feafa94bb713bc73272e1fa84134297702eb2 Mon Sep 17 00:00:00 2001 From: Laplie Anderson Date: Tue, 30 Jul 2019 19:50:16 -0400 Subject: [PATCH] Use the bootstrapProxy to load jars. Better bootstrap url algo --- .../trace/bootstrap/DatadogClassLoader.java | 11 ++--- .../bootstrap/DatadogClassLoaderTest.groovy | 2 +- .../agent/test/ClassLoaderMatcherTest.groovy | 2 +- .../datadog/trace/agent/TracingAgent.java | 40 +++++++++++++++---- 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java index 393b02d2d2..c5717a82fa 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java @@ -34,7 +34,6 @@ public class DatadogClassLoader extends URLClassLoader { // As a workaround, we keep a reference to the bootstrap jar // to use only for resource lookups. private final BootstrapClassLoaderProxy bootstrapProxy; - /** * Construct a new DatadogClassLoader * @@ -44,25 +43,23 @@ public class DatadogClassLoader extends URLClassLoader { * 9+. */ public DatadogClassLoader( - final URL bootstrapJarLocation, - final String internalJarFileName, - final ClassLoader classloaderForJarResource, - final ClassLoader parent) { + final URL bootstrapJarLocation, final String internalJarFileName, final ClassLoader parent) { super(new URL[] {}, parent); bootstrapProxy = new BootstrapClassLoaderProxy(new URL[] {bootstrapJarLocation}); - if (classloaderForJarResource != null) { // Some tests pass null + if (internalJarFileName != null) { // some tests pass null try { // The fields of the URL are mostly dummy. InternalJarURLHandler is the only important // field. If extending this class from Classloader instead of URLClassloader required less // boilerplate it could be used and the need for dummy fields would be reduced + final URL internalJarURL = new URL( "x-internal-jar", null, 0, "/", - new InternalJarURLHandler(internalJarFileName, classloaderForJarResource)); + new InternalJarURLHandler(internalJarFileName, bootstrapProxy)); addURL(internalJarURL); } catch (final MalformedURLException e) { diff --git a/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/DatadogClassLoaderTest.groovy b/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/DatadogClassLoaderTest.groovy index 7e26f18ae9..346c458114 100644 --- a/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/DatadogClassLoaderTest.groovy +++ b/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/DatadogClassLoaderTest.groovy @@ -13,7 +13,7 @@ class DatadogClassLoaderTest extends Specification { def className1 = 'some/class/Name1' def className2 = 'some/class/Name2' final URL loc = getClass().getProtectionDomain().getCodeSource().getLocation() - final DatadogClassLoader ddLoader = new DatadogClassLoader(loc, null, null, null) + final DatadogClassLoader ddLoader = new DatadogClassLoader(loc, null, null) final Phaser threadHoldLockPhase = new Phaser(2) final Phaser acquireLockFromMainThreadPhase = new Phaser(2) diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ClassLoaderMatcherTest.groovy b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ClassLoaderMatcherTest.groovy index 0f32c8000b..4b2178bdb7 100644 --- a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ClassLoaderMatcherTest.groovy +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ClassLoaderMatcherTest.groovy @@ -16,7 +16,7 @@ class ClassLoaderMatcherTest extends Specification { def "skips agent classloader"() { setup: URL root = new URL("file://") - final URLClassLoader agentLoader = new DatadogClassLoader(root, null, null, null) + final URLClassLoader agentLoader = new DatadogClassLoader(root, null, null) expect: ClassLoaderMatcher.skipClassLoader().matches(agentLoader) } diff --git a/dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java b/dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java index 64ec481feb..c90fefadc3 100644 --- a/dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java +++ b/dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java @@ -5,11 +5,14 @@ import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.lang.instrument.Instrumentation; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.security.CodeSource; import java.util.jar.JarFile; /** Entry point for initializing the agent. */ @@ -140,10 +143,34 @@ public class TracingAgent { private static synchronized void installBootstrapJar(final Instrumentation inst) throws Exception { if (BOOTSTRAP_URL == null) { - BOOTSTRAP_URL = TracingAgent.class.getProtectionDomain().getCodeSource().getLocation(); + File bootstrapJarFile = null; - // bootstrap jar must be appended before agent classloader is created. - inst.appendToBootstrapClassLoaderSearch(new JarFile(new File(BOOTSTRAP_URL.toURI()))); + final CodeSource codeSource = TracingAgent.class.getProtectionDomain().getCodeSource(); + + if (codeSource != null) { + BOOTSTRAP_URL = codeSource.getLocation(); + bootstrapJarFile = new File(BOOTSTRAP_URL.toURI()); + } + + if (bootstrapJarFile == null || bootstrapJarFile.isDirectory()) { + // Certain tests (and when running with an IDE) have a folder as the CP + // Get the jar from the -javaagent parameter + final RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); + for (final String arg : runtimeMxBean.getInputArguments()) { + if (arg.startsWith("-javaagent")) { + BOOTSTRAP_URL = new URL("file:" + arg.substring(arg.indexOf(":") + 1)); + bootstrapJarFile = new File(BOOTSTRAP_URL.toURI()); + break; + } + } + + if (bootstrapJarFile == null) { + throw new Exception( + "Unable to install bootstrap jar because agent is running from directory"); + } + } + + inst.appendToBootstrapClassLoaderSearch(new JarFile(bootstrapJarFile)); } } @@ -169,11 +196,8 @@ public class TracingAgent { final Class loaderClass = ClassLoader.getSystemClassLoader().loadClass("datadog.trace.bootstrap.DatadogClassLoader"); final Constructor constructor = - loaderClass.getDeclaredConstructor( - URL.class, String.class, ClassLoader.class, ClassLoader.class); - return (ClassLoader) - constructor.newInstance( - BOOTSTRAP_URL, innerJarFilename, TracingAgent.class.getClassLoader(), agentParent); + loaderClass.getDeclaredConstructor(URL.class, String.class, ClassLoader.class); + return (ClassLoader) constructor.newInstance(BOOTSTRAP_URL, innerJarFilename, agentParent); } private static ClassLoader getPlatformClassLoader()