27

Is it possible to insert a javaagent after virtual machine start from within the same VM?

Lets say for example we have an agent in a jar myagent.jar with the appropriate meta data set-up and an agentmain method already implemented. Now the users program calls an API call which should result in the insertion of the agent so that it can redefine the classes.

Can it be done and how?

Paul Keeble
  • 1,202
  • 2
  • 12
  • 16

4 Answers4

20

https://web.archive.org/web/20141014195801/http://dhruba.name/2010/02/07/creation-dynamic-loading-and-instrumentation-with-javaagents/ has a great example of how to write an agent as well as how to start one on the fly.

Alan Cabrera
  • 694
  • 1
  • 8
  • 16
  • 3
    It's not meant to be a self contained tutorial, true. But it is a great example for advanced Java developers. I, personally, had no problem with the example. – Alan Cabrera Apr 25 '13 at 16:18
  • 2
    The link is broken. I was able to find it archived on the WayBackMachine: https://web.archive.org/web/20141014195801/http://dhruba.name/2010/02/07/creation-dynamic-loading-and-instrumentation-with-javaagents/ – 11101101b Oct 29 '14 at 21:40
  • that link does not work anymore. you should have copied content and pasted here. – hrishikeshp19 Nov 20 '14 at 19:49
  • 2
    The wayback link should suffice – Alan Cabrera May 23 '16 at 18:30
  • @AlanCabrera I'm using jdk 1.8. I have tried oracle and openjdk, but I never can attach to the jvm. The attempt causes a threaddump in the target jvm and fails on the injecting jvm saying com.sun.tools.attach.AttachNotSupportedException: Unable to open socket file: target process not responding or HotSpot VM not loaded at sun.tools.attach.LinuxVirtualMachine.(LinuxVirtualMachine.java:106) at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:63) at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:208) at Main.main(Main.java:15) – Sam Thomas May 16 '18 at 20:27
  • I have tried this on CentOS and Ubuntu. Both failed the same way – Sam Thomas May 16 '18 at 20:29
15

Yes, you just have to pass the JVM process ID to the VirtualMachine.attach(String pid) method, and load the agent jar. The VirtualMachine class is available in the JDK_HOME/lib/tools.jar file. Here's an example of how I activate an agent at runtime:

public static void attachGivenAgentToThisVM(String pathToAgentJar) {
  try {                                                                               
    String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName();                                                   
    String pid = nameOfRunningVM.substring(0, nameOfRunningVM.indexOf('@'));                                                   
    VirtualMachine vm = VirtualMachine.attach(pid);                                                                            
    vm.loadAgent(pathToAgentJar, "");
    vm.detach();   
  } catch (Exception e) {
    e.printStackTrace();
  }
}                                                                                                            
11101101b
  • 7,679
  • 2
  • 42
  • 52
  • 1
    thanks for good answer. but when i am trying the same but i got an exception ** com.sun.tools.attach.AgentLoadException: Agent JAR not found or no Agent-Class attribute ** – madhu Apr 09 '15 at 13:28
  • 1
    I suspect it's a dependency issue, here how to solve in maven: http://m.blog.csdn.net/blog/chendeng8899/8487336 ("Dynamic loading of a javaagent at runtime" section) – pierpytom Apr 27 '15 at 12:13
  • @11101101b I'm using jdk 1.8. I have tried oracle and openjdk, but I never can attach to the jvm. The attempt causes a threaddump in the target jvm and fails on the injecting jvm saying com.sun.tools.attach.AttachNotSupportedException: Unable to open socket file: target process not responding or HotSpot VM not loaded at sun.tools.attach.LinuxVirtualMachine.(LinuxVirtualMachine.java:106) at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:63) at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:208) at Main.main(Main.java:15) – Sam Thomas May 16 '18 at 20:28
  • I have tried this on CentOS and Ubuntu. Both failed the same way – Sam Thomas May 16 '18 at 20:29
  • It needs tools.jar, is it worth adding tools.jar in class path. (using Java8) – Ashok Waghmare Oct 30 '18 at 10:39
4

You should be able to do it in Java 6, see the package documentation chapter "Starting Agents After VM Startup"

edit: Maybe it was possible in Java 5 already and just the javadocs didn't mention it that explicitly

HerdplattenToni
  • 486
  • 2
  • 5
  • It does not specify what the method call is however. Looking further into it however would ((URLClassLoader)ClassLoader.getSystemClassLoader()).addURL(....) where the URL added pointed to the myagent.jar result in the agentmain being called? – Paul Keeble Aug 14 '09 at 11:50
  • Is this Java 6 in general or only with HotSpot? – Thorbjørn Ravn Andersen Aug 14 '09 at 13:35
  • @Paul: I haven't tried it so I can't say if it works like that but it seems reasonable. However you will have to call addURL by reflection since it is protected. Something like: URLClassLoader sysloader = (URLClassLoader)ClassLoader.getSystemClassLoader(); Class sysclass = URLClassLoader.class; try { Method method = sysclass.getDeclaredMethod("addURL",parameters); method.setAccessible(true); method.invoke(sysloader,new Object[]{ yourURL }); } – HerdplattenToni Aug 17 '09 at 10:25
1

Having encountered the same issue, I have found a far more comprehensive solution, from the ByteBuddy library.

ByteBuddy thoroughly attempts to load its java agent dynamically:

Installs an agent on the currently running Java virtual machine. Unfortunately, this does not always work. The runtime installation of a Java agent is supported for:

  • JVM version 9+: For Java VM of at least version 9, the attachment API was moved into a module and the runtime installation is possible if the {@code jdk.attach} module is available to Byte Buddy which is typically only available for VMs shipped with a JDK.
  • OpenJDK / Oracle JDK / IBM J9 versions 8-: The installation for HotSpot is only possible when bundled with a JDK and requires a {@code tools.jar} bundled with the VM which is typically only available for JDK-versions of the JVM.
  • When running Linux and including the optional junixsocket-native-common dependency, Byte Buddy emulates a Unix socket connection to attach to the target VM.
  • A248
    • 690
    • 7
    • 17