An overview of the

How does the virtual machine know which method to call in SO when executing Java’s native method? This requires registration, which binds the Java method to the so method so that the corresponding method can be found. This article is just a note in case you forget it later

There are two types of registration: static registration and dynamic registration

Static registration

The project we automatically generated was statically registered, so let’s look at the code

extern "C" JNIEXPORT jstring JNICALL
Java_com_text_ndk1_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std: :string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
Copy the code

When the Java native method is called for the first time, the virtual machine will search for the corresponding native function. If it exists, an association will be established, and this part of the operation will be completed by the virtual machine when it is called again in the future

Corresponding rules

Java+ package name + class name + method name

It is separated by underscores, and package names are also separated by underscores

There are some disadvantages to doing this:

  • The name is too long
  • The first call requires a search, affecting efficiency

Dynamic registration

  • We need to establish contact manually, increasing the amount of code but improving efficiency
  • Allow yourself to define function names

Loading the Dynamic library

The Java layer loads a dynamic library through the system.loadLibrary () method, at which point the virtual machine calls the JNI_OnLoad() function in the JNI library

jint JNI_OnLoad(JavaVM* vm, void* reserved);
Copy the code

The return value represents the version of JNI required by the dynamic library. If the virtual machine does not recognize this version, the dynamic library cannot be loaded

The current return values are JNI_VERSION_1_1, JNI_VERSION_1_2, JNI_VERSION_1_4, and JNI_VERSION_1_6.

If the dynamic library does not provide JNI_OnLoad(), the JNI_VERSION_1_1 version is used by default, but this version is old and many new functions do not, so it is best to return to the version

The registration function

The JNI_OnLoad() function is often used to do some initialization, and this is where dynamic registration takes place

Dynamic registration is accomplished by the RegisterNatives() function of _JNIEnv

The function prototype is

jint RegisterNatives(JNIEnv *env, jclass clazz, 
        const JNINativeMethod *methods, jint nMethods);
Copy the code
  • First argument: JNIEnv * pointer
  • The second argument: represents a Java class
  • The third parameter: representationJNINativeMethodStruct array,JNINativeMethodThe mapping between Java layer functions and Native layer functions is defined
  • The fourth argument: represents the size of the third argument, the methods array

The return value 0 represents success and a negative value represents failure

JNINativeMethod structure

The most important thing about the RegisterNatives function is the JNINativeMethod construct. Let’s take a look at this construct

typedef struct {
    const char* name;
    const char* signature;
    void*       fnPtr;
} JNINativeMethod;
Copy the code
  • Name: represents the name of a Java native method
  • Signature: indicates the method signature
  • FnPtr: is a function pointer to a jNI layer function, that is, the connection between the Java layer and the Native layer

practice

Now we have a Java class with two native methods. Let’s complete the dynamic registration of these two methods

public class TextJni {

    static {
        System.loadLibrary("textjni_lib");
    }

    native int text(String message);

    static native int static_text(String message);
}
Copy the code

First, write the corresponding method of C manually

jint native_text(JNIEnv *env, jobject jobject1, jstring msg) 

jint native_staic_text(JNIEnv *env, jobject jclass1, jstring meg) 
Copy the code

Native_text corresponds to the Text method of the Java layer, and native_staic_text corresponds to the static_text method of the Java layer

So how do you write it?

  • Native method name, you can call it whatever you want
  • The return value corresponds to the Java equivalent of int, where jni is jint
  • The first argument that is fixed is the JNIEnv pointer
  • The second parameter I currently understand as fixed jobject
  • The following parameters are converted from Java parameters

Then you need to populate JNINativeMethod

static const JNINativeMethod nativeMethod[] = {
        {"text"."(Ljava/lang/String;) I", (void *) native_text},
        {"static_text"."(Ljava/lang/String;) I", (void *) native_staic_text}
};
Copy the code

We’ve already talked about that

And then start registering

static int registNativeMethod(JNIEnv *env) {
    int result = - 1;
    // Find the class where the native method is located
    jclass class_text = env->FindClass("com.text.ndk1.TextJni");
    if (env->RegisterNatives(class_text, nativeMethod,
                             sizeof(nativeMethod) / sizeof(nativeMethod[0])) == JNI_OK) {
        result = 0;
    }
    return result;
}
Copy the code

Dynamic registration is successful

Take a look at the complete code

Java code

public class TextJni {

    static {
        System.loadLibrary("textjni_lib");
    }

    native int text(String message);

    static native int static_text(String message);
}
Copy the code

C code

#include <jni.h>
#include <string>
#include <android/log.h>

jint native_text(JNIEnv *env, jobject jobject1, jstring msg) {
    const char *p_msg = env->GetStringUTFChars(msg, JNI_FALSE);
    __android_log_print(ANDROID_LOG_INFO, "mmm"."method = %s, msg = %s", __FUNCTION__, p_msg);

    return 0;
}

jint native_staic_text(JNIEnv *env, jobject jclass1, jstring meg) {
    const char *p_msg = env->GetStringUTFChars(meg, JNI_FALSE);
    __android_log_print(ANDROID_LOG_INFO, "mmm"."method = %s, msg = %s", __FUNCTION__, p_msg);

    return 0;
}


static const JNINativeMethod nativeMethod[] = {
        {"text"."(Ljava/lang/String;) I", (void *) native_text},
        {"static_text"."(Ljava/lang/String;) I", (void *) native_staic_text}
};

static int registNativeMethod(JNIEnv *env) {
    int result = - 1;

    jclass class_text = env->FindClass("com.text.ndk1.TextJni");
    if (env->RegisterNatives(class_text, nativeMethod,
                             sizeof(nativeMethod) / sizeof(nativeMethod[0])) == JNI_OK) {
        result = 0;
    }
    return result;
}

jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env = NULL;
    int result = - 1;

    if (vm->GetEnv((void **) &env, JNI_VERSION_1_1) == JNI_OK) {
        if (registNativeMethod(env) == JNI_OK) {
            result = JNI_VERSION_1_6;
        }
        returnresult; }}Copy the code

call

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextJni.static_text("I'm a static method, ha ha");
        new TextJni().text("I'm the normal way, ha ha."); }}Copy the code

Look at the printed message

MMM: method = native_staic_text, MSG = I'm a static method, haha MMM: method = native_staic_text, MSG = I'm a normal method, hahaCopy the code

reference

Juejin. Cn/post / 684490…

Blog.csdn.net/afei__/arti…

www.jianshu.com/p/b71aeb4ed…