1: What is JNI?
Java NativeInterface (JNI) is an important feature provided by Java. It enables code written in languages such as C/C ++ to be integrated with Java code running on the Java Virtual Machine (JVM. Sometimes, Java cannot meet all your development needs. For example, you want to improve the efficiency of some key modules, or you must use a library written in C/C ++ or other Native languages. At this time, JNI can meet your needs to access these Native modules in Java code. The emergence of JNI allows developers to use both the cross-platform Java language, rich class libraries, convenient development, and the efficiency of Native language.
2: What is the relationship between JNI and JVM?
JNI is a part of JVM implementation. Therefore, both Native and Java code run in the Host Environment of JVM ). In addition, JNI is a two-way Interface: developers can not only access the Native module in Java code through JNI, but also embed a JVM in Native code, and access the Java module running in it through JNI. It can be seen that JNI acts as a bridge, linking JVM with the Native module, thus implementing mutual access between Java code and Native code. Using Java Virtual Machine on OPhone is a Dalvik Virtual Machine Specially optimized for embedded devices. Each time an application is started, the system creates a new process to run a Dalvik Virtual Machine. Therefore, each application is actually running in its own VM. Dalvik VM provides comprehensive support for JNI specifications, and supports enhancements from JDK 1.2 to JDK 1.6.
Before using JNI, developers must fully understand its advantages and disadvantages so that they can reasonably select technical solutions to achieve their goals. The advantages of JNI have been mentioned earlier. The shortcomings of JNI are also obvious: due to the use of Native modules, Java code will lose its original features such as cross-platform and type security. In addition, in JNI applications, Java code and Native code run in the same process space. For cross-process or even cross-host environment communications between Java and Native, you can consider using the socket, Web Service, and other IPC communication mechanisms.
3: JNI is mutually operational in JAVE and c ++;
A: Basic java and c ++ calls:
B: Concepts and usage of JNIhelper:
The compilation error occurs during compilation. If you want to debug it, try it. The problem is not serious;
C: use of independent JNIhelper:
4: JNI Compilation
Android. mk compilation Configuration:
Compile the basic commands:
5: JNI usage item reading
(1). andorid CPP calls java functions and accesses its members:
Principle => CPP Code: Find the function entry address in the java class, and then call the java code in the CPP Code
Step 1) Use the FindClass () function to locate the reference of the java class (such as android. OS. Binder) instance object:
Jclass clazz = env-> FindClass (kBinderPathName) = env-> FindClass ("android. OS. Binder ")
Step 2) use the GetFieldID () function to obtain the ID of the domain to be accessed (field: actually the name of a member variable in the java class:
GBinderOffsets. mObject = env-> GetFieldID (clazz, "mObject", "I") // mObject is a member variable in java class "Binder"
-> Note: the ID of the member mObject of the java object to be accessed is saved to the global variable gBinderOffsets. mObject. the prerequisites and advantages of this operation are as follows:
Premise: In android, only one java Virtual Machine is allowed in each java Process (in sun's original java architecture, one process can contain multiple java virtual machines)
Advantage: In addition to the first time, every time you access the java object, the member mObject will be very fast (no need to go to FindClass () and GetFieldID ())
Step 3) use the GetMethodID () function to obtain the ID of the Method to be accessed (Method: actually the name of a member function in the java class:
GBinderOffsets. mExecTransact = env-> GetMethodID (clazz, "execTransact", "(IIII) Z") // execTransact is a member function in java class "Binder"
Step 4) use a function similar to GetIntField () to obtain the value of the field (member) of the java object:
IBinder * target = (IBinder *) env-> GetIntField (obj, gBinderProxyOffsets. mObject)
// Obtain the value of the member mObject in the javaandroid. OS. Binder type object
Step 5) Call the member function of the java object using a function similar to CallBooleanMethod:
Jboolean res = env-> CallBooleanMethod (mObject, gBinderOffsets. mExecTransact, code, (int32_t) & data, (int32_t) reply, flags)
(2). android java calls the CPP function:
Principle => similar to the java class, some functions are implemented using CPP Code.
1) Use the JNINativeMethod structure to describe the correspondence between java code call functions and CPP functions:
Typedef struct {
Const char * name; // java code call CPP function entry
Const char * signature; // returned value of the CPP Function
Void * fnPtr; // CPP function name
} JNINativeMethod;
=> For example, java code uses IBinder. transact () to call the CPP function android_ OS _BinderProxy_transact ()
{"Transact", "(ILandroid/OS/Parcel; Landroid/OS/Parcel; I) Z", (void *) android_ OS _BinderProxy_transact },
2) register the CPP function to a class in java: Use the AndroidRuntime: registerNativeMethods () function to register.
=> After that, the java code can call the CPP function.
3) the java code calls the CPP function method:
IBinder. transact ()
To call a JAVA program, C/C ++ must first load the JAVA Virtual Machine and the JAVA Virtual Machine will explain and execute the class file. To initialize the Java Virtual Machine, JNI provides a series of interface functions to conveniently load the virtual machine to the memory.