"Go" Android JNI programming-jni Basics

Source: Internet
Author: User

Original URL: http://www.jianshu.com/p/aba734d5b5cd

Recently saw a lot of open-source projects about HotPatching--depoxed (Ali), Anfix (Ali), dynamicapk (Ctrip), they all use JNI programming, and JNI programming also runs through the Android system, Learning JNI programming is useful for us to learn about Android source code, Android security, and Android security hardening. But for most of us writing Android apps, most of the time we're using Java programming, with very little C + + programming, and less about JNI programming, so let's take a simple look at the basics of JNI programming.

What is JNI and how to use it

Jni--java Native Interface, which is a feature of the Java platform (not specific to the Android system). In fact, the main definition of a number of JNI functions, so that developers can call these functions to implement Java code C + + code, the code can also call Java code, C + +, so you can play the characteristics of each language. So how to use JNI, in general, we will be the first to compile the C + + code to the corresponding platform of the dynamic library (Windows is generally DLL files, Linux is generally so files, etc.), here we are for the Android platform, so only discuss so library. Because JNI programming supports C and C + + programming, here our chestnuts are using C + +, for the C version may be somewhat different, but the main content is consistent, we can comprehend by analogy.

My good Friends program is also not ape expression can not understand, so afraid of my friends have the same confusion, here to add the main content of this article:

How the native method of 1.Java is linked to a function in C + +

2.JNI defines the data type that corresponds to Java for JNI programming.

3. Descriptors-Used to describe class names or data types, we need to use strings to describe the class name, variable type, and method of the object that needs to be fetched in order to get the Java layer's objects, variables, and Java-like methods in the C + + layer.
The article mainly from the above three to do a brief introduction, and so on the next article introduced the NDK practice, come back to see believe there will be a better understanding.

From a chestnut.

This is also directly from the code, so that more image and intuitive, but also easy to understand. The Java code used today is as follows:

public class AndroidJni {    static{ System.loadLibrary("main"); } public native void dynamicLog(); public native void staticLog();}

Here we define two methods declared as native, and declare a static zone, in which the static zone class is loaded with a library named libmain.so, here we say is the libmain.so library, but the load when it only wrote "main", in fact, as long as we know that this is agreed on it.

The C + + code is as follows:

#Include<jni.h>#Define Log_tag"Main.cpp"#Include"Mylog.h"StaticvoidNativedynamiclog(jnienv *evn, Jobject obj) {LOGE ("Hell Main");}Jniexportvoid JnicallJava_com_github_songnick_jni_androidjni_staticlog(jnienv *env, Jobject obj) {LOGE ("Static register Log"); Jninativemethod nativemethod[] = {{ "Dynamiclog",  "() V", (void*) Nativedynamiclog},}; jniexport jint jnicall jni_onload ( JAVAVM *JVM, void *reserved) {jnienv *env; if (jvm->getenv ((void**) &env, JNI_VERSION_1_4)! = JNI _OK) {return-1;} LOGE ( "jni_onload comming"); Jclass clz = Env->findclass ( "com /github/songnick/jni/androidjni "); Env->registernatives (CLZ, Nativemethod, sizeof (Nativemethod)/ sizeof (Nativemethod[0])); return jni_version_1_4;}           

Here's a reference to two header files, jni.h and mylog.h, where jni.h defines a lot of the JNI functions and structs we use, and mylog.h is my own definition of the function that prints the Android log (the same functionality as the Java Log Class).
For the time being, it is not discussed how to compile some specifications for so libraries and so libraries, which are described in the next article. This assumes that the above C + + program is compiled into a file called libmain.so. Use the System.loadlibarary ("main") method at the Java layer to load the so library so that Dynamiclog (), Staticlog (), and the corresponding java_com_github_songnick_jni_ Androidjni_staticlog (), Nativedynamiclog () Two native methods link up, of course, this part of the work is done by the Java Virtual machine, then the specific how to complete, the next will be based on the above code for analysis.

Static Registration native method

In the code above see the Jniexport and Jnicall keywords, these two keywords are two macro definitions, his main role is to explain that the function is a JNI function, when the Java virtual machine is loaded, the corresponding native method is linked, Staticlog () is declared in the Androidjni.java class as the native method, and his corresponding JNI function is Java_com_github_songnick_jni_androidjni_staticlog (), So how to link, when the Java Virtual machine load so library, if found to contain the above two macro definition of the function will be linked to the corresponding Java layer of the native method, then how to know which class in Java which native method? We carefully observed that the composition of the JNI function name is: Java_pkgname_classname_nativemethodname, prefixed with Java, and with "_" underscore the package name, class name and native method name is the corresponding JNI function. In general, we can manually to follow this rule to write, but if the native method is particularly many, then there is a certain amount of work, and in the process of writing accidentally may write wrong, in fact, Java provides us with Javah tools to help generate the corresponding header file. In the generated header file is the corresponding JNI function generated in accordance with the above-mentioned rules, we are in the development of a direct copy of the past can be. Here is the code above for example, after compiling in Androidstudio, go to the project directory App/build/intermediates/classes/debug, run the following command:

javah -d jni com.github.songnick.jni.AndroidJni

Here-d Specifies the directory where the. h file is generated (if it is not created automatically), Com.github.songnick.jni.AndroidJni represents the class file under the specified directory. Here is a brief introduction to the generated JNI function contains two fixed parameter variables, respectively, jnienv and Jobject, where JNIEnv is described later, Jobject is the currently linked native method of the class object (similar to this in Java). Both of these variables are generated by the Java Virtual machine and passed in at the time of invocation.

Dynamic registration

Above we introduce the process of static registration native method, that is, the Java Layer declaration of the native method and the JNI function is one by one corresponding, then there is no way to let Java layer native method and arbitrary jni function link up, of course, it is possible, this must use the method of dynamic registration. The next step is to see how to implement dynamic registration.

Jni_onload function

When we use the System.loadlibarary () method to load the so library, the Java Virtual machine will find this function and call the function, so you can do some initialization action in the function, in fact, this function is equivalent to the activity of the OnCreate () Method. The function is preceded by three keywords, jniexport, jnicall, and Jint, where Jniexport and Jnicall are two macro definitions that specify that the function is a JNI function. Jint is a data type that is defined by JNI, because the data types of Java and C + + or objects cannot be referenced or used directly from each other, the JNI layer defines its own data type, which is used to interface the Java layer and the JNI layer, as described in the following data types. The jint here corresponds to the Java int data type, which returns an int representing the version of the JNI that is currently in use, in fact, similar to the API version of the Android system, some of the different JNI functions defined in the different JNI versions. The function will have two parameters, where *JVM is a Java Virtual machine instance, and the JAVAVM struct defines the following function:

DestroyJavaVM   AttachCurrentThread   DetachCurrentThread   GetEnv

Here we use the getenv function to get the JNIENV variable, which has the following code in the Jni_onload function:

JNIEnv *env;if (jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {    return -1;}

Here called the getenv function to get the jnienv struct pointer, in fact, the jnienv struct is pointing to a function table, the function table points to the corresponding JNI function, we call these JNI functions to implement JNI programming, we will also introduce it later.

Get Java objects, complete dynamic registration

The above describes how to get the jnienv struct pointer, we can call the Registernatives function in jnienv to complete the dynamic registration native method After we get the struct pointer. The method is as follows:

jint RegisterNatives(jclass clazz, const JNINativeMethod* methods, jint nMethods)

The first argument is that the Java layer corresponds to the object that contains the native method (this is the Androidjni object), and the class object is obtained by calling the jnienv corresponding function (the parameter of the Findclass function is to obtain the classes descriptor of the class object):

jclass clz = env->FindClass("com/github/songnick/jni/AndroidJni");

The second parameter is the Jninativemethod struct pointer, where the Jninativemethod struct is a description of the Java layer native method, which is defined as follows:

typedef struct {    const char* name;//Java层native方法的名字 const char* signature;//Java层native方法的描述符 void* fnPtr;//对应JNI函数的指针} JNINativeMethod;

The third parameter is the number of registered native methods. It is common to dynamically register multiple native methods, first defining a Jninativemethod array, and then passing the array pointer as a parameter to the Registernative function, so the following Jninativemethod array is defined:

JNINativeMethod nativeMethod[] = {{"dynamicLog", "()V", (void*)nativeDynamicLog}};

Finally, call the Registernative function to complete the dynamic registration:

env->RegisterNatives(clz, nativeMethod, sizeof(nativeMethod)/sizeof(nativeMethod[0]));
JNIEnv Structural Body

The above mentioned JNIENV this structure, it is very old, point to a function table, the function table points to a series of JNI functions, we call these JNI functions can be implemented with the Java layer of interaction, here is a simple look at a few defined functions:

const char* name, const char* sig)jboolean GetBooleanField(jobject obj, jfieldID fieldID)jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)CallVoidMethod(jobject obj, jmethodID methodID, ...)CallBooleanMethod(jobject obj, jmethodID methodID, ...)..........

Here is a simple look at the above four functions, the Getfieldid () function is to get a variable in a Java object, the Id,getbooleanfield () function is to obtain a variable with the data type Boolean based on the ID of the variable. The Getmethodid () function is a method that gets the Id,callvoidmethod () of the corresponding method in the Java object, based on Methodid, and the return value of the method is of type void. With these functions we can implement code that calls the Java layer. More functions Let's take a look at the API documentation!

JNI data type

Above we mentioned that JNI defines some of its own data types. These data types are connected to the Java layer and the C/s + + layer, if there is an object passed down, then for C + +, there is no way to recognize this object, the same if the C + + pointer to the Java layer It is also not able to identify, then need JNI to match, So you need to define some of your own data types.

1. Original data type

Java Type Native Typ Description
Boolean Jboolean Unsigned 8 bits
Byte Jbyte Signed 8 bits
Char Jchar Unsigned bits
Short Jshort Signed Bits
Int Jint Signed Bits
Long Jlong Signed Bits
Float Jfloat Bits
Double Jdouble + Bits
void void N/A

2. Reference types

Before we get the use of the Androidjni object by defining the Jclass reference, and then calling the Findclass function to get the object, JNI also defines some reference types so that the JNI layer is called, and the specific reference type is as follows:

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            

3. IDs of methods and variables
When we need to call a method in Java we first want to get its ID, according to the ID call JNI function to get the method, the variable is the same process, the structure of these IDs are defined as follows:

struct _jfieldID;              /* opaque structure */ typedef struct _jfieldID *jfieldID;   /* field IDs */ struct _jmethodID; /* opaque structure */ typedef struct _jmethodID *jmethodID; /* method IDs */
Descriptor

1. Class Descriptor
In order to get the Androidjni object of Java, which is obtained by calling the Findclass () function, the function parameter has only one string parameter, we find the string as follows:

com/github/songnick/jni/AndroidJni

In fact, this is the JNI definition of the class descriptor, and its rule is to "Com.github.songnick.jni.AndroidJni" in the "." Replace with "/".

2. Method descriptors
Before we dynamically register the native method, the struct Jninativemethod contains the method descriptor, which is to determine the parameters and the return value of the native method, the Dynamiclog () method We define here has no parameters, the return value is empty so the corresponding descriptor is: "() V ", the bracket class is a parameter, and V indicates that the return value is null. Let's look at a few chestnuts below:

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);

The chestnut above we see that the return type and method parameters of the method have reference types and basic data types such as Boolean, int, and the descriptors for these types are described in the next section. Here the descriptor of the array is expressed as "[" and the corresponding type descriptor. For two-dimensional arrays and three-dimensional arrays, they are expressed as "[[" and "[["]:

Descriptor Java langauage Type
"[[I] Int[][]
"[[[D] Double[][][]

3. Data type descriptor
We said the descriptor of the method before, so what is the descriptor for the data type such as Boolean, int, and the descriptors for the basic data type are defined as follows:

Field Desciptor Java Language Type
Z Boolean
B Byte
C Char
S Short
I Int
J Long
F Floa
D Double

For reference type descriptors, start with "L"; The end, shown as follows:

Field Desciptor Java Language Type
"Ljava/lang/string;" String
"[Ljava/lang/object;] Object[]
Summarize

The above section we have a simple analysis of the JNI programming of the chestnut, here is just a simple introduction, just a part of the JNI programming, I believe that any technical or technical point can not be mastered by an article, more or practice, only in the process of practice to find problems-solve problems, In order to gain a better understanding of knowledge and to achieve mastery. So hopefully through this article you can have a preliminary understanding of JNI programming, and will not feel that JNI programming is difficult. You can take a look at the JNI API documentation, I also have a JNI tutorial here, everyone download it to see it, this will have more knowledge of JNI. There's a bit of a difference here about the JNI programming of Android, and you can take a look at some of the guidance and demo programs that Google's official documentation has for JNI programming. The next article will cover Android NDK-related content and apply JNI programming to Android development.

Hope that on the way of Android learning, we grow together!

"Go" Android JNI programming-jni Basics

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.