JNI and NDK Programming Knowledge Points

Keywords: Java Android jvm Programming

Summarize the knowledge points related to JNI and NDK.

Reprinted please indicate: http://blog.csdn.net/feather_wch/article/details/79599270

JNI and NDK Programming

Version: 2018/3/18-1 (11:36)

Brief Introduction to JNI and NDK

1. What is JNI? Effect?

  1. Java Native Interface(java Local Interface)
  2. A Layer of Interface Encapsulated by Local Code such as C, C++ Convenient Java Call

2. Why do you need JNI?

  1. Java is characterized by cross-platform, but it will lead to the lack of strong local interaction capabilities, some operating system-related features Java is unable to complete - so Java provides JNI specifically for interacting with local code, which in turn enhances local interaction capabilities.
  2. Existing open source libraries can be used, and many excellent open source libraries are written in C/C++.
  3. Code protection, Android apk's java code is easy to decompile, and C/C++ is more difficult to decompile.
  4. It is easy to transplant, and the library written in C/C++ can be easily used in other embedded platforms.

3. What is NDK?

  1. NDK is a collection of tools provided by Android
  2. With NDK, local code can be accessed more easily through JNI in Android, such as C C++.
  3. NDK also provides a cross-compiler that generates dynamic libraries for specific CPU platforms by simply modifying mk files

4. Advantages of NDK

  1. Improving Code Security-so Library Decompilation is Difficult
  2. It is easy to use the existing C/C++ open source libraries.
  3. Easy to transplant between platforms --- Dynamic libraries implemented by C/C++ can be easily used on other platforms.
  4. Improving the execution efficiency of the program in some specific circumstances, but it can not significantly improve the performance of Android programs.

5. How to integrate JNI function in AS3.0

  1. Download NDK, CMake (Advanced Compiler Configuration Tool) and LLDB (Efficient C/C++ Debugger) in AS3.0
  2. Java's native method generates corresponding header files through javah
  3. Writing C/C++ Code
  4. CMakeList file configuration

6. The role of JNIEXPORT and JNICALL keywords in cpp code?

  1. These two keywords are two macro definitions
  2. Used to illustrate that this function is a JNI function. When the Java virtual machine loads, it links the corresponding native method.

7. When Java Virtual Machine loads so library, how to find the corresponding hative method in Java layer? (Static registration)

  1. Matching by the function name of the JNI function: Java_PackageName_ClassName_NativeMethodName
  2. You can use the javah-d jni package name in app/build/intermediates/classes/debug. The class name generates the jni directory under the debug directory (-d jni parameter specifies), and generates the corresponding H header file in it.

8. What is the parameter jobject in the automatically generated JNI function?

  1. The class object (equivalent to this in Java) to which the native method currently connected to the JNI function belongs

9. What is the dynamic registration of JNI?

  1. The process of statically registering native methods is to match Java layer native methods with JNI functions one by one.
  2. Dynamic registration enables native methods in the Java layer to be linked to any JNI function.

10. Steps for dynamic registration of JNI

  1. Defining native functions in Java
  2. Define the corresponding JNI function in C/C++ (name does not need correspondence at will)
  3. Data Defining JNI native Method in C/C++-Specifying the Corresponding Relations between Multiple native Functions and JNI Functions
  4. Dynamic Registration in JNI_OnLoad() in C/C++
public class JniUtils2 {
    static {
        System.loadLibrary("native-lib");
    }
    public native String getStringFromC();

    public native void dynamicFunction();

    public native void dynamicFunction2();
}
#include "com_hao_jniapp_JniUtils2.h"
#include "android/log.h"

extern "C" {
JNIEXPORT jstring JNICALL Java_com_hao_jniapp_JniUtils2_getStringFromC
        (JNIEnv *env, jobject jobject1) {
    return env->NewStringUTF("I am from JniUtils2 Of Native Method");
}

// 6. JNI function (concrete implementation of native method in Java layer)
static void jniDynamicLog(JNIEnv *evn, jobject obj){
    __android_log_print(ANDROID_LOG_INFO, "feather", "JNI's Log: hello Java! Im from JNI");
}
static void jniTest(JNIEnv *evn, jobject obj){
    __android_log_print(ANDROID_LOG_INFO, "feather", "JNI's Log: hello Java! Im from JNI's Test");
}

/**==========================
 * 7. JNINativeMethod Structures: Recording the correspondence between java's native methods and JNI functions
 *==========================*/
JNINativeMethod nativeMethod[] = {  {"dynamicFunction", //1. Method name of Java layer native method
                                            "()V",      //2. Descriptor of Java Layer native Method
                                            (void*)jniDynamicLog} //3. Pointer of JNI function
                    ,{"dynamicFunction2", "()V", (void*)jniTest}  //4. native/jni of another binding relationship
};

/**===========================================================
 * 1. JNI_OnLoad Called when `System.loadLibarary()` loads so libraries in Java
 * @param jvm *jvm For Java virtual machine instances, Java VM is a structure.
 *==========================================================*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {

    JNIEnv *env;
    //2. *jvm calls GetEnv() to get the JNIEnv variable
    if (jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {

        return -1;
    }
    __android_log_print(ANDROID_LOG_INFO, "feather", "JNI's Log: JNI_OnLoad...");
    //3. The JNIEnv structure points to a function table and gets the JniUtils object
    jclass clz = env->FindClass("com/hao/jniapp/JniUtils2");
    //4. Dynamic registration of Java-level native methods and JNI functions described by JniUtils objects and nativeMethod structures
    env->RegisterNatives(clz, nativeMethod, sizeof(nativeMethod)/sizeof(nativeMethod[0]));

    //5. return the JNI version currently in use
    return JNI_VERSION_1_4;
}

}

11. The Role of JNI Native Method

  1. As a structure, the binding relationship between native method and JNI function is described.
typedef struct {
    const char* name;//Name of Java Layer native Method
    const char* signature;//Descriptor of Java Layer native Method
    void*       fnPtr;//Pointer corresponding to JNI function
} JNINativeMethod;

12. The Role of JNIEnv Structures

  1. Point to a function table that points to a series of JNI functions
  2. With these JNI functions, you can implement the code that calls the Java layer.
//1. Get the ID of a variable in a Java object
jfieldID GetFieldID(jclass clazz, const char* name, const char* sig)
//2. Obtain variables with boolean data type according to the ID of the variable
jboolean GetBooleanField(jobject obj, jfieldID fieldID)
//3. Get the ID of the corresponding method in the Java object
jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
//4. Call the method in the corresponding object according to the method ID, and the method returns void.
CallVoidMethod(jobject obj, jmethodID methodID, ...)
//5. Call the method in the corresponding object according to the method ID, and the method returns boolean.
CallBooleanMethod(jobject obj, jmethodID methodID, ...)

13. The Role of JNI Data Types

  1. Data types and objects in the Java layer and C/C++ cannot be directly referenced and used by each other.
  2. C/C++ pointing to Java is not recognizable.
  3. To sum up: JNI layer defines its own data type to achieve the function of cohesion.

14. What kinds of data types are there in JNI?

  1. There are two types of JNI data types: basic type and reference type.

15. JNI's original data type

Java Type Native Typ 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

16. JNI Reference Type?

  1. JNI defines some reference types to facilitate JNI layer invocation
jobject                     (all Java objects)
|
|-- jclass                  (java.lang.Class objects)
|-- jstring                 (java.lang.String objects)
|-- jarray                  (array)
|     |--jobjectArray       (object arrays)
|     |--jbooleanArray      (boolean arrays)
|     |--jbyteArray         (byte arrays)
|     |--jcharArray         (char arrays)
|     |--jshortArray        (short arrays)
|     |--jintArray          (int arrays)
|     |--jlongArray         (long arrays)
|     |--jfloatArray        (float arrays)
|     |--jdoubleArray       (double arrays)
|
|--jthrowable

17. The role of method ID and variable ID in JNI?

  1. If you want to call a method of Java layer in JNI, you need to get its ID first, and then get the method through JNI function according to ID.
//Variable ID
struct _jfieldID;
typedef struct _jfieldID *jfieldID;

//Method ID
struct _jmethodID;
typedef struct _jmethodID *jmethodID; /* method IDs */

18. The Role of Class Descriptors in JNI

  1. Objects used to retrieve Java.
  2. For example, com. hao. jniapp. JniUtils 2 is a package belonging to this class. It needs to be replaced by com/hao/jniapp/JniUtils 2 - this is the class descriptor (FindClass ("com/hao/jniapp/JniUtils 2").
    3.

19. Method Descriptor?

  1. It is used to determine the parameters and return values of the native method.
  2. "V" in "() V" means that the return value is empty
  3. "()" in "() V" is identified as a parameter
Method Descriptor Java Language Type
"()Ljava/lang/String;" String f();
"(ILjava/lang/Class;)J" long f(int i, Class c);
"([B)V" String(byte[] bytes);

20. Data Type Descriptor

Field Desciptor Java Language Type
Z boolean
B byte
C char
S short
I int
J long
F floa
D double

21. Array descriptor

  1. The descriptor for an array of bits is "[+corresponding type descriptor"
  2. Two-dimensional and three-dimensional arrays, starting with "[" and "[[[]", are similar to more dimensional arrays
Descriptor Java Langauage Type
"[[I" int[][]
"[[[D" double[][][]
Field Desciptor Java Language Type
"Ljava/lang/String;" String
"[Ljava/lang/Object;" Object[]

22. Static method of calling Java in JNI function

  1. Write a general method in the class where the native method in the Java layer resides
  2. Writing functions in C/C++ files requires parameters (JNIEnv *env, jobject thiz) to get Java layer methods internally and call them.
  3. Call the above method in the JNI function of C/C++.
//JniUtils2.Java
public class JniUtils2 {
    static {
        System.loadLibrary("native-lib");
    }
    ...
  //1. Static method
    public static void staticShowMsg(String msg){
        Log.i("feather", "I'm Java Static method: get JNI's msg =" + msg);
    }
}
//xxx.cpp
void callJavaMethod(JNIEnv *env, jobject thiz){
  //1. Get the Java class
    jclass clazz = env->FindClass("com/hao/jniapp/JniUtils2");
    if(clazz == NULL){
        printf("find class JniUtils2 error!");
        return;
    }
  //2. Get method ID
    jmethodID  id = env->GetStaticMethodID(clazz, "staticShowMsg", "(Ljava/lang/String;)V");
    if(id == NULL){
        printf("find method staticShowMsg error!");
    }
  //3. Call the static method and pass in parameters
    jstring msg = env->NewStringUTF("Hello Java! I'm JNI message");
    env->CallStaticVoidMethod(clazz, id, msg);
}

23. Non-static method of calling Java in JNI function

The key point is to call through JNIEnv non-static method, and the corresponding Java object this needs to be passed in as a parameter.

//java
public class JniUtils2 {
    static {
        System.loadLibrary("native-lib");
    }
    ...
    public void showMsg(String msg){
        Log.i("feather", "I'm Java method: get msg =" + msg + "from JNI");
    }
}
void callAnothorJavaMethod(JNIEnv *env, jobject thiz){
    jclass clazz = env->FindClass("com/hao/jniapp/JniUtils2");
    if(clazz == NULL){
        printf("find class JniUtils error!");
        return;
    }
  //1. Getting the ID of a non-static method
    jmethodID  id = env->GetMethodID(clazz, "showMsg", "(Ljava/lang/String;)V");
    if(id == NULL){
        printf("find method showMsg error!");
    }
    jstring msg = env->NewStringUTF("Hello Java! I'm JNI message");
  //2. The emphasis is on the need for this pointer (`jobject thiz') that will represent the JniUtils 2 object.
    env->CallVoidMethod(thiz, id, msg);
}

Reference books

  1. JNI and NDK Development Tutorials for AS3.0
  2. Android JNI Foundation
  3. How to Print log to logcat in C/C++ Layer of JNI
  4. JNI API Document

Posted by d401tq on Tue, 14 May 2019 15:16:42 -0700