Skip to content

Commit 4fffb61

Browse files
Andrew Kenttylerbenson
authored andcommitted
Enable bootstrap instrumentation and helper injection.
1 parent f57faba commit 4fffb61

5 files changed

Lines changed: 58 additions & 8 deletions

File tree

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@
1717

1818
@Slf4j
1919
public class AgentInstaller {
20+
private static volatile Instrumentation INSTRUMENTATION;
21+
22+
public static Instrumentation getInstrumentation() {
23+
return INSTRUMENTATION;
24+
}
2025

2126
public static ResettableClassFileTransformer installBytebuddyAgent(final Instrumentation inst) {
2227
return installBytebuddyAgent(inst, new AgentBuilder.Listener[0]);
@@ -30,6 +35,7 @@ public static ResettableClassFileTransformer installBytebuddyAgent(final Instrum
3035
*/
3136
public static ResettableClassFileTransformer installBytebuddyAgent(
3237
final Instrumentation inst, final AgentBuilder.Listener... listeners) {
38+
INSTRUMENTATION = inst;
3339
AgentBuilder agentBuilder =
3440
new AgentBuilder.Default()
3541
.disableClassFormatChanges()

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ClassLoaderMatcher.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public class ClassLoaderMatcher {
1313
public static final String[] BOOTSTRAP_PACKAGE_PREFIXES = {
1414
"io.opentracing", "datadog.slf4j", "datadog.trace"
1515
};
16+
public static final ClassLoader BOOTSTRAP_CLASSLOADER = null;
1617

1718
/** A private constructor that must not be invoked. */
1819
private ClassLoaderMatcher() {
@@ -53,9 +54,9 @@ private SkipClassLoaderMatcher() {}
5354

5455
@Override
5556
public boolean matches(ClassLoader target) {
56-
if (null == target) {
57-
// bootstrap instrumentation not supported yet.
58-
return true;
57+
if (target == BOOTSTRAP_CLASSLOADER) {
58+
// Don't skip bootstrap loader
59+
return false;
5960
}
6061
return shouldSkipClass(target) || shouldSkipInstance(target);
6162
}

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/HelperInjector.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package datadog.trace.agent.tooling;
22

3+
import static datadog.trace.agent.tooling.ClassLoaderMatcher.BOOTSTRAP_CLASSLOADER;
4+
5+
import java.io.File;
36
import java.io.IOException;
47
import java.util.Arrays;
58
import java.util.Collections;
@@ -57,14 +60,14 @@ public DynamicType.Builder<?> transform(
5760
final TypeDescription typeDescription,
5861
final ClassLoader classLoader,
5962
final JavaModule module) {
60-
if (helperClassNames.size() > 0 && classLoader != null) {
63+
if (helperClassNames.size() > 0) {
6164
synchronized (this) {
6265
if (!injectedClassLoaders.contains(classLoader)) {
6366
try {
6467
final Map<TypeDescription, byte[]> helperMap = getHelperMap();
6568
final Set<String> existingClasses = new HashSet<>();
6669
final ClassLoader systemCL = ClassLoader.getSystemClassLoader();
67-
if (!classLoader.equals(systemCL)) {
70+
if (classLoader != BOOTSTRAP_CLASSLOADER && !classLoader.equals(systemCL)) {
6871
// Build a list of existing helper classes.
6972
for (final TypeDescription def : helperMap.keySet()) {
7073
final String name = def.getName();
@@ -73,8 +76,16 @@ public DynamicType.Builder<?> transform(
7376
}
7477
}
7578
}
76-
new ClassInjector.UsingReflection(classLoader).inject(helperMap);
77-
if (!classLoader.equals(systemCL)) {
79+
if (classLoader == BOOTSTRAP_CLASSLOADER) {
80+
ClassInjector.UsingInstrumentation.of(
81+
new File(System.getProperty("java.io.tmpdir")),
82+
ClassInjector.UsingInstrumentation.Target.BOOTSTRAP,
83+
AgentInstaller.getInstrumentation())
84+
.inject(helperMap);
85+
} else {
86+
new ClassInjector.UsingReflection(classLoader).inject(helperMap);
87+
}
88+
if (classLoader != BOOTSTRAP_CLASSLOADER && !classLoader.equals(systemCL)) {
7889
for (final TypeDescription def : helperMap.keySet()) {
7990
// Ensure we didn't add any helper classes to the system CL.
8091
final String name = def.getName();
@@ -91,7 +102,9 @@ public DynamicType.Builder<?> transform(
91102
+ ". Failed to inject helper classes into instance "
92103
+ classLoader
93104
+ " of type "
94-
+ classLoader.getClass().getName(),
105+
+ (classLoader == BOOTSTRAP_CLASSLOADER
106+
? "<bootstrap>"
107+
: classLoader.getClass().getName()),
95108
e);
96109
throw new RuntimeException(e);
97110
}

dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ClassLoaderMatcherTest.groovy

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ class ClassLoaderMatcherTest extends Specification {
2929
!ClassLoaderMatcher.skipClassLoader().matches(emptyLoader)
3030
}
3131

32+
def "does not skip bootstrap classloader"() {
33+
expect:
34+
!ClassLoaderMatcher.skipClassLoader().matches(null)
35+
}
36+
3237
/*
3338
* A URLClassloader which only delegates java.* classes
3439
*/

dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/HelperInjectionTest.groovy

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
package datadog.trace.agent.test
22

3+
import datadog.trace.agent.tooling.AgentInstaller
4+
5+
import static datadog.trace.agent.tooling.ClassLoaderMatcher.BOOTSTRAP_CLASSLOADER
6+
37
import datadog.trace.agent.tooling.HelperInjector
48
import datadog.trace.agent.tooling.Utils
9+
import net.bytebuddy.agent.ByteBuddyAgent
510
import spock.lang.Specification
611

712
import java.lang.reflect.Method
@@ -31,6 +36,26 @@ class HelperInjectionTest extends Specification {
3136
emptyLoader?.close()
3237
}
3338

39+
def "helpers injected on bootstrap classloader"() {
40+
setup:
41+
ByteBuddyAgent.install()
42+
AgentInstaller.installBytebuddyAgent(ByteBuddyAgent.getInstrumentation())
43+
String helperClassName = HelperInjectionTest.getPackage().getName() + '.HelperClass'
44+
HelperInjector injector = new HelperInjector(helperClassName)
45+
URLClassLoader bootstrapChild = new URLClassLoader(new URL[0], (ClassLoader) null)
46+
47+
when:
48+
bootstrapChild.loadClass(helperClassName)
49+
then:
50+
thrown ClassNotFoundException
51+
52+
when:
53+
injector.transform(null, null, BOOTSTRAP_CLASSLOADER, null)
54+
Class<?> helperClass = bootstrapChild.loadClass(helperClassName)
55+
then:
56+
helperClass.getClassLoader() == BOOTSTRAP_CLASSLOADER
57+
}
58+
3459
private static boolean isClassLoaded(String className, ClassLoader classLoader) {
3560
final Method findLoadedClassMethod = ClassLoader.getDeclaredMethod("findLoadedClass", String)
3661
try {

0 commit comments

Comments
 (0)