Android JNI – Overview

Preface

Life is really simple, but we insist on making it complicated. – Confucius

quote-Confucius-life-is-really-simple-but-we-insist-39514

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

Picture1

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 

 

 

 

Leave a comment