Use the bootstrapProxy to load jars. Better bootstrap url algo

This commit is contained in:
Laplie Anderson 2019-07-30 19:50:16 -04:00
parent cf98110991
commit 273feafa94
4 changed files with 38 additions and 17 deletions

View File

@ -34,7 +34,6 @@ public class DatadogClassLoader extends URLClassLoader {
// As a workaround, we keep a reference to the bootstrap jar // As a workaround, we keep a reference to the bootstrap jar
// to use only for resource lookups. // to use only for resource lookups.
private final BootstrapClassLoaderProxy bootstrapProxy; private final BootstrapClassLoaderProxy bootstrapProxy;
/** /**
* Construct a new DatadogClassLoader * Construct a new DatadogClassLoader
* *
@ -44,25 +43,23 @@ public class DatadogClassLoader extends URLClassLoader {
* 9+. * 9+.
*/ */
public DatadogClassLoader( public DatadogClassLoader(
final URL bootstrapJarLocation, final URL bootstrapJarLocation, final String internalJarFileName, final ClassLoader parent) {
final String internalJarFileName,
final ClassLoader classloaderForJarResource,
final ClassLoader parent) {
super(new URL[] {}, parent); super(new URL[] {}, parent);
bootstrapProxy = new BootstrapClassLoaderProxy(new URL[] {bootstrapJarLocation}); bootstrapProxy = new BootstrapClassLoaderProxy(new URL[] {bootstrapJarLocation});
if (classloaderForJarResource != null) { // Some tests pass null if (internalJarFileName != null) { // some tests pass null
try { try {
// The fields of the URL are mostly dummy. InternalJarURLHandler is the only important // 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 // 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 // boilerplate it could be used and the need for dummy fields would be reduced
final URL internalJarURL = final URL internalJarURL =
new URL( new URL(
"x-internal-jar", "x-internal-jar",
null, null,
0, 0,
"/", "/",
new InternalJarURLHandler(internalJarFileName, classloaderForJarResource)); new InternalJarURLHandler(internalJarFileName, bootstrapProxy));
addURL(internalJarURL); addURL(internalJarURL);
} catch (final MalformedURLException e) { } catch (final MalformedURLException e) {

View File

@ -13,7 +13,7 @@ class DatadogClassLoaderTest extends Specification {
def className1 = 'some/class/Name1' def className1 = 'some/class/Name1'
def className2 = 'some/class/Name2' def className2 = 'some/class/Name2'
final URL loc = getClass().getProtectionDomain().getCodeSource().getLocation() 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 threadHoldLockPhase = new Phaser(2)
final Phaser acquireLockFromMainThreadPhase = new Phaser(2) final Phaser acquireLockFromMainThreadPhase = new Phaser(2)

View File

@ -16,7 +16,7 @@ class ClassLoaderMatcherTest extends Specification {
def "skips agent classloader"() { def "skips agent classloader"() {
setup: setup:
URL root = new URL("file://") URL root = new URL("file://")
final URLClassLoader agentLoader = new DatadogClassLoader(root, null, null, null) final URLClassLoader agentLoader = new DatadogClassLoader(root, null, null)
expect: expect:
ClassLoaderMatcher.skipClassLoader().matches(agentLoader) ClassLoaderMatcher.skipClassLoader().matches(agentLoader)
} }

View File

@ -5,11 +5,14 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.lang.instrument.Instrumentation; import java.lang.instrument.Instrumentation;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.CodeSource;
import java.util.jar.JarFile; import java.util.jar.JarFile;
/** Entry point for initializing the agent. */ /** Entry point for initializing the agent. */
@ -140,10 +143,34 @@ public class TracingAgent {
private static synchronized void installBootstrapJar(final Instrumentation inst) private static synchronized void installBootstrapJar(final Instrumentation inst)
throws Exception { throws Exception {
if (BOOTSTRAP_URL == null) { if (BOOTSTRAP_URL == null) {
BOOTSTRAP_URL = TracingAgent.class.getProtectionDomain().getCodeSource().getLocation(); File bootstrapJarFile = null;
// bootstrap jar must be appended before agent classloader is created. final CodeSource codeSource = TracingAgent.class.getProtectionDomain().getCodeSource();
inst.appendToBootstrapClassLoaderSearch(new JarFile(new File(BOOTSTRAP_URL.toURI())));
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 = final Class<?> loaderClass =
ClassLoader.getSystemClassLoader().loadClass("datadog.trace.bootstrap.DatadogClassLoader"); ClassLoader.getSystemClassLoader().loadClass("datadog.trace.bootstrap.DatadogClassLoader");
final Constructor constructor = final Constructor constructor =
loaderClass.getDeclaredConstructor( loaderClass.getDeclaredConstructor(URL.class, String.class, ClassLoader.class);
URL.class, String.class, ClassLoader.class, ClassLoader.class); return (ClassLoader) constructor.newInstance(BOOTSTRAP_URL, innerJarFilename, agentParent);
return (ClassLoader)
constructor.newInstance(
BOOTSTRAP_URL, innerJarFilename, TracingAgent.class.getClassLoader(), agentParent);
} }
private static ClassLoader getPlatformClassLoader() private static ClassLoader getPlatformClassLoader()