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: representation
JNINativeMethod
Struct array,JNINativeMethod
The 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…