javavm - krishnaramb/cplusplus GitHub Wiki
JavaVM and JNIEnv
- 
JNI defines two key data structures, "JavaVM" and "JNIEnv". Both of these are essentially pointers to pointers to function tables. (In the C++ version, they're classes with a pointer to a function table and a member function for each JNI function that indirects through the table.) 
- 
The JavaVM provides the "invocation interface" functions, which allow you to create and destroy a JavaVM. In theory you can have multiple JavaVMs per process, but Android only allows one 
- 
The JNIEnv provides most of the JNI functions. Your native functions all receive a JNIEnv as the first argument 
- 
The JNIEnv is used for thread-local storage. For this reason, you cannot share a JNIEnv between threads. If a piece of code has no other way to get its JNIEnv, you should share the JavaVM, and use GetEnv to discover the thread's JNIEnv. (Assuming it has one; see AttachCurrentThread below.) 
Threads
- 
All threads are Linux threads, scheduled by the kernel. They're usually started from managed code (using Thread.start()), but they can also be created elsewhere and then attached to the
- 
For example, a thread started with pthread_create()orstd::threadcan be attached using theAttachCurrentThread()orAttachCurrentThreadAsDaemon()functions.
- 
Until a thread is attached, it has no JNIEnv, and cannot make JNI calls 👊 
- 
It's usually best to use Thread.start()to create any thread that needs to call in to Java code. Doing so will ensure that you have sufficient stack space, that you're in the correctThreadGroup, and that you're using the sameClassLoaderas your Java code.
java main thread
- This example uses three functions in the API. The Invocation API allows a native application to use the JNI interface pointer to access VM features. The design is similar to Netscape’s JRI Embedding Interface.
Creating the VM The JNI_CreateJavaVM() function loads and initializes a Java VM and returns a pointer to the JNI interface pointer. The thread that called JNI_CreateJavaVM() is considered to be the main thread.
Attaching to the VM The JNI interface pointer (JNIEnv) is valid only in the current thread. Should another thread need to access the Java VM, it must first call AttachCurrentThread() to attach itself to the VM and obtain a JNI interface pointer. Once attached to the VM, a native thread works just like an ordinary Java thread running inside a native method. The native thread remains attached to the VM until it calls DetachCurrentThread() to detach itself.
The attached thread should have enough stack space to perform a reasonable amount of work. The allocation of stack space per thread is operating system-specific. For example, using pthreads, the stack size can be specified in the pthread_attr_t argument to pthread_create
Calling Java Methods from native
- This section illustrates how you can call Java methods from native methods. Our example program, Callbacks.java, invokes a native method. The native method then makes a call back to a Java method. To make things a little more interesting, the Java method again (recursively) calls the native method. This process continues until the recursion is five levels deep, at which time the Java method returns without making any more calls to the native method. To help you see this, the Java method and the native method print a sequence of tracing information
JNIEXPORT void JNICALL
Java_Callbacks_nativeMethod(JNIEnv *env, jobject obj, jint depth)
{
  jclass cls = (*env)->GetObjectClass(env, obj);
  jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "(I)V");
  if (mid == 0)
    return;
  printf("In C, depth = %d, about to enter Java\n", depth);
  (*env)->CallVoidMethod(env, obj, mid, depth);
  printf("In C, depth = %d, back from Java\n", depth);
}
- You can call an instance (non-static) method by following these three steps:
- Your native method calls GetObjectClass. This returns the Java class object to which the Java object belongs.
- Your native method then calls GetMethodID. This performs a lookup for the Java method in a given class. The lookup is based on the name of the method as well as the method signature. If the method does not exist, GetMethodID returns 0. An immediate return from the native method at that point causes a NoSuchMethodError to be thrown in Java code.
- Lastly, your native method calls CallVoidMethod. This invokes an instance method that has void return type. You pass the object, method ID, and the actual arguments to CallVoidMethod.