The Java Native Interface (JNI) standard is part of the Java platform. It allows Java code to interact with code written in other languages. JNI is a local programming interface that enables the Java code running inside the Java Virtual Machine (VM) to work with other programming languages (such as C, C ++, and assembly languages) write Applications and libraries for interaction.
1. Starting from how to load the. So file
Because the classes at the Android Application layer are written in Java, after these Java classes are compiled into Dex-type bytecode, they must be executed by the Dalvik Virtual Machine (Vm: Virtual Machine. VM plays an important role in the Android platform.
In addition, during Java class execution, if the Java class needs to communicate with the c component, the VM will load the C component, then, let Java functions smoothly call the C component functions. In this case, the VM acts as a bridge, allowing Java and C components to communicate with each other through the standard JNI interface.
Java classes at the application layer are executed on virtual machines (Vm: vitual machine), while C is not executed on the VM. How can Java programs require VM to load) what about the specified C component? You can use the following commands:
System. loadlibrary (*. So file name );
For example, the mediaplayer. Java class provided in the android framework contains commands:
This requires VM to load the/system/lib/libmedia_jni.so file of Android. After loading *. So, the Java class and *. So files are merged and executed together.
2. How to Write the entry function *. So
---- Functions of jni_onload () and jni_onunload ()
When the android VM (Virtual Machine) executes the system. loadlibrary () function, it first executes the jni_onload () function in the C component. It has two purposes:
(1) Tell VM that the C component uses the JNI version. If your *. So file does not provide the jni_onload () function, Vm will use the oldest JNI 1.1 version by default *. So file. Because the new version of JNI has made a lot of extensions, if you need to use the new features of JNI, such as Java. NiO. bytebuffer of JNI 1.4, you must use the jni_onload () function to inform the VM.
(2) because the VM runs to system. when the loadlibrary () function is used, jni_onload () is called immediately. Therefore, the C component developer can use jni_onload () to set the initial value (initialization) in the C component ).
For example, in the/system/lib/libmedia_jni.so file of Android, The jni_onload () function is provided, and its code segment is:
This function returns the jni_version_1_4 value to the VM, so the VM knows the JNI version it uses. In addition, it also performs some initial actions (can call any local function), such as commands:
Register the native functions provided by this component to the VM to accelerate subsequent calls to the local functions.
The jni_onunload () function corresponds to jni_onload. When the C component is loaded, jni_onload () is immediately called for initial actions in the component. When the VM releases the C component, jni_onunload () is called () function. When the VM calls the jni_onload () or jni_unload () function, it will pass the VM pointer (pointer) to them. The parameters are as follows:
Jint jni_onload (JavaVM * Vm, void * Reserved ){}
Jint jni_onunload (JavaVM * Vm, void * Reserved ){}
In the jni_onload () function, the jnienv indicator value is obtained through VM indicators and stored in the Env indicator variable, as instructed below:
Because the VM is usually the execution environment of multi-threading. When jni_onload () is called by each thread, the passed jnienv metric values are different. To work with this multi-thread environment, C component developers can avoid conflicts in execution threads by using different jnienv metric values when writing local functions, in order to ensure that the written local functions can be safely executed in the android multi-thread VM. For this reason, when calling a function of the C component, the jnienv indicator value is passed to it, as shown below:
When jni_onload () calls the register_android_media_mediaplayer (ENV) function, the Env indicator value is passed. In this way, the register_android_media_mediaplayer () function can distinguish different execution threads with this indicator value to resolve data conflicts.
For example, in the register_android_media_mediaplayer () function, you can write the following commands:
If (* env)-> monitorenter (ENV, OBJ )! = Jni_ OK ){
}
Check whether other threads have entered the object. If no thread exists, the thread is executed in the object. You can also write the following commands:
If (* env)-> monitorexit (ENV, OBJ )! = Jni_ OK ){
}
Check whether the thread is being executed in this object. If yes, the thread will leave immediately.
3. Purpose of the registernativemethods () function
Java classes at the application level call local functions through VMS. Generally, the VM is used to find local functions in *. So. If you need to call multiple times in a row, it will take a lot of time to search for them each time. In this case, the component developer can register the local function with the VM. For example, the code segment in the/system/lib/libmedia_jni.so file of Android is as follows:
When the VM loads the libmedia_jni.so file, it calls the jni_onload () function. Then, jni_onload () calls the register_android_media_mediaplayer () function. Now, call the androidruntime: registernativemethods () function to register the local functions contained in the gmethods [] table with the VM (androidruntime. In short, the registernativemethods () function has two purposes:
(1) Find functions more efficiently.
(2) The switch can be performed during execution. Gmethods [] is a <name, function pointer> table. During program execution, you can call registernativemethods () function multiple times to replace the pointer of the local function, to achieve the purpose of using local functions elastically.
4. andoird uses a different traditional Java JNI method to define its native function. An important difference is that andorid uses a ing table array of Java and C functions, and describes the parameters and return values of the functions. The type of this array is jninativemethod, which is defined as follows:
The second parameter is hard to understand, for example
"() V"
"(Ii) V"
"(Ljava/lang/string;) V"
In fact, these characters correspond to the function parameter types one by one.
The character in "()" represents a parameter, and the subsequent character represents the return value. For example, "() V" indicates void func ();
"(Ii) V" indicates void func (INT, INT );
The relationship between each character is as follows:
Character Java type C type
V void
Z jboolean Boolean
I jint int
J jlong long
D jdouble double
F jfloat float
B jbyte byte
C jchar char
S jshort short
The array starts with "[" and is represented by two characters.
[I jintarray int []
[F jfloatarray float []
[B jbytearray byte []
[C jchararray char []
[S jshortarray short []
[D jdoublearray double []
[J jlongarray long []
[Z jbooleanarray Boolean []
The above are all basic types. If the Java function parameter is a class, it starts with "L" and ends with ";", with the package and class names separated by "/" in the middle. The parameter of the corresponding C function name is jobject. An exception is the string class, and its corresponding class is jstring.
Ljava/lang/string; string jstring
Ljava/NET/socket; socket jobject
If a Java function is located in an embedded class, $ is used as the delimiter between class names.
For example, "(ljava/lang/string; landroid/OS/fileutils $ filestatus;) z"
Android JNI programming practices
1. directly use the Java JNI interface (Windows/UBUNTU)
1. Create an Android Application in cmdsh. Two classes: one class inherits from the activity and is used for UI display. Another method that contains native. Compile and generate all classes.
The preceding steps are completed in windows.
2. Use the javah command to generate C/C ++. h file. Note that the class should contain the package name and the path folder should contain classes in all packages. Otherwise, an error will be reported that the class cannot be found. The classpath parameter specifies the first-level folder before the package name. The folder hierarchy must conform to the Java class organization hierarchy.
Javah-classpath ../jnitest/bin com. Hello. jnitest. nadd
Com_hello_jnitest_nadd. h file:
3. Edit the. c file to implement the native method.
Com_hello_jnitest_nadd.c file:
4. Compile the. c file to survive the dynamic library.
Arm-None-Linux-gnueabi-gcc-I/home/A/work/Android/jdk1.6.0 _ 17/include-I/home/A/work/Android/jdk1.6.0 _ 17/ include/Linux-FPIC-C com_hello_jnitest_nadd.c
Arm-None-Linux-gnueabi-LD-T/home/A/codesourcery/sourcery_g ++ _ lite/ARM-None-Linux-gnueabi/lib/ldscripts/armelf_linux_eabi.xsc-share- O libnadd. so com_hello_jnitest_nadd.o
Obtain the libnadd. So file.
The preceding steps are completed in Ubuntu.
5. Push the corresponding dynamic library file to system/lib of AVD: ADB push libnadd. So/system/lib. If the read-only file system error is prompted, run the ADB remount command.
ADB push libnadd. So/system/lib
6. Run the original application in cmdsh.
The preceding steps are completed in windows.
You can also use the second method to compile the so file generated in step 1 into the APK package. You only need to create the libs/armeabi folder in the project folder (other folder names are invalid, and only the libs folder is created is invalid), and then merge the so file into and compile the project.
Ii. Use ndk to generate a local method (Ubuntu and Windows)
1. Install ndk: unzip, then enter the directory after ndk unzipping, run build/host-setup.sh (make 3.81 and awk required ). If there are errors, modify the host-setup.sh file: Will #! /Bin/sh #! /Bin/Bash: Run it again.
2. Create your own project folder under the apps folder, and then create the application. mk and project folders under the folder.
Application. mk file:
App_project_path: = $ (call my-DIR)/Project
App_modules: = myjni
3. Create a JNI folder under the project folder, and then create Android. mk and myjni. C. You do not need to use javah to generate the corresponding. h file, but the function name must contain the complete package and class name.
4. Edit the content of the file.
Android. mk file:
Myjni file organization:
A @ Ubuntu :~ /Work/Android/ndk-1.6_r1/apps $ tree myjni
Myjni
| -- Application. mk
'-- Project
| -- JNI
| -- Android. mk
| '-- Myjni. c
'-- Libs
'-- Armeabi
'-- Libmyjni. So
4 directories, 4 files
5. Compile: Make APP = myjni.
The above content is completed in Ubuntu. The following content is completed in windows. Of course, this can also be done in Ubuntu.
6. Create an Android Application in cmdsh. Copy the automatically generated libs folder in myjni to the current project folder and compile and run the folder.
Ndktest. Java file:
The so file generated in the second stage can also be pushed to AVD using the method in the second stage.
This article from the csdn blog, reproduced please indicate the source: http://blog.csdn.net/li_guotao/archive/2011/05/03/6386694.aspx