1

I am trying to communicate from a java application with a different java virtual machine via an JVMTI attached agent (C++). The basic idea is to attach the agent from VM A to VM B via the Attach API (https://docs.oracle.com/javase/8/docs/technotes/guides/attach/index.html) and later on communicate with the agent so that it can delegate my commands from VM A to the VM B. I have a JavaFX application which lists all java VMs (VirtualMachine.list()) and attaches an agent to them. For every java VM there is a button which should send a String to the agent which is attached to the corresponding VM.

Images:

JavaFX application

Configuration

What I have reached so far:

I am able to attach a native agent via the Attach API to a running virtual machine. The Agent_OnAttach method is executed and so I am able to do some basic checks on the VM B if it is suitable for my needs.

The problem:

After the agent has been attached I am not able to communicate with the agent any more. It would be possible to attach a new agent every time I want to send a command to VM B but since I have no possibility to remove attached agents this would result in a huge number of agents attached to the VM. I would also prefer not to use files or sockets for the communication.

I tried to use JNI for the communication but I am not able to setup a communication between the shared library and the native agent. I didn’t find a way to save the jvmtiEnv from the Agent_OnAttach method to use it from the native method.

The only ways I can think of solving this problem is either to attach a new agent every time I want to send a command (which would require finding a way to detach the agent after executing its Agent_OnAttach method) or to figure out how to use JNI in order to communicate with the agent after attaching.

Native agent:

jvmtiExtensionFunction getExtensionFunction(jvmtiEnv* jvmti, const std::string& functionName) {
   ....
   return function;
}

JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) {
   jvmtiEnv* jvmti = NULL;
   // Initialize jvmti
   vm->GetEnv((void**) &jvmti, JVMTI_VERSION_1_2);

   std::string isVMSuitableFunctionName("vmCheckFunction");
   jvmtiExtensionFunction isVMSuitableFunction = getExtensionFunction(jvmti, isVMSuitableFunctionName);

   int result = 1;
   if(isVMSuitableFunction != NULL) {
       jboolean jIsVMSuitable;
       isVMSuitableFunction(jvmti, &jIsVMSuitable);
       if(jIsVMSuitable) {
           result = 0;
       } else {
           result = 2;
       }
    }
    return result;
}

JNIEXPORT void JNICALL Java_jni_method_tag(JNIEnv *env, jobject obj, jstring tag) {
   // Communicate with the VM the agent has been attached to
}

Java class:

public class TaggingAgent {

    public void attachToVM(String vmID, String agentPath) throws AgentAttachException {
        try {
            VirtualMachine machine = VirtualMachine.attach(vmID);
            machine.loadAgentPath(agentPath);
            machine.detach();
        } catch (AgentInitializationException e) {
            switch (e.returnValue()) {
                case 1:
                    throw new AgentAttachException("JVM is not suitable.", e);
                case 2:
                    throw new AgentAttachException("JVM doesn't support this action.", e);
                default:
                    throw new AgentAttachException("Couldn't attach agent to JVM.", e);
            }
        } catch (AttachNotSupportedException | IOException | AgentLoadException e) {
            throw new AgentAttachException("Couldn't attach agent to JVM.", e);
        }
    }

    public native void tag(String tag);
}

I already checked the following questions:

How to communicate with jvmti agent attached on a running JVM

Communication between JVMTI agent and separate JVM

Unloading a JVMTI agent at runtime?

but it seems like there has no good solution been found.

Markus Weninger
  • 11,931
  • 7
  • 64
  • 137
Max M.
  • 11
  • 2
  • 1
    You have all options of inter-process communication, most notably local sockets and shared memory (implemented via a mapped file), to name those which work on almost all platforms, in C++ and Java. – Holger May 31 '18 at 07:23

0 Answers0