net.bytebuddy.agent.Attacher Maven / Gradle / Ivy
/*
* Copyright 2014 - Present Rafael Winterhalter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.bytebuddy.agent;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import net.bytebuddy.agent.utility.nullability.MaybeNull;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
/**
* A Java program that attaches a Java agent to an external process.
*/
public class Attacher {
/**
* Indicates that any error during attachment should be dumped to a given file location.
*/
public static final String DUMP_PROPERTY = "net.bytebuddy.agent.attacher.dump";
/**
* The attacher provides only {@code static} utility methods and should not be instantiated.
*/
private Attacher() {
throw new UnsupportedOperationException("This class is a utility class and not supposed to be instantiated");
}
/**
* Runs the attacher as a Java application.
*
* @param args A list containing the fully qualified name of the virtual machine type,
* the process id, the fully qualified name of the Java agent jar followed by
* an empty string if the argument to the agent is {@code null} or any number
* of strings where the first argument is proceeded by any single character
* which is stripped off.
*/
@SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback.")
public static void main(String[] args) {
try {
String argument;
if (args.length < 5 || args[4].length() == 0) {
argument = null;
} else {
StringBuilder stringBuilder = new StringBuilder(args[4].substring(1));
for (int index = 5; index < args.length; index++) {
stringBuilder.append(' ').append(args[index]);
}
argument = stringBuilder.toString();
}
install(Class.forName(args[0]), args[1], args[2], Boolean.parseBoolean(args[3]), argument);
} catch (Throwable throwable) {
try {
String property = System.getProperty(DUMP_PROPERTY);
if (property != null && property.length() > 0) {
PrintStream outputStream = new PrintStream(new FileOutputStream(property, true), false, "UTF-8");
try {
throwable.printStackTrace(outputStream);
} finally {
outputStream.close();
}
}
} catch (Throwable ignored) {
/* do nothing */
}
System.exit(1);
}
}
/**
* Installs a Java agent on a target VM.
*
* @param virtualMachineType The virtual machine type to use for the external attachment.
* @param processId The id of the process being target of the external attachment.
* @param agent The Java agent to attach.
* @param isNative {@code true} if the agent is native.
* @param argument The argument to provide or {@code null} if no argument is provided.
* @throws NoSuchMethodException If the virtual machine type does not define an expected method.
* @throws InvocationTargetException If the virtual machine type raises an error.
* @throws IllegalAccessException If a method of the virtual machine type cannot be accessed.
*/
protected static void install(Class> virtualMachineType,
String processId,
String agent,
boolean isNative,
@MaybeNull String argument) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Object virtualMachineInstance = virtualMachineType
.getMethod("attach", String.class)
.invoke(null, processId);
try {
virtualMachineType
.getMethod(isNative ? "loadAgentPath" : "loadAgent", String.class, String.class)
.invoke(virtualMachineInstance, agent, argument);
} finally {
virtualMachineType
.getMethod("detach")
.invoke(virtualMachineInstance);
}
}
}