Stoud
Stoud

Reputation: 293

Java - Inject java agent in to running jvm

Basically, I am trying to write something that lists every class loaded by the JVM. What I wrote works, but it only works for the jvm it is running on. I crafted a java agent to dynamically inject into another JVM, but then realized I don't actually know how to inject it. How do I actually send this agent into another JVM? Is it possible?

Upvotes: 10

Views: 16325

Answers (4)

Rafael Winterhalter
Rafael Winterhalter

Reputation: 44032

Dynamic agents need to declare an agentmain(String, Instrumentation) method which is executed upon attachment within the target VM. You can use the tools.jar dependency which is (until Java 9) only included in a JDK but not a JRE. You can however bundle your agent program with a JDK and attach to JVMs from there.

The biggest pitfall is that the API differs for different VMs; you can however use a library like byte-buddy-agent which contains different implementations for different VMs. An attachment can be done using:

ByteBuddyAgent.attach("my.jar", "my-pid");

This attaches the agent contained in my.jar onto the Java process with id my-id.

Upvotes: 11

apangin
apangin

Reputation: 98304

As far as I understand from the comment, you are interested in something that can inspect remote JVM from within another Java process. If it is the case, then you need a Serviceability Agent rather than Java Agent.

Serviceability Agent API allows you to attach to another JVM process, to read its memory, to reconstruct VM structures and to inspect remote objects in reflection-like manner.

Here is a sample tool to list all classes loaded by a remote JVM:

import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.tools.Tool;

public class ListRemoteClasses extends Tool {

    public static void main(String[] args) {
        new ListRemoteClasses().execute(args);
    }

    @Override
    public void run() {
        VM.getVM().getSystemDictionary().classesDo(klass -> {
            String className = klass.getName().asString().replace('/', '.');
            System.out.println(className);
        });
    }
}

How to run it:

java -cp $JAVA_HOME/lib/sa-jdi.jar:. ListRemoteClasses PID

Upvotes: 5

apangin
apangin

Reputation: 98304

Agents can be injected with HotSpot Attach API.
Run the following snippet with $JAVA_HOME/lib/tools.jar on the class path.

    VirtualMachine vm = VirtualMachine.attach(PID);
    try {
        vm.loadAgent(agentJar);
    } finally {
        vm.detach();
    }

Alternatively you may do this with my command-line jattach utility:

$ jattach PID load instrument false /path/to/agent.jar

Note that in order to support dynamic attach, your Java agent should have agentmain method and Agent-Class property in MANIFEST.MF.

Upvotes: 11

Raman Sahasi
Raman Sahasi

Reputation: 31841

It's hard to provide assistance without looking at the content that you've written but this is just to notify that there is a class named as Instrumentation interface (public interface Instrumentation) from java.lang.instrument package that provides services needed to instrument Java programming language code.

One such method provided by this class is getInitiatedClasses which returns an array containing all the classes that are loaded.

Look at the documentation here

getInitiatedClasses

Class[] getInitiatedClasses(ClassLoader loader)
Returns an array of all classes for which loader is an initiating loader. If the supplied loader is null, classes initiated by the bootstrap class loader are returned.

Parameters: loader - the loader whose initiated class list will be returned Returns: an array containing all the classes for which loader is an initiating loader, zero-length if there are none

Upvotes: -1

Related Questions