Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java API on top of JVMTI?

Tags:

java

jvmti

Is there a nice Java API I can use on top of JVMTI?

like image 652
yazz.com Avatar asked Jan 27 '11 16:01

yazz.com


3 Answers

JVMTI was not built for having Java API on top. The JVM TI definition itself says:

The JVM tool interface (JVM TI) is a standard native API that allows for native libraries to capture events and control a Java Virtual Machine (JVM) for the Java platform.

Since it was built for native API to capture events & controls, I don't think there are API on top of it. May you can explain what you are trying to achieve?

I am not aware of any Java API on top of JVM TI.

like image 158
Abdel Raoof Olakara Avatar answered Oct 18 '22 22:10

Abdel Raoof Olakara


ok... just tried it... seems to work as expected.... in real life the VMInit callback would return an instance of a class that implemented an interface that mirrored the C JVMTI interface.... the C agent would store this instance and call it when required on events .... additionally before the VMInit Java returned it would set up capabilities and callbacks and register events etc.... you would probably be able to get about 90% JVMTI API coverage..... it's just a case of typing it in .... I could do it in a weekend if you have a strong case :-)

the following code produces this:

C: VMInit, preparing to callback Java method
Java: JVMTI callback class, VMInit().
C: VMInit, callback Java method returned successfully
Java: And Finally... Hello, I'm the Java main


package com.stackoverflow;

public class JVMTICallback {

    public static void VMInit() {

        System.out.println("Java:\tJVMTI callback class, VMInit().");

    }

    public static void main(String[] args) {
        // This main is only here to give us something to run for the test

        System.out.println("Java:\tAnd Finally... Hello, I'm the Java main");
    }

}

and the C

#include <stdlib.h>
#include "jvmti.h"

jvmtiEnv *globalJVMTIInterface;

void JNICALL
vmInit(jvmtiEnv * jvmti_env, JNIEnv * jni_env, jthread thread)
{

  printf("C:\tVMInit, preparing to callback Java method\n");

  char *className = "com/stackoverflow/JVMTICallback";
  char *methodName = "VMInit";
  char *descriptor = "()V";

  jclass callbackClass = (*jni_env)->FindClass(jni_env, className);

  if (!callbackClass) {
      fprintf(stderr,"C:\tUnable to locate callback class.\n");
      return;
      }

  jmethodID callbackMethodID = (*jni_env)->GetStaticMethodID(jni_env, callbackClass, methodName, descriptor);

  if (!callbackMethodID)
    {
      fprintf(stderr, "C:\tUnable to locate callback VMInit method\n");
      return;
    }

  (*jni_env)->CallStaticVoidMethodV(jni_env, callbackClass, callbackMethodID, NULL);

  printf("C:\tVMInit, callback Java method returned successfully\n");


}

JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM * jvm, char *options, void *reserved)
{

  jint returnCode = (*jvm)->GetEnv(jvm, (void **) &globalJVMTIInterface,
      JVMTI_VERSION_1_0);

  if (returnCode != JNI_OK)
    {
      fprintf(stderr,
          "The version of JVMTI requested (1.0) is not supported by this JVM.\n");
      return JVMTI_ERROR_UNSUPPORTED_VERSION;
    }

  jvmtiEventCallbacks *eventCallbacks;

  eventCallbacks = calloc(1, sizeof(jvmtiEventCallbacks));
  if (!eventCallbacks)
    {
      fprintf(stderr, "Unable to allocate memory\n");
      return JVMTI_ERROR_OUT_OF_MEMORY;
    }

  eventCallbacks->VMInit = &vmInit;

  returnCode = (*globalJVMTIInterface)->SetEventCallbacks(globalJVMTIInterface,
      eventCallbacks, (jint) sizeof(*eventCallbacks));
  if (returnCode != JNI_OK)
    {
      fprintf(stderr, "C:\tJVM does not have the required capabilities (%d)\n",
          returnCode);
      exit(-1);
    }

  returnCode = (*globalJVMTIInterface)->SetEventNotificationMode(
      globalJVMTIInterface, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, (jthread) NULL);
  if (returnCode != JNI_OK)
    {
      fprintf(
          stderr,
          "C:\tJVM does not have the required capabilities, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT (%d)\n",
          returnCode);
      exit(-1);
    }

  return JVMTI_ERROR_NONE;
}
like image 34
Paul Anderson Avatar answered Oct 19 '22 00:10

Paul Anderson


I searched around and unfortunately can't find any Java API library on top of JVMTI. Seems like you're out of luck.

What you can do though is to call a native lib from your Java code. I'm not very good at C/C++ but from JVMTI docs I see that it's possible to build a small shared library from provided headers. Then you can call it using JNA**. It will give you a nice API wrapper around native library.

Take a look at examples at JNA Getting Started page

This page also links to JNAerator which can generate all necessary Java bindings for you.

The downside of this approach is a necessity of maintaining this thin native layer for your target platforms.


** JNA deals a runtime overhead compared to usual JNI but ease of development overweights performance benefits IMO. Switch to JNI only if you have to.

like image 3