Preface
Life is really simple, but we insist on making it complicated. – Confucius
What is JNI
JNI is the Java Native Interface, It defines a way for managed code
(written in the Java programming language) to interact with native
code (written in C/C++).
JNI Types and Data Structures
Primitive types
Java Type | Native Type | Description |
boolean | jboolean | unsigned 8 bits |
byte | jbyte | signed 8 bits |
char | jchar | unsigned 16 bits |
short | jshort | signed 16 bits |
int | jint | signed 32 bits |
long | jlong | signed 64 bits |
float | jfloat | 32 bits |
double | jdouble | 64 bits |
void | void | N/A |
Reference Types
Field and Method IDs
Method and field IDs are regular C pointer types
struct _jfieldID; /* opaque structure */ typedef struct _jfieldID *jfieldID; /* field IDs */ struct _jmethodID; /* opaque structure */ typedef struct _jmethodID *jmethodID; /* method IDs */
The Value Type
The jvalue union type is used as the element type in argument arrays. It is declared as follows.
typedef union jvalue { jboolean z; jbyte b; jchar c; jshort s; jint i; jlong j; jfloat f; jdouble d; jobject l; } jvalue;
Type Signatures
The JNI uses the Java VM’s representation of type signatures.
Type Signature | Java Type |
Z | boolean |
B | byte |
C | char |
S | short |
I | int |
J | long |
F | float |
D | double |
L fully-qualified-class ; | fully-qualified-class |
[ type | type[] |
( arg-types ) ret-type | method type |
For example:
long f (int n, String s, int[] arr);
has the type signature:
(ILjava/lang/String;[I)J
Tips: Using Javah to generate the header file and copy the correct signature from there, or utilise Android Studio IDE to help you with this.
JNI Functions
Full list of JNI interface functions can be found at jni.h header file. Basically, it covers below categories of functionalities.
- Version Information
- Class Operations
- Exceptions
- Global and Local References
- Weak Global References
- Object Operations
- Accessing Fields of Objects
- Calling Instance Methods
- Accessing Static Fields
- Calling Static Methods
- String Operations
- Array Operations
- Registering Native Methods
- Monitor Operations
- NIO Support
- Reflection Support
- Java VM Interface
Version Information
GetVersion
jint GetVersion(JNIEnv *env);
Returns the version of the native method interface.
LINKAGE:
Index 4 in the JNIEnv interface function table.
PARAMETERS:
env: the JNI interface pointer.
RETURNS:
Returns the major version number in the higher 16 bits and the minor version number in the lower 16 bits.
- In JDK/JRE 1.1, GetVersion() returns 0x00010001.
- In JDK/JRE 1.2, GetVersion() returns 0x00010002.
- In JDK/JRE 1.4, GetVersion() returns 0x00010004.
- In JDK/JRE 1.6, GetVersion() returns 0x00010006.
Java VM Interface
GetJavaVM
jint GetJavaVM(JNIEnv *env, JavaVM **vm);
Returns the Java VM interface (used in the Invocation API) associated with the current thread. The result is placed at the location pointed to by the second argument, vm.
Data structure of JavaVM
typedef const struct JNIInvokeInterface* JavaVM; /* * JNI invocation interface. */ struct JNIInvokeInterface { void* reserved0; void* reserved1; void* reserved2; jint (*DestroyJavaVM)(JavaVM*); jint (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*); jint (*DetachCurrentThread)(JavaVM*); jint (*GetEnv)(JavaVM*, void**, jint); jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*); };
JavaVM and JNIEnv
- “JavaVM” and “JNIEnv” are essentially pointers to pointers to function tables.
- JavaVM provides the “invocation interface” functions, which allow you to create and destroy a JavaVM. Android only has one JavaVM per process.
- JNIEnv is thread local, cannot be shared among different threads.
JNI_OnLoad
jint JNI_OnLoad(JavaVM *vm, void *reserved);
The VM calls JNI_OnLoad when the native library is loaded (for example, through System.loadLibrary). JNI_OnLoad must return the JNI version needed by the native library. In order to use any of the new JNI functions, a native library must export a JNI_OnLoad function that returns JNI_VERSION_1_2. If the native library does not export a JNI_OnLoad function, the VM assumes that the library only requires JNI version JNI_VERSION_1_1. If the VM does not recognize the version number returned by JNI_OnLoad, the native library cannot be loaded.
JNI_OnUnload
void JNI_OnUnload(JavaVM *vm, void *reserved);
The VM calls JNI_OnUnload when the class loader containing the native library is garbage collected. This function can be used to perform cleanup operations. Because this function is called in an unknown context (such as from a finalizer), the programmer should be conservative on using Java VM services, and refrain from arbitrary Java call-backs.
Note that JNI_OnLoad and JNI_OnUnload are two functions optionally supplied by JNI libraries, not exported from the VM.
Registering Native Methods
RegisterNatives
Compared to using javah command to generate the compilation time JNI method signature, using “RegisterNatives” function is an alternative that can provide a better security experience, because this approach, by making the JNI methods be static (not exported), can escape you from exporting the JNI functions which may be security sensitive in some situations.
jint RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods);
Registers native methods with the class specified by the clazz argument. The methods parameter specifies an array of JNINativeMethod structures that contain the names, signatures, and function pointers of the native methods. The name and signature fields of the JNINativeMethod structure are pointers to modified UTF-8 strings. The nMethods parameter specifies the number of native methods in the array. The JNINativeMethod structure is defined as follows:
typedef struct { char *name; char *signature; void *fnPtr; } JNINativeMethod;
The function pointers nominally must have the following signature:
ReturnType (*fnPtr)(JNIEnv *env, jobject objectOrClass, ...);
UnregisterNatives
jint UnregisterNatives(JNIEnv *env, jclass clazz);
Unregisters native methods of a class. The class goes back to the state before it was linked or registered with its native method functions.
This function should not be used in normal native code. Instead, it provides special programs a way to reload and relink native libraries.
Reference
https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html