Android JNI Learning (4) - Chinese API of common methods of JNI

 This series of articles are as follows:

Android JNI learning (1) - NDK and JNI basic
Android JNI learning (2) - "hello world" of actual JNI
Android JNI learning (3) - Java and Native call each other
Android JNI learning (4) - JNI Chinese API for common methods

This article is mainly based on the translation of JNI's common interface documents to help us better understand the commonly used APIs in JNI. details as follows:

1. Interface Function Table (interface function table)

Each function can be accessed through the JNIEnv parameter. The JNIEnv type is a pointer to store all JNI interface pointers. It is defined as follows:

typedef const struct JNINativeInterface *JNIEnv;

Virtual machine initialization function table, as shown in the following code, the first three entries are reserved for future compatibility with COM. Also, we keep some extra NULL entries near the beginning of the function table, for example, so that future class-related JNI operations can be added after FindClass instead of at the end of the table. Note that the function table can be shared between all JNI interface pointers.

First let's look at JNINativeInterface:

const struct JNINativeInterface ... = {

    NULL,
    NULL,
    NULL,
    NULL,
    GetVersion,

    DefineClass,
    FindClass,

    FromReflectedMethod,
    FromReflectedField,
    ToReflectedMethod,

    GetSuperclass,
    IsAssignableFrom,

    ToReflectedField,

    Throw,
    ThrowNew,
    ExceptionOccurred,
    ExceptionDescribe,
    ExceptionClear,
    FatalError,

    PushLocalFrame,
    PopLocalFrame,

    NewGlobalRef,
    DeleteGlobalRef,
    DeleteLocalRef,
    IsSameObject,
    NewLocalRef,
    EnsureLocalCapacity,

    AllocObject,
    NewObject,
    NewObjectV,
    NewObjectA,

    GetObjectClass,
    IsInstanceOf,

    GetMethodID,

    CallObjectMethod,
    CallObjectMethodV,
    CallObjectMethodA,
    CallBooleanMethod,
    CallBooleanMethodV,
    CallBooleanMethodA,
    CallByteMethod,
    CallByteMethodV,
    CallByteMethodA,
    CallCharMethod,
    CallCharMethodV,
    CallCharMethodA,
    CallShortMethod,
    CallShortMethodV,
    CallShortMethodA,
    CallIntMethod,
    CallIntMethodV,
    CallIntMethodA,
    CallLongMethod,
    CallLongMethodV,
    CallLongMethodA,
    CallFloatMethod,
    CallFloatMethodV,
    CallFloatMethodA,
    CallDoubleMethod,
    CallDoubleMethodV,
    CallDoubleMethodA,
    CallVoidMethod,
    CallVoidMethodV,
    CallVoidMethodA,

    CallNonvirtualObjectMethod,
    CallNonvirtualObjectMethodV,
    CallNonvirtualObjectMethodA,
    CallNonvirtualBooleanMethod,
    CallNonvirtualBooleanMethodV,
    CallNonvirtualBooleanMethodA,
    CallNonvirtualByteMethod,
    CallNonvirtualByteMethodV,
    CallNonvirtualByteMethodA,
    CallNonvirtualCharMethod,
    CallNonvirtualCharMethodV,
    CallNonvirtualCharMethodA,
    CallNonvirtualShortMethod,
    CallNonvirtualShortMethodV,
    CallNonvirtualShortMethodA,
    CallNonvirtualIntMethod,
    CallNonvirtualIntMethodV,
    CallNonvirtualIntMethodA,
    CallNonvirtualLongMethod,
    CallNonvirtualLongMethodV,
    CallNonvirtualLongMethodA,
    CallNonvirtualFloatMethod,
    CallNonvirtualFloatMethodV,
    CallNonvirtualFloatMethodA,
    CallNonvirtualDoubleMethod,
    CallNonvirtualDoubleMethodV,
    CallNonvirtualDoubleMethodA,
    CallNonvirtualVoidMethod,
    CallNonvirtualVoidMethodV,
    CallNonvirtualVoidMethodA,

    GetFieldID,

    GetObjectField,
    GetBooleanField,
    GetByteField,
    GetCharField,
    GetShortField,
    GetIntField,
    GetLongField,
    GetFloatField,
    GetDoubleField,
    SetObjectField,
    SetBooleanField,
    SetByteField,
    SetCharField,
    SetShortField,
    SetIntField,
    SetLongField,
    SetFloatField,
    SetDoubleField,

    GetStaticMethodID,

    CallStaticObjectMethod,
    CallStaticObjectMethodV,
    CallStaticObjectMethodA,
    CallStaticBooleanMethod,
    CallStaticBooleanMethodV,
    CallStaticBooleanMethodA,
    CallStaticByteMethod,
    CallStaticByteMethodV,
    CallStaticByteMethodA,
    CallStaticCharMethod,
    CallStaticCharMethodV,
    CallStaticCharMethodA,
    CallStaticShortMethod,
    CallStaticShortMethodV,
    CallStaticShortMethodA,
    CallStaticIntMethod,
    CallStaticIntMethodV,
    CallStaticIntMethodA,
    CallStaticLongMethod,
    CallStaticLongMethodV,
    CallStaticLongMethodA,
    CallStaticFloatMethod,
    CallStaticFloatMethodV,
    CallStaticFloatMethodA,
    CallStaticDoubleMethod,
    CallStaticDoubleMethodV,
    CallStaticDoubleMethodA,
    CallStaticVoidMethod,
    CallStaticVoidMethodV,
    CallStaticVoidMethodA,

    GetStaticFieldID,

    GetStaticObjectField,
    GetStaticBooleanField,
    GetStaticByteField,
    GetStaticCharField,
    GetStaticShortField,
    GetStaticIntField,
    GetStaticLongField,
    GetStaticFloatField,
    GetStaticDoubleField,

    SetStaticObjectField,
    SetStaticBooleanField,
    SetStaticByteField,
    SetStaticCharField,
    SetStaticShortField,
    SetStaticIntField,
    SetStaticLongField,
    SetStaticFloatField,
    SetStaticDoubleField,

    NewString,

    GetStringLength,
    GetStringChars,
    ReleaseStringChars,

    NewStringUTF,
    GetStringUTFLength,
    GetStringUTFChars,
    ReleaseStringUTFChars,

    GetArrayLength,

    NewObjectArray,
    GetObjectArrayElement,
    SetObjectArrayElement,

    NewBooleanArray,
    NewByteArray,
    NewCharArray,
    NewShortArray,
    NewIntArray,
    NewLongArray,
    NewFloatArray,
    NewDoubleArray,

    GetBooleanArrayElements,
    GetByteArrayElements,
    GetCharArrayElements,
    GetShortArrayElements,
    GetIntArrayElements,
    GetLongArrayElements,
    GetFloatArrayElements,
    GetDoubleArrayElements,

    ReleaseBooleanArrayElements,
    ReleaseByteArrayElements,
    ReleaseCharArrayElements,
    ReleaseShortArrayElements,
    ReleaseIntArrayElements,
    ReleaseLongArrayElements,
    ReleaseFloatArrayElements,
    ReleaseDoubleArrayElements,

    GetBooleanArrayRegion,
    GetByteArrayRegion,
    GetCharArrayRegion,
    GetShortArrayRegion,
    GetIntArrayRegion,
    GetLongArrayRegion,
    GetFloatArrayRegion,
    GetDoubleArrayRegion,
    SetBooleanArrayRegion,
    SetByteArrayRegion,
    SetCharArrayRegion,
    SetShortArrayRegion,
    SetIntArrayRegion,
    SetLongArrayRegion,
    SetFloatArrayRegion,
    SetDoubleArrayRegion,

    RegisterNatives,
    UnregisterNatives,

    MonitorEnter,
    MonitorExit,

    GetJavaVM,

    GetStringRegion,
    GetStringUTFRegion,

    GetPrimitiveArrayCritical,
    ReleasePrimitiveArrayCritical,

    GetStringCritical,
    ReleaseStringCritical,

    NewWeakGlobalRef,
    DeleteWeakGlobalRef,

    ExceptionCheck,

    NewDirectByteBuffer,
    GetDirectBufferAddress,
    GetDirectBufferCapacity,

    GetObjectRefType
  };

Below we will introduce in detail

2. Get JNI version information

In the JNIEnv pointer, there is a function to get the version of JNI:

jint GetVersion(JNIEnv *env);

This method mainly returns the version information of the local JNI method interface. The return value is different in different JDK environments, as follows:

  • In JDK/JRE 1.1, returns 0x00010001
  • In JDK/JRE 1.2, returns 0x00010002
  • In JDK/JRE 1.3, returns 0x00010004
  • In JDK/JRE 1.4, returns 0x00010006

The above numbers are not taken randomly by me. In fact, they have long been defined as a macro, as follows:

#define JNI_VERSION_1_1 0x00010001
#define JNI_VERSION_1_2 0x00010002

/* Error codes */
#define JNI_EDETACHED    (-2)              /* thread detached from the VM */
#define JNI_EVERSION     (-3)              /* JNI version error 
SINCE JDK/JRE 1.4:
    #define JNI_VERSION_1_4 0x00010004
SINCE JDK/JRE 1.6:
    #define JNI_VERSION_1_6 0x00010006

3. Java class operation

(1), define class (load class)

jclass DefineClass(JNIEnv *env,const char* name,jobject loader,const jbyte *buf, jsize bufLen)

This function mainly loads the class from the buffer containing the data, which contains the original class data that is not referenced by the virtual machine when the class is called.

Entry explanation:

  • env: JNI interface pointer
  • name: The defined class name or interface name, the string has modefied UTF-8 encoding
  • loader: assigned to the defined class loader
  • buf: buffer containing .class file data
  • bufLen: buffer length

Returns: Java class object, returns NULL when an error occurs

Possible exceptions thrown:

  • If no Java class is specified, a ClassFormatError will be thrown
  • If a class/interface is a superclass/superinterface of itself, a ClassCircularityError will be thrown
  • If out of memory, an OutOfMemoryError will be thrown
  • A SecurityException is thrown if one tries to define a class in a Java package

(2), search class

jclass FindClass(JNIEnv *env,const char *name);

There are two cases here, one is JDK release1.1, and the other is JDK release 1.2. From JDK release 1.1, this function loads a locally defined class, which searches the directories and zip files in the CLASSPATH environment variable for a class with a specific name. Since Java 2 release 1.2, the Java security model allows non-system class loading and calling native methods. FindClass defines the class loading associated with the current native method, that is, the class loading class of the class declaring the native method. If the native method belongs to a system class, no class loader is involved; otherwise, the appropriate class loading is invoked to load and link the specified class. Starting with Java 2 SDK 1.2, when calling FindClass through the calling interface, there is no current native method or associated class loader. In this case, use the result of ClassLoader.getSystemClassLoader. This is the class loader that the virtual machine creates for the application and is able to find the classes listed in the java.class.path property.

Entry explanation:

  • env: JNI interface pointer
  • name: A fully qualified class name, which includes "package name" + "/" + class name. For example: such as java.lang.String, the parameter is java/lang/String; if the class name starts with [, an array class will be returned. For example, the signature of the array class is java.lang.Object[], and the parameter should be "[Ljava/lang/Object"

return:

  • Returns the corresponding fully qualified class object, when the class cannot be found, returns NULL

Possible exceptions thrown:

  • If no Java class is specified, a ClassFormatError will be thrown
  • If a class/interface is a superclass/superinterface of itself, a ClassCircularityError will be thrown
  • If no definition for the class/interface is found, NoClassDefFoundError is thrown
  • If out of memory, an OutOfMemoryError will be thrown

(3), find the parent class

jclass GetSuperclass(JNIEnv *env,jclass clazz);

If clazz is not of class Object, this function will return a Class object representing the parent class of this clazz, if the class is Object, or clazz represents an interface, this function will return NULL.

Entry explanation:

  • env: JNI interface pointer
  • clazz: Java Class class

return:

  • Returns the clazz's parent class if it has one, or NULL if it does not

(4), safe conversion

jboolean IsAssignableFrom(JNIEnv *env,jclass clazz1,jclass clazz2);

Determine whether the object of clazz1 can be safely converted to the object of clazz2

Entry explanation:

  • env: JNI interface pointer
  • clazz1: Java's Class class, that is, the class that needs to be converted
  • clazz2: Java's Class class, that is, the class that needs to be converted into a target

return:

Returns JNI_TRUE if any of the following conditions are true:

  • If clazz1 and clazz2 are the same Java class.
  • If clazz1 is a subclass of clazz2
  • If clazz1 is the implementation class of clazz2 interface

4. Abnormal operation

(1), throwing an exception

jint Throw(JNIEnv *env,jthrowable obj);

Pass in a jthrowable object, and throw it in JNI:

Entry explanation:

  • env: JNI interface pointer
  • jthrowable: a Java java.lang.Throwable object

return:

  • Returns 0 on success, and a negative number on failure.

Possible exceptions thrown:

  • Throws a java.lang.Throwable object

(2) Construct a new exception and throw it

jint ThrowNew(JNIEnv *env,jclass clazz,const char* message);

Pass in a message, use it to construct an exception and throw it.

Entry explanation:

  • env: JNI interface pointer
  • jthrowable: a Java java.lang.Throwable object
  • message: The message used to construct a java.lang.Throwable object, the string is encoded in modified UTF-8

return:

  • Returns 0 on success, a negative number on failure

Possible exceptions thrown:

  • Throws a newly constructed java.lang.Throwable object

(3) Check whether an exception occurs and throw an exception

jthrowable ExceptionOccurred(JNIEnv *env);

Check whether an exception has occurred, and if so, return a reference to the exception (before calling the ExceptionClear() function, or before Java handles the exception), and return NULL if no exception occurs.

Entry explanation:

  • env: JNI interface pointer

return:

  • jthrowable's exception reference or NULL

(4) Print the abnormal stack information

void ExceptionDescribe(JNIEnv *env)

Print the exception's stack trace.

Entry explanation:

  • env: JNI interface pointer

(5) Clear the exception stack information

void ExceptionClear(JNIEnv *env);

Clears the exception being thrown. If no exception is currently thrown, this function has no effect.

Entry explanation:

  • env: JNI interface pointer

(6), fatal exception

void FatalError(JNIEnv *env,const char* msg);

A fatal exception is used to output an exception message and terminate the current VM instance, that is, exit the program.

Entry explanation:

  • env: JNI interface pointer
  • msg: the error message of the exception, the string is encoded in modified UTF-8

(7), just check whether an exception occurs

jboolean ExceptionCheck(JNIEnv *env);

Checks whether an exception has occurred, and returns JNI_TRUE if an exception has occurred, or JNI_FALSE otherwise.

Entry explanation:

  • env: JNI interface pointer

return:

  • Returns JNI_TRUE if an exception has occurred, or JNI_FALSE if no exception has occurred

5. Global references and local references

(1) Create a global reference

jobject NewGlobalRef(JNIEnv *env,object obj);

Create a global reference to the object obj, obj can be a global or local reference. Global references must be explicitly handled via DeleteGlobalRef().

Parameter explanation:

  • env: JNI interface pointer
  • obj: object object

return:

  • Global reference to jobject, return NULL if out of memory

(2), delete the global reference

void DeleteGlobalRef(JNIEnv *env,jobject globalRef);

Remove global references.

Parameter explanation:

  • env: JNI interface pointer
  • globalRef: the global reference that needs to be deleted

(3) Delete local references

Local references are only valid during the lifetime of the native interface call, and they are automatically released when the native method returns. Each local reference will consume a certain amount of virtual machine resources. Although local references can be automatically destroyed, programmers also need to be careful not to over-allocate local references in local methods. Excessive allocation of local references will cause the virtual machine to memory when executing local methods overflow.

void DeleteLocalRef(JNIEnv *env, jobject localRef); 

Delete local references via localRef.

parameter explanation

  • env: JNI interface pointer
  • localRef: the local reference that needs to be deleted

JDK/JRE 1.1 provides the above DeleteLocalRef function so that programmers can manually delete local references.

Starting from JDK/JRE 1.2, a set of life cycle management functions are provided, which are the following four functions.

(4) Set the capacity of local variables

jint EnsureLocalCapacity(JNIEnv *env,jint capacity);

In the current thread, limit the number of local references created by passing in a capacity, capacity. Returns 0 on success, otherwise returns a negative number and throws an OutOfMemoryError. The VM automatically ensures that at least 16 local references can be created.

parameter explanation

  • env: JNI interface pointer
  • capacity—Capacity

return:

  • Success returns 0, failure returns a negative number, and an OutOfMemoryError will be thrown

For backward compatibility, if the virtual machine creates local references that exceed capacity. The VM calls FatalError to ensure that no more local references can be created. (If it is in debug mode, the virtual machine will issue a warning to the user and prompt that more local references have been created. In JDK, the programmer can provide the -verbose: jni command line option to open this message)

(5) Create a new frame on the old one

jint PushLocalFram(JNIEnv *env ,jint capacity);

In the case that the local variable capacity has been set, re-create a local variable container. Success returns 0, failure returns a negative number and throws an OutOfMemoryError exception.

Note: In the current local frame, the local references created by the previous local frame are still valid

parameter explanation

  • env: JNI interface pointer
  • capacity—Capacity

(6), release a local reference

jobject PopLocalFrame(JNIEnv *env,jobject result)

Pops the current local reference frame and releases all local references. Returns the local reference corresponding to the given result object at the previous local reference frame. If you do not need to return any references, set result to NULL.

parameter explanation

  • env: JNI interface pointer
  • result: the local reference that needs to be released

(7) Create a local reference

jobject NewLocalRef(JNIEnv *env,jobject ref);

Create a local reference from ref. ref can be a global or local reference, if ref is NULL, returns NULL.

parameter explanation

  • env: JNI interface pointer
  • ref: You can try local references or global references.

(8), weak global reference

A weak global reference is a special kind of global reference. Unlike normal global references, a weak global reference allows the underlying Java object to be garbage collected. Weak global references can be applied wherever global or local references are used. When the garbage collector runs, it will free the underlying variables if the object is only referenced by weak references. A weak global reference to a freed object is equivalent to NULL. Programmers can check whether a weak global refers to a freed object by using isSampleObject to compare the weak reference to NULL. Weak global references in JNI are a simplified version of Java weak references, available in the Java platform API.

When the native method is running, the garbage collector may be working, and the object pointed to by the weak reference may be released at any time. Weak global references can be applied anywhere global references are used, which is generally not a good idea to do so because they can become NULL inadvertently.

When IsSampleObject can identify whether a weak global reference points to a released object, but this does not prevent the object from being released immediately after being detected. This means that programmers cannot rely on this method to identify whether a weak global reference can be used in subsequent JNI function calls.

If you want to solve the above problems, it is recommended to use the JNI function NewLocalRef or NewGlobalRef to use standard global or local references to point to the same object. These functions return NULL if the exclusive has been released. Otherwise, a strong reference is returned (so that the object will not be released). When access to this object is no longer needed, new references must be explicitly deleted.

1. Create a global weak reference

jweak NewWeakGlobalRef(JNIEnv *env,jobject obj);

Create a new weak global reference. Returns NULL if obj points to NULL. If the VM memory overflows, an exception OutOfMemoryError will be thrown.

parameter explanation

  • env: JNI interface pointer
  • obj: reference object

return:

  • global weak reference

2. Delete the global weak reference

void DeleteWeakGlobalRef(JNIEnv *env,jweak obj);

The VM deletes the corresponding resource according to the given weak global reference.

parameter explanation

  • env: JNI interface pointer
  • obj: the weak global reference that will be deleted

Six, object operation

(1) Create a Java object directly

jobject AllocObject(JNIEnv *env,jclass clazz);

Allocates a new Java object without resorting to any constructor, returning a reference to the object.

Parameter explanation:

  • env: JNI interface pointer
  • clazz:: Java class object

return:

  • Returns a Java object, or NULL if the object could not be created.

abnormal:

  • If the class is an interface or an abstract class, an InstantiationException is thrown
  • If it is out of memory, OutOfMemoryError is thrown

(2) Create a Java object according to a constructor

jobject NewObject(JNIEnv *env,jclass clazz,jmethodID methodID,...);
jobject NewObjectA(JNIEnv *env,jclass clazz,jmethodID methodID,const jvalue *args);
jobject NewObjectV(JNIEnv *env,jclass clazz,jmethodID methodID,va_list args);

Constructs a new Java object, methodID indicates that a constructor needs to be called. This ID must be obtained by calling GetMethodID(), GetMethodID() is the function name, and void (V) is the return value. The clazz parameter cannot point to an array class.

  • NewObject: It is necessary to put the input parameters of all constructors after the parameter methodID. NewObject() takes these parameters and passes them to the Java constructor that needs to be called
  • NewObjectA: After methodID, a parameter array of type jvalue—args is placed, which stores all parameters that need to be passed to the constructor. NewObjectA() receives all the parameters in this array and passes them in order to the Java method that needs to be called.
  • NewObjectV: After the methodID, an args of type va_list is placed, and the parameters store all the parameters that need to be passed to the constructor. NewObjectv() receives all parameters and passes them in order to the Java method that needs to be called.

Parameter explanation:

  • env: JNI interface pointer
  • clazz::Java class
  • methodID: the method ID of the constructor

Additional parameters:

  • Additional parameters of NewObject: arguments are the parameters of the constructor
  • Additional parameters for NewObjectA: args is an array of parameters for the constructor
  • Additional parameters of NewObjectV: args is the parameter list of the constructor

return:

  • the Java object, or NULL if the object could not be created

abnormal:

  • If the incoming class is an interface or an abstract class, an InstantiationException is thrown
  • Throw OutOfMemoryError if out of memory
  • All exceptions are thrown through the constructor

(3) Get the "class" of an object

jclass GetObjectClass(JNIEnv *env,object obj);

Returns the class corresponding to obj.

parameter explanation

  • env: JNI interface pointer
  • obj: Java object, cannot be NULL

return:

  • Returns a Java "class" object

(4) Get the "type" of an object

jobjectRefType GetObjectRefType(JNIEnv *env,jobject obj);

Returns the type of the object pointed to by the obj parameter. The parameter obj can be a local variable, a global variable or a global reference.

parameter explanation

  • env: JNI interface pointer
  • obj: local, global or weak global reference

return:

  • JNIInvalidRefType=0: indicates that the obj parameter is not a valid reference type
  • JNILocalRefType=1: indicates that the obj parameter is a local variable type
  • JNIGlobalRefType=2: indicates that the obj parameter is a global variable type
  • JNIWeakGlobalRefType=3: indicates that the obj parameter is a weak global effective reference

An invalid citation is a citation without a citation. In other words, the pointer of obj does not point to the address in memory when the function was created, or has returned from the JNI function. So NULL is an invalid reference. And GetObjectRefType(env, NULL) will return type is JNIInvalidRefType. But what the null reference returns is not JNIInvalidRefType, but the reference type when it was created.

PS: This function cannot be called when the reference is being deleted

(5) Determine whether an object is a subclass of a "class"

jboolean IsInstanceOf(JNIEnv *env, jobject obj,jclass clazz); 

Tests whether obj is an instance of clazz.

parameter:

  • env: JNI interface pointer
  • obj: a Java object
  • clazz: a Java class

return:

Returns JNI_TRUE if obj is an instance of clazz; otherwise returns JNI_FALSE; an empty object can be an instance of any class.

(6) Determine whether two references point to the same reference

jboolean IsSampleObject(JNIEnv *env,jobject ref1,jobject ref2);

Determines whether two references point to the same object.

Parameter explanation:

  • env: JNI interface pointer
  • ref1: Java object
  • ref2: Java object

return:

  • If the same class object, return JNI_TRUE; otherwise, return JNI_FALSE;

(7), return attribute id

jfieldID GetFieldID(JNIEnv *env,jclass clazz,const char *name,const char *sig);

Get the non-static attribute id of a class. The corresponding attribute is determined by the method attribute name and the signature of the attribute (that is, the type of the attribute). By retrieving this attribute ID, we can call Get <type>Field and Set <type>Field, which are our commonly used get and set methods.

Parameter explanation:

  • env: JNI interface pointer
  • clazz: a Java class object
  • name: attribute name ending with "0" and the character type is "utf-8"
  • sig: attribute signature ending with "0" and the character type is "utf-8"

return

  • The attribute corresponds to the ID, and returns NULL if the operation fails

abnormal:

  • Throws NoSuchFieldError if the specified property cannot be found
  • Throws ExceptionInitializerError if class initialization fails
  • If out of memory, throw OutOfMemoryError

PS: GetFieldID() may cause uninitialized classes to start to initialize. At the same time, you cannot use GetFieldID() to get the length of the array, but GetArrayLength() should be used.

(8), return attribute id series

NativeType GetField(JNIEnv *env,jobject obj,jfieldID fielD);

Returns the value of a non-static property of a class, shorthand for a set of functions, as follows:

jobject        GetObjectField(JNIEnv *env,jobject obj,jfieldID fielD)   
jboolean     GetBooleanField(JNIEnv *env,jobject obj,jfieldID fielD)
jbyte           GetByteField(JNIEnv *env,jobject obj,jfieldID fielD)
jchar           GetCharField(JNIEnv *env,jobject obj,jfieldID fielD)
jshort          GetShortField(JNIEnv *env,jobject obj,jfieldID fielD)
jint              GetIntField(JNIEnv *env,jobject obj,jfieldID fielD)
jlong           GetLongField(JNIEnv *env,jobject obj,jfieldID fielD)
jfloat           GetFloatField(JNIEnv *env,jobject obj,jfieldID fielD)
jdouble       GetDoubleField(JNIEnv *env,jobject obj,jfieldID fielD)

Parameter explanation:

  • env: JNI interface pointer
  • obj: Java object, cannot be empty
  • fieldID: a valid fieldID

return:

  • The value of the corresponding attribute

(9), set the attribute id series

void Set<type>Field(JNIEnv *env,jobject obj,jfieldID fieldID,NativeType value)

Sets the value of a non-static property of a class. Among them, which attribute is determined by GetFieldID(). This is shorthand for a set of functions, as follows:

void SetObjectField(jobject)

void SetBooleanField(jboolean)

void SetByteField(jbyte)

void SetCharField(jchar)

void SetShortField(jshort)

void SetIntField(jint)

void SetLongField(jlong)

void SetFloatField(jfloat)

void SetDoubleField(jdouble)

Parameter explanation:

  • env: JNI interface pointer
  • obj: Java object, cannot be empty
  • fieldID: a valid field ID
  • value: the new value of the attribute

(10), get a method id of a class

jmethodID GetMethodID(JNIEnv *env,jclass clazz,const char*name,const char* sig);

Returns the method ID of a class or interface, which can be defined in the parent class of clazz and then inherited by clazz. We identify a method based on its name and signature.

GetMethodID () will cause the class that has not been initialized to be initialized.
If you want to get the ID of the constructor, provide init as the method name and void (V) as the return type.

Parameter explanation:

  • env: JNI interface pointer
  • clazz: Java class object
  • name: method name that ends with 0 and is a string of "utf-8"
  • sig: method signature that ends with 0 and is a string of "utf-8"

return:

  • Returns a method ID, if the specified method is not found, it returns NULL

abnormal:

  • If the specified method cannot be found, NoSuchMethodError is thrown
  • If initialization fails, ExceptionInInitializerError is thrown
  • If there is not enough memory, an OutOfMemoryError is thrown

(11), calling a non-static method "series" of a Java instance

NativeType Call<type>Method(JNIEnv *env,jobject obj,jmethodID methodID,...);
NativeType Call<type>MethodA(JNIEnv *env,jobjct obj,jmethodID methodID ,const jvalue *args);
NativeType  Call<type>MethodV(JNEnv *env,jobject obj,jmethodID methodID,va_list args); 

These columns are all calling a non-static method of a Java object in native, and the difference between them is that they pass parameters differently. It is to specify a certain method of the corresponding Java object according to the method ID. The methodID parameter needs to be obtained by calling GetMethodID().

When a "private" function or constructor needs to be called, the methodID must be a method of the obj class, not a method of its parent class.

Let's take a look at their differences

  • CallMethod: You need to put the input parameters of the method after the parameter methodID. CallMethod() actually passes these parameters to the Java method that needs to be called.
  • CallMethodA: Behind the methodID, there is an args array of type jvalue, which stores all the parameters that need to be passed to the constructor. CallMethodA() receives the parameters in this array and passes them to the corresponding Java method in order
  • CallMethodV: Behind the methodID, there is a parameter args of type Wieva_list, which stores all the parameters that need to be passed to the constructor. CallMethodV() receives all parameters and passes them in order to the Java method that needs to be called.
Call<type>Method Routine Name            Native Type

CallVoidMethod() 
CallVoidMethodA()                        void
CallVoidMethodV()                       

CallObjectMethod()
CallObjectMethodA()                      jobject
CallObjectMethodV()

CallBooleanMethod()
CallBooleanMethodA()                     jboolean
CallBooleanMethodV()

CallByteMethod()
CallByteMethodA()                        jbyte
CallByteMethodV()

CallCharMethod()
CallCharMethodA()                        jchar
CallCharMethodV()

CallShortMethod() 
CallShortMethodA()                       jshort
CallShortMethodV()

CallIntMethod()
CallIntMethodA()                         jint
CallIntMethodV()

CallLongMethod()
CallLongMethodA()
CallLongMethodV()

CallFloatMethod()
CallFloatMethodA()                        jlong
CallFloatMethodV()

CallDoubleMethod()
CallDoubleMethodA()                      jfloat
CallDoubleMethodV()

Parameter explanation:

  • env: JNI interface pointer
  • obj: the corresponding Java object
  • methodID: the method id of a method

return:

  • Returns the result corresponding to calling the Java method

abnormal:

  • An exception occurs during the execution of a Java method.

(12), calling a non-abstract method of a class

Call the instance method in the parent class, as follows:

CallNonvirtual<type>Method 
CallNonvirtual<type>MethodA 
CallNonvirtual<type>MethodV 

details as follows:

NativeType CallNonvirtual<Type>Method(JNIEnv *env,jobject obj,jclass clazz,jmethodID methodID,....);
NativeType CallNonvirtual<Type>MethodA(JNIEnv *env,jobject obj,jclass clazz,jmethodID methodID,const jvalue *args);
NativeType CallNonvirtual<type>MethodV(JNIEnv *env, jobject obj,
jclass clazz, jmethodID methodID, va_list args);

This series of operations is to call the non-static method of the instance of the Java object according to the specific class and its method ID. The methodID parameter needs to be obtained by calling GetMethodID().

CallNonvirtual<Type>Method and Call<type>Method are different, where CallNonvirtual<Type>Method is based on "class", and Call<type>Method is based on class object. So the input parameter of CallNonvirtual<Type>Method is clazz, methodID must come from the class of obi, not its parent class.

Let's take a look at their differences

  • CallNonvirtual<type>Method : You need to put the input parameters of the method after the parameter methodID. CallNonvirtual<type>Method() actually passes these parameters to the Java method that needs to be called.
  • CallNonvirtual<type>Method: Behind the methodID, there is an args array of type jvalue, which stores all the parameters that need to be passed to the constructor. CallNonvirtual<type>Method() receives the parameters in this array and passes them to the corresponding Java method in order
  • CallNonvirtual<type>MethodV: Behind the methodID, there is a parameter args of type Wieva_list, which stores all the parameters that need to be passed to the constructor. CallNonvirtual<type>MethodV() receives all parameters and passes them in order to the Java method that needs to be called.

Expand the above series of methods as follows:

CallNonvirtual<type>Method Routine Name      Native Type
CallNonvirtualVoidMethod()
CallNonvirtualVoidMethodA()                  void
CallNonvirtualVoidMethodV()

CallNonvirtualObjectMethod()
CallNonvirtualObjectMethodA()                jobject
CallNonvirtualObjectMethodV()

CallNonvirtualBooleanMethod()
CallNonvirtualBooleanMethodA()               jboolean
CallNonvirtualBooleanMethodV()

CallNonvirtualByteMethod()
CallNonvirtualByteMethodA()                  jbyte
CallNonvirtualByteMethodV()

CallNonvirtualCharMethod()
CallNonvirtualCharMethodA()                  jchar
CallNonvirtualCharMethodV()

CallNonvirtualShortMethod()
CallNonvirtualShortMethodA()                 jshort
CallNonvirtualShortMethodV()

CallNonvirtualIntMethod()
CallNonvirtualIntMethodA()                   jint
CallNonvirtualIntMethodV()

CallNonvirtualLongMethod()
CallNonvirtualLongMethodA()                  jlong
CallNonvirtualLongMethodV()

CallNonvirtualFloatMethod()
CallNonvirtualFloatMethodA()                 jfloat
CallNonvirtualFloatMethodV()

CallNonvirtualDoubleMethod()
CallNonvirtualDoubleMethodA()                jdouble
CallNonvirtualDoubleMethodV()

Parameter explanation:

  • env: JNI interface pointer
  • obj: Java object
  • clazz: Java class
  • methodID: Method ID

return:

  • The result of calling the Java method

Throw an exception:

  • Exceptions that may occur during the execution of a Java method

(13), get static attributes

jfieldID GetStaticFieldID(JNIEnv *env,jclass clazz,const char* name,const char *sig);

Obtain a static attribute ID of a class, and determine which attribute it is based on the attribute name and label. GetStaticField() and SetStaticField() operate on properties by using the property ID. If the class has not been initialized, calling GetStaticFieldID() directly will cause the class to be initialized.

Parameter explanation:

  • env: JNI interface pointer
  • clazz: Java class
  • name: The attribute name of the static attribute, which is a string encoded in "utf-8" and terminated by 0.
  • sig: The signature of the attribute, which is a string encoded in "utf-8" and terminated by 0.

return:

Returns the static attribute ID, or NULL if the specified static attribute cannot be found

abnormal:

  • Throws NoSuchFieldError if the specified static property cannot be found
  • ExceptionInInitializerError is thrown if the class fails to initialize
  • If there is not enough memory, an OutOfMemoryError is thrown

(14), get the static attribute series

NativeType GetStatic<type>Field(JNIEnv *env,jclass clazz,jfieldID fieldID);

This series returns the value of a static property of an object. The ID of the static attribute can be obtained through GetStaticFieldID(). With this ID, we can obtain this and operate on it.

The function name and return value of the function are shown below, so you only need to replace the class in GetStatic<type>Field with the Java type of the field or the actual static field accessor in the table. and replace NativeType with the corresponding native type:

GetStatic<type>Field Routine Name      Native Type
GetStaticObjectField()                 jobject
GetStaticBooleanField()                jboolean
GetStaticByteField()                   jbyte
GetStaticCharField()                   jchar
GetStaticShortField()                  jshort
GetStaticIntField()                    jint
GetStaticLongField()                   jlong
GetStaticFloatField()                  jfloat
GetStaticDoubleField()                 jdouble

Parameter explanation:

  • env: JNI interface pointer
  • clazz: Java class
  • field: static attribute ID

return:

  • return static property

(15), set the static attribute series

void SetStatic<type>Field(JNIEnv *env,jclass clazz,jfieldID fieldID,NativeType value);

This series is to set the value of the static property of the class. The ID of a static field can be obtained through GetStaticFieldID().

The function name and its value are introduced in detail below. You can set the static property in Java through SetStatic<type> and the NativeType passed in.

SetStatic<type>Field Routine Name         NativeType
SetStaticObjectField()                    jobject
SetStaticBooleanField()                   jboolean
SetStaticByteField()                      jbyte
SetStaticCharField()                      jchar
SetStaticShortField()                     jshort
SetStaticIntField()                       jint
SetStaticLongField()                      jlong
SetStaticFloatField()                     jfloat
SetStaticDoubleField()                    jdouble

Parameter explanation:

  • env: JNI interface pointer
  • clazz: Java class
  • field: static attribute ID
  • value: set value

(16), get the static function ID

jmethodID GetStaticMethodID(JNIEnv *env,jclass clazz,const char *name,const char sig);

Returns the static method ID of the class, which method is identified by its method name and signature. If the class has not been initialized, calling GetStaticMethodID() will cause the class to be initialized.

Parameter explanation:

  • env: JNI interface pointer
  • clazz: Java class
  • name: The method name of the static method, encoded in "utf-8", and terminated by 0
  • sig: method signature, encoded in "utf-8", and a 0-terminated string

return:

  • Returns the method ID, or NULL if the operation failed

abnormal:

  • If no corresponding static method is found, NoSuchMethodError is thrown
  • Throws ExceptionInInitializerError if class initialization fails
  • Throws OutOfMemoryError if the system is out of memory

(17), calling static function series

NativeType CallStatic<type>Method(JNIEnv *env,jclass clazz,jmethodID methodID,...);
NativeType CallStatic<type>MethodA(JNIEnv *env,jclass clazz,jmethodID methodID,... jvalue *args);
NativeType CallStatic<type>MethodV(JNIEnv *env,jclass,jmethodID methodid, va_list args)

According to the specified method ID, you can operate the static method of the Java object. The methodID can be obtained through GetStaticMethodID(). The ID of the method must be clazz's, not the method ID of its parent class.

The following is the detailed method:

CallStatic<type>Method Routine Name                Native Type
CallStaticVoidMethod()
CallStaticVoidMethodA()                            void
CallStaticVoidMethodV()

CallStaticObjectMethod()
CallStaticObjectMethodA()                          jobject
CallStaticObjectMethodV()

CallStaticBooleanMethod()
CallStaticBooleanMethodA()                         jboolean
CallStaticBooleanMethodV()

CallStaticByteMethod()
CallStaticByteMethodA()                            jbyte
CallStaticByteMethodV()

CallStaticCharMethod()
CallStaticCharMethodA()                            jchar
CallStaticCharMethodV()

CallStaticShortMethod()
CallStaticShortMethodA()                           jshort
CallStaticShortMethodV()

CallStaticIntMethod()
CallStaticIntMethodA()                             jint
CallStaticIntMethodV()

CallStaticLongMethod()
CallStaticLongMethodA()                            jlong
CallStaticLongMethodV()

CallStaticFloatMethod()
CallStaticFloatMethodA()                           jfloat
CallStaticFloatMethodV()

CallStaticDoubleMethod()
CallStaticDoubleMethodA()                          jdouble
CallStaticDoubleMethodV()

Parameter explanation:

  • env: JNI interface pointer
  • clazz: Java class
  • methodID: static method ID

return:

  • Returns the calling method of a static Java method

abnormal:

  • Exception thrown during execution of Java method

Seven, string operation

(1), create a string

jstring NewString(JNIEnv *env,const jchar *unicodeChars,jszie len);

Parameter explanation:

  • env: JNI interface pointer
  • unicodeChars: pointer to Unicode character string
  • len: the length of the unicode string

return:

  • Returns a Java string object, or NULL if the string cannot be created

abnormal:

  • Throws OutOfMemoryError if out of memory

(2) Get the length of the string

jsize  GetStringLength(JNIEnv *env,jstring string);

Returns the length of the Java string (the number of unicode characters)

Parameter explanation:

  • env: JNI interface pointer
  • string: Java string object

return:

  • Returns the length of a Java String

(3) Obtain the pointer of the string

const jchar* GetStringChar(JNIEnv *env,jstring string , jboolean *isCopy);

Returns a pointer to the UNICODE character array of the string, which is valid until the ReleaseStringchars() function is called.

If isCopy is non-null, set isCopy to JNI_TRUE after the copy is complete. Set to JNI_FALSE if no replication.

Parameter explanation:

  • env: JNI interface pointer
  • string: Java string object
  • isCopy: pointer to boolean value

return:

  • Returns a pointer to a unicode string, or NULL if the operation fails

(4), release the string

void ReleaseStringChars(JNIEnv *env,jstring string,const jchar *chars);

Through the VM, native code will no longer access chars. The parameter chars is a pointer. It can be obtained through the GetStringChars() function.

Parameter explanation:

  • env: JNI interface pointer
  • string: Java string object
  • chars: pointer to Unicode character string

(5) Create a UTF-8 string

jstring NewStringUTF(JNIEnv *env,const char *bytes);

Create a UTF-8 string.

Parameter explanation:

  • env: JNI interface pointer
  • bytes: pointer to UTF-8 string

return:

  • A Java String object, or NULL if the string could not be constructed.

abnormal:

  • Throws OutOfMemoryError if the system is out of memory

(6) Get the length of a UTF-8 string

jsize GetStringUTFLength(JNIEnv *env,jstring string);

Returns the UTF-8 length of the string in bytes.

Parameter explanation:

  • env: JNI interface pointer
  • String: Java string object

return:

  • UTF-8 length of the string

(7), Get the pointer of StringUTFChars

const char *GetStringUFTChars(JNIEnv *env, jString string, jboolean *isCopy);

Returns a pointer to a UTF-8 character array, which remains valid unless the array is released by the ReleaseStringUTFChars() function call.

If isCopy is not NULL, *isCopy is set to JNI_TRUE after the assignment is complete. Set to JNI_FALSE if not copied.

Parameter explanation:

  • env: JNI interface pointer
  • String: Java string object
  • isCopy: pointer to boolean value

return:

  • Pointer to a UTF-8 string, or NULL if the operation failed.

(8), release UTFChars

void ReleaseStringUTFChars(JNIEnv *env,jstring string,const char *urf)

Through the virtual machine, the native code no longer accesses utf. utf is a pointer, which can be obtained by calling GetStringUTFChars().

Parameter explanation:

  • env: JNI interface pointer
  • string: Java string object
  • utf: pointer to utf-8 string

Note: In JDK/JRE 1.1, programmers can get basic type array elements in user-supplied buffers. Starting from JDK/JRE1.2, additional methods are provided that allow Unicode characters (UTF -16 encoding) or UTF-8 characters. These methods are as follows:

(9), JRE1.2 new string operation method

1. Intercept a string

void GetStringRegion(JNIEnv *env,jstring str,jsize start,jsize len,jchar *buf)

Intercept the length of len from the start position in str (Unicode character) and place it in buf. Throws StringIndexOutOfBoundsException if out of bounds.

2. Intercept a string and convert it to UTF-8 format

void GetStringUTFRegion(JNIEnv *env,jstring str,jsize start ,jsize len,char *buf);

Intercept str (Unicode string) with a length of len from the start position and convert it to UTF-8 encoding, and then store the result in buf.

3. Intercept a string and convert it to UTF-8 format

const jchar * GetStringCritical(JNIEnv *env,jstring string,jboolean *isCopy);
void ReleaseStringCritical(JNIEnv *env,jstring string,cost jchar * carray);

The above two functions are somewhat similar to the GetStringChars() and ReleaseStringChars() functions. The virtual machine returns a pointer to the string element if possible; otherwise, a copied copy.

GetStringChars () and ReleaseStringChars () These two functions have great limitations. When using these two functions, the code between these two functions cannot call any native functions or JNI functions that make the thread block or wait for other threads of the JVM. With these restrictions, the JVM can disable GC when a native method holds a pointer to a string obtained from GetStringCritical. When GC is disabled, any thread that initiates GC will be blocked. However, any native code between the two functions GetStringChars() and ReleaseStringChars() cannot execute calls that cause blocking or allocate memory in the JVM for new objects. Otherwise, the JVM may deadlock, imagine this scenario:

  1. Only when the GC triggered by the current thread finishes blocking and releases the GC, can the GC initiated by other threads be released from the blocking and continue to execute.
  2. During this process, the current thread will always be blocked, because any blocking call needs to acquire a lock that is being held by other threads, while other threads are waiting for GC.

Alternate iterative calls of GetStringChars() and ReleaseStringChars() are safe, in which case their use must be strictly ordered. Moreover, we must remember to check whether its return value is NULL due to memory overflow. Because the JVM still has the possibility of data copying when executing the GetStringChars() function, especially when the array stored by the JVM in memory is discontinuous, in order to return a pointer to a continuous memory space, the JVM must copy all data.

In summary, to avoid deadlocks, do not call any JNI functions between GetStringChars() and ReleaseStringChars().

Eight, array operation

(1) Get the length of the array

jsize GetArrayLength(JNIEnv *env,jarray array)

Returns the length of the array.

Parameter explanation:

  • env: JNI interface pointer
  • array: Java array

return:

  • the length of the array

(2) Create an array of objects

jobjectArray NewObjectArray(JNIEnv *env,jsize length,jclass elementClass, jobject initialElement);

Creates a new array of objects whose elements are of type elementClass and whose default value is initialElement.

Parameter explanation:

  • env: JNI interface pointer
  • length: array size
  • elementClass: array element class
  • initialElement: the initial value of the array element

return:

  • Java array object, or NULL if the array cannot be constructed

abnormal:

  • Throws OutOfMemoryError if out of memory

(3) Get an element in the array element

jobject GetObjectArrayElement(JNIEnv *env,jobjectArray array,jsize index);

Returns the element at a position within the element.

Parameter explanation:

  • env: JNI interface pointer
  • array: Java array
  • index: array subscript

return:

  • java object

abnormal:

  • If the index subscript is not a valid subscript, an ArrayIndexOutOfBoundsException will be thrown

(4), set the value of an element in the array

void SetObjectArrayElement(JNIEnv *env,jobjectArray array,jsize index,jobject value);

Sets the subscript to the value of the index element.

Parameter explanation:

  • env: JNI interface pointer
  • array: Java array
  • index: array subscript
  • value: the new value of the array element

abnormal:

  • If index is not a valid subscript, an ArrayIndexOutOfBoundsException will be thrown
  • ArrayStoreException will be thrown if value is not a subclass of the element class

(5) Create a series of basic type arrays

ArrayType New<PrimitiveType>Array(JNIEnv *env,jsize length);

A sequence of operations for constructing array objects of primitive types. The creation functions for arrays of specific primitive types are described below. You can replace New<PrimitiveType>Array with an actual primitive type array creation function, and then replace ArrayType with the corresponding array type.

New<PrimitiveType>Array Routines           Array Type
NewBooleanArray()                          jbooleanArray
NewByteArray()                             jbyteArray
NewCharArray()                             jcharArray
NewShortArray()                            jshortArray
NewIntArray()                              jintArray
NewLongArray()                             jlongArray
NewFloatArray()                            jfloatArray
NewDoubleArray()                           jdoubleArray

Parameter explanation:

  • env: JNI interface pointer
  • length: array length

return:

  • The Java array, or NULL if the array could not be created.

(6) Obtain the medium array pointer series of the basic type array

NativeType * Get<PrimitiveType>ArrayElements(JNIEnv *env,ArrayType array,jboolean * isCopy);

A set of functions that return array bodies of primitive types. The result will remain valid until the corresponding Release<PrimitiveType>ArrayElements() function is called. Since the returned array may be a copy of the Java array, changes to the returned array do not have to be reflected in the primitive array until the Release<PrimitiveType>ArrayElements() function is called.

If isCopy is not NULL, *isCopy is set to JNI_TRUE after the copy is complete. Set to JNI_FALSE if not copied.

Specific functions for specific primitive type array elements are described below:

  • Replace Get<PrimitiveType>ArrayElements with a function of some actual primitive> type in the table
  • Replace ArrayType with the corresponding array type
  • Replace NativeType with local variable

Regardless of how the Boolean array is always represented in the Java virtual machine, GetBooleanArrayElements() will always return a pointer of jboolean type, where each byte represents an element (open package representation). Arrays of all other types are guaranteed to be contiguous in memory.

Get<PrimitiveType>ArrayElements Routines     Array Type         Native Type
GetBooleanArrayElements()                    jbooleanArray      jboolean
GetByteArrayElements()                       jbyteArray         jbyte
GetCharArrayElements()                       jcharArray         jchar
GetShortArrayElements()                      jshortArray        jshort
GetIntArrayElements()                        jintArray          jint
GetLongArrayElements()                       jlongArray         jlong
GetFloatArrayElements()                      jfloatArray        jfloat
GetDoubleArrayElements()                     jdoubleArray       jdouble

Parameter explanation:

  • env: JNI interface pointer
  • array: Java array
  • isCopy: pointer to boolean value

return:

  • Returns a pointer to an element of the array, or NULL if the operation failed

(7) Release the array series of basic types

void Release<PrimitiveType>ArrayElements(JNIEnv *env,ArrayType array,NativeType *elems,jint mode);

Notify the virtual machine that Native no longer accesses the elements of the array. The elems parameter is a pointer returned by the corresponding Get<PrimitiveType> ArrayElements() function array element. This function copies all transformations on elems to the original array elements, if necessary. The mode parameter provides how the array buffer should be freed. If elems is not a copy of array, mode has no effect.

The value of mode has the following three situations:

  • 0: copy content and release elems buffer
  • JNI_COMMIT: copy content but do not release elems buffer
  • JNI_ABORT: free buffer without copying possible changes

Most of the time, programmers pass "0" as an argument because this ensures consistent behavior of pinning and copying arrays. Other options give the programmer more control over memory.

Specific functions for specific primitive type array elements are described below:

  • Replace Release <PrimitiveType> ArrayElements with one of the actual primitive> type functions below
  • Replace ArrayType with the corresponding basic array type
  • Replace NativeType with local variable

The details of freeing arrays of primitive types are described below. You should make the following substitutions:

Release<PrimitiveType>ArrayElements Routines     Array Type               Native Type
ReleaseBooleanArrayElements()                    jbooleanArray            jboolean
ReleaseByteArrayElements()                       jbyteArray               jbyte
ReleaseCharArrayElements()                       jcharArray               jchar
ReleaseShortArrayElements()                      jshortArray              jshort
ReleaseIntArrayElements()                        jintArray                jint
ReleaseLongArrayElements()                       jlongArray               jlong
ReleaseFloatArrayElements()                      jfloatArray              jfloat
ReleaseDoubleArrayElements()                     jdoubleArray             jdouble

Parameter explanation:

  • env: JNI interface pointer
  • array: Java array
  • elems: pointer to an array of primitive types
  • mode: release mode

(8), copy the array series of basic types in the past

void Get<PrimitiveType> ArrayRegion(JNIEnv *env,ArrayType array,jsize start,jsize len,NativeType *buf);

Copy an array of primitive types to buff

Specific functions for specific primitive type array elements are described below:

  • Replace Get<PrimitiveType> ArrayRegion with one of the actual primitive> type functions below
  • Replace ArrayType with the corresponding basic array type
  • Replace NativeType with local variable
Get<PrimitiveType>ArrayRegion Routine           Array Type              Native Type
GetBooleanArrayRegion()                         jbooleanArray           jboolean
GetByteArrayRegion()                            jbyteArray              jbyte
GetCharArrayRegion()                            jcharArray              jchar
GetShortArrayRegion()                           jshortArray             jhort
GetIntArrayRegion()                             jintArray               jint
GetLongArrayRegion()                            jlongArray              jlong
GetFloatArrayRegion()                           jfloatArray             jloat
GetDoubleArrayRegion()                          jdoubleArray            jdouble

Parameter explanation:

  • env: JNI interface pointer
  • array: Java array
  • start: start index
  • len: the length to be copied
  • buf: target buffer

abnormal:

  • Throws ArrayIndexOutOfBoundsException if the index is invalid

(9), copy the array of the basic type array back to the series

void Set<PrimitiveType> ArrayRegion(JNIEnv *env,ArrayType array,jsize start,jsize len,const NativeType *buf);

It is mainly a function for buffering and copying arrays of basic types.

Specific functions for specific primitive type array elements are described below:

  • Replace Set<PrimitiveType>ArrayRegion with one of the actual basic> type functions below
  • Replace ArrayType with the corresponding basic array type
  • Replace NativeType with local variable
Set<PrimitiveType>ArrayRegion Routine        Array Type            Native Type
SetBooleanArrayRegion()                      jbooleanArray         jboolean
SetByteArrayRegion()                         jbyteArray            jbyte
SetCharArrayRegion()                         jcharArray            jchar
SetShortArrayRegion()                        jshortArray           jshort
SetIntArrayRegion()                          jintArray             jint
SetLongArrayRegion()                         jlongArray            jlong
SetFloatArrayRegion()                        jfloatArray           jfloat 
SetDoubleArrayRegion()                       jdoubleArray          jdouble

Parameter explanation:

  • env: JNI interface pointer
  • array: Java array
  • start: start index
  • len: the length to be copied
  • buf:源buffer

abnormal:

  • ArrayIndexOutOfBoundsException will be thrown if the index is invalid

(10), Supplement

Starting from JDK/JER 1.1, the Get/Release<primitivetype>ArrayElements function is provided to obtain pointers to primitive array elements. Returns a pointer to the original array if the VM supports locking, otherwise a copy.
Starting from JDK/JRE 1.3 new features are introduced, even if the VM does not support locking, native code can obtain direct pointers to array elements.

void *GetPrimitiveArrayCritical(JNIEnv *env,jarray array,jboolean *isCopy);
void ReleasePrimitiveArrayCritical(JNIEnv *env,jarray array,void *carray,jint mode);

Although these two functions are very similar to the Get/Release <primitivetype> ArrayElements function above, there are still many restrictions when using this function.

After calling GetPrimitiveArrayCritical and before calling ReleasePrimitiveArrayCritical, this area cannot call other JNI functions, nor can it call any system calls that may cause the thread to block and wait for another Java thread.

For example, the current thread cannot call the read function to read streams that are being written by other streams.

Nine system-level operations

(1) Registration method

jint RegisterNatives(JNIEnv *env,jclass clazz,const JNINativeMethod *methods,jint nMethod);

The local method is registered according to the clazz parameter, and the methods parameter formulates the JNINativeMethod structure array, which contains the name, signature and function pointer of the local method. Among them, the name and signature are pointers to the encoding "UTF-8"; the nMethod parameter indicates the number of local methods in the array.

Here is the JNINativeMethod structure:

typedef struct { 
char *name; 
char *signature; 
void *fnPtr; 
} JNINativeMethod; 

Parameter explanation:

  • env: JNI interface pointer
  • clazz: Java class object
  • methods: native methods in the class
  • nMethod: the number of native methods in the class

return;

  • Success returns 0, failure returns a negative number

abnormal:

  • If the specified method is not found or the method is not a native method, NoSuchMethodError is thrown.

(2) Cancellation method

jint UnregisterNatives(JNIEnv *env,jclass clazz);

Unregister a native method. The class reclaims the state that has not been registered by the function before. This function generally cannot be called in Native code, and it provides a method for reloading and relinking native libraries for specific programs.

Parameter explanation:

  • JNI: interface pointer
  • clazz: Java class object

return:

  • If the logout is successful, it returns 0, and if it fails, it returns a negative number

(3) Monitoring operation

jint MonitorEnter(JNIEnv *env,jobject obj);

The monitor associated with the underlying Java object referenced by obj. obj reference cannot be null. Every Java object has an associated monitor. If the current thread already has a monitor associated with obj, it will add the monitor's counter to indicate the number of times this thread has entered the monitor. If the monitor associated with obj does not belong to any thread, the current thread will become the owner of the monitor and set the counter to 1. If other counters already own the monitor, the current thread will wait until the monitor is acquired Release, and then take ownership of the monitor.

A monitor invoked through the MonitorEnter JNI function cannot be exited with the monitorexitJVM instruction or a synchronous method. The MonitorEnterJNI function call and the monitorenter Java virtual machine instruction may compete to enter the monitor with the same object.

To avoid deadlocks, monitors entered through the MonitorEnterJNI function call must be exited with the MonitorExitJNI call, unless the DetachCurrentThread interface is implicitly called to release the JNI monitor

Parameter explanation:

  • env: JNI interface pointer
  • obj: ordinary Java object or class object

return:

  • Success returns 0, failure returns a negative number

(4) Monitor exit

jint MonitorExit(JNIEnv *env,jobject obj);

The current thread owns the monitor associated with this obj, and the thread decrements the counter to indicate the number of times the thread has entered the monitor. If the value of the counter becomes 0, the thread releases the monitor. Native code cannot directly call MonitorExit to release the monitor. Instead, use the Java Virtual Machine instruction to release the monitor through a synchronous method

Parameter explanation:

  • env: JNI interface pointer
  • obj: ordinary Java object or class object

return:

  • Success returns 0, failure returns a negative number

abnormal:

  • If the current thread does not own the monitor, an IllegalMonitorStateException should be thrown

Ten NIO operations

NIO-related operations allow Native code to directly access java.nio's direct buffers. The content of the direct buffer may exist in local memory outside of the normal garbage collector. For information on direct buffers, refer to the specifications of the NIO and java.nio.ByteBuffer classes.

In JDK/JRE 1.4 new JNI functions were introduced that allow inspection and manipulation of direct buffers

  • NewDirectByteBuffer
  • GetDirectBufferAddress
  • GetDirectBufferCapacity

Every Java virtual machine implementation is required to support these features, but not every implementation is required to support JNI access to direct buffers. If the JVM does not support such access, the NewDirectByteBuffer and GetDirectBufferAddress functions must always return NULL, and the GetDirectBufferCapacity function must always return -1. If the JVM does support such access, then these three functions must be implemented to return suitable values.

(1) Return ByteBuffer

jobject NewDirectByteBuffer(JNIEnv *env,void *address,jlong capacity);

Allocates and returns a direct java.nio.ByteBuffer memory block capacity bytes starting at memory address address.

Native code that calls this function and returns a byte buffer object must ensure that the buffer points to a reliable memory area that can be read and written. Entering an illegal memory location may return an arbitrary value, DNA will not be visibly impressed, and an exception may be thrown.

Parameter explanation:

  • env: JNIEnv interface pointer
  • address: the starting address of the memory area
  • capacity: the size of the memory area

return:

Returns a local reference to a newly opened java.nio.ByteBuffer object. Returns NULL if an exception occurs. If the JVM does not support JNI access to direct buffers, it will also return NULL

abnormal:

Returns OutOfMemoryError if buffer allocation fails

(2) Return the initial address of the object in the direct buffer

void* GetDirectBufferAddress(JNIEnv *env,jobject buf);

Get and return the initial memory address of java.nio.Buffer.

This function allows Native code to access the same memory area as Java code through a direct buffer object.

Parameter explanation:

  • env: JNIEnv interface pointer
  • buffer:java.nio.Buffer对象

return:

Returns the initial address of the memory region. Returns NULL if the memory region is undefined, returns NULL if the given object is not a java.nio.buffer, or returns NULL if the virtual machine does not support JNI access.

(3) Return the memory capacity of the object in the direct buffer

jlong GetDirectBufferCapacity(JNIEnv *env,jobject buf);

Get and return the memory capacity of java.nio.Buffer. The capacity is the number of elements that the memory area can hold

parameter:

  • env: JNIEnv interface pointer
  • buffer:java.nio.Buffer对象

return:

Returns the capacity of the memory region. Returns -1 if the specified object is not a java.nio.buffer, or if the object is an unaligned view buffer and the processor architecture does not support aligned access. Returns -1 if the virtual machine does not support JNI access.

11. Reflection support

If the programmer knows the names and types of methods and properties, he can directly use JNI to call Java methods or access Java fields. The Java core reflection API allows reflection of Java classes at runtime. JNI provides a set of conversion functions between field and method IDs used in JNI and field and method objects used in the Java Core Reflection API.

(1) Conversion and acquisition method ID

jmethodID FromReflectedMethod(JNIEnv *env,jobject method);

Convert a java.lang.reflect.Method or java.lang.reflect.Constructor object to a method ID.

Parameter explanation:

  • env: JNIEnv interface pointer
  • method: java.lang.reflect.Method or java.lang.reflect.Constructor object

return:

  • Method ID

(2), conversion to obtain attribute ID

jfield FromReflectedField(JNIEnv *env,jobject field);

Convert java.lang.reflect.Field to ID.

Parameter explanation:

  • env: JNIEnv interface pointer
  • field: java.lang.reflect.Field object

return:

  • Region ID

(3) Reverse transformation and obtain the method object

jobject ToReflectedMethod(JNIEnv *env,jclass clazz,jmethodID methodID, jboolean isStatic);

Convert method ID from cls to java.lang.reflect.Method or java.lang.reflect.Constructor object. isStatic must be set to JNI_TRUE if the method ID points to a static property, or JNI_FALSE otherwise.

Parameter explanation:

  • env: JNIEnv interface pointer
  • clazz: Java class object
  • methodID: the method id corresponding to the Java class
  • isStatic: whether it is a static method

return

Corresponds to the Java layer java.lang.reflect.Method or java.lang.reflect.Constructor object. Returns 0 on failure

abnormal:

If there is insufficient memory, an OutOfMemoryError is thrown.

(4), reverse transformation and get the attribute object

jobject ToReflectedField(JNIEnv *env,jclass cls,jfieldID field,jboolean isStatic)

Convert the attribute ID from cls to java.lang.reflect.Field object. isStatic must be set to JNI_TRUE if the property ID points to a static property, or JNI_FALSE otherwise.

Parameter explanation:

  • env: JNIEnv interface pointer
  • cls: Java class object
  • methodID: Java corresponding attribute ID
  • isStatic: whether it is a static property

return:

Return java.lang.reflect.Field object successfully, return 0 if failed

abnormal:

Throws OutOfMemoryError if out of memory

12. Obtain a virtual machine

jint GetJavaVM(JNIEnv *env,JavaVM **vm);

Returns the java virtual machine interface corresponding to the current thread. The returned result is saved in vm.

Parameter explanation:

  • env: JNI interface pointer
  • vm: save the virtual machine pointer

return:

It returns 0 on success, and a negative number on failure.

Guess you like

Origin blog.csdn.net/Jason_Lee155/article/details/132274563