当前位置:网站首页>Analyze while doing experiments -ndk article -jni uses registernatives for explicit method registration
Analyze while doing experiments -ndk article -jni uses registernatives for explicit method registration
2022-06-11 05:13:00 【Kakar】
What is? JNI
JNI refer to Java Native Interface, namely JAVA The native interface , Its function is to define JAVA Code and the C/C++ The way the code interacts , Thus making Java To be able to call c/c++ Code , It can also make c/c++ To be able to call java Methods ( Callback ), Facilitate native development , Strictly speaking , It's actually using Java or Kotlin The interaction between bytecode written in programming language and native code , therefore Kotlin And it's also fully supported
JNI stay Android How to use the
To configure c/c++ Compile environment
Since this article does not mainly explain how to configure Native Development environment of , And the official website description is also more detailed , Therefore, the configuration process can refer to the instructions on the official website https://developer.android.google.cn/studio/projects/add-native-code, There is no other explanation here
Be careful , This article will use CMake For the following description
load
JAVA Layers need to pass through System.loadLibrary Method to load so library , By calling... In a static initialization method
JAVA Call mode
JAVA
public class MainNativeInterface {
static {
System.loadLibrary("native-lib");
}
}
Kotlin
class MainNativeInterfaceKotlin {
companion object {
init {
System.loadLibrary("native-lib")
}
}
}
Pay attention to the Kotlin In writing , We used companion object Inside to execute init, In this way, the final translation comes out Java The code will be static Static code block , If init Put it in the outer layer , be Java The code will become called in the constructor of the class . The official recommended practice is to call in the static initialization method , This allows you to load ahead of time
register Native Method
Generally speaking , We will reduce the Native Methods distinguish between static and dynamic registration methods 2 Kind of , But whether it is static registration or dynamic registration ,Native Methods are registered and bound at run time , The way of static registration JNI The layer will find the method name that conforms to the corresponding rules to bind when calling the method , Dynamic registration will be done in JNI When the dynamic library is loaded, all methods are bound , So it can be understood that static registration is an implicit passive registration method , Dynamic registration is the active registration mode of display , Let's take a look at the specific methods of these two methods , You can see that it shows 、 Implicit , Take the initiative 、 The difference between passivity
Static registration - Implicit passivity
The way is through JNI Complete the registration process for us , We just need to configure our method name according to certain method name rules , Let's take a look first Java Layer writing
JAVA
public class MainNativeInterface {
static {
System.loadLibrary("native-lib");
}
public native static String stringFromJNI();
}
Kotlin
class MainNativeInterface {
companion object {
init {
System.loadLibrary("native-lib")
}
@JvmStatic
external fun stringFromJNI(): String
}
}
We define a stringFromJNI Method , The method for native Methods , And here is a static Methods
notes :Kotlin The version corresponds to Java Version of , We used JvmStatic Annotation to indicate that it is a static Methods , And it belongs directly to MainNativeInterface This class of , There may be some students wondering , Why? companion
object no way , You can try to get rid of it , Then look at the translation Java The code of version is clear at a glance (Tools->Kotlin->showKotlinBytecode,
Decompile), original Kotlin Inside companion
object Will create a static Companion class , Then use the method as the internal method of the static class , This is undoubtedly for JNI It will have an impact when binding method queries , We're writing JNI Layer method name , Only the package name will be written + Class name + Method name , And the class name we only write MainNativeInterface, Therefore, the binding will fail
java.lang.NoSuchMethodError: no static or non-static method
And then we were in cpp There is a native-lib.cpp file , In it we define the corresponding native Layer method
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_nativeevaldemo_MainNativeInterface_stringFromJNI(JNIEnv *env, jclass thiz) {
return env->NewStringUTF("native auto search method bind");
}
such , We have completed the implicit passive registration of methods , It is also very convenient to use , Because we declared static Methods , So call the static... Directly native The method can , Of course, you can also use non static methods
JAVA
public class MainNativeInterface {
static {
System.loadLibrary("native-lib");
}
public native String stringFromJNI();
}
Kotlin
class MainNativeInterface {
companion object {
init {
System.loadLibrary("native-lib")
}
}
external fun stringFromJNI(): String
}
JNI The layer needs to modify the last parameter passed in by the method to be jobject
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_nativeevaldemo_MainNativeInterface_stringFromJNI(JNIEnv *env, jobject thiz) {
return env->NewStringUTF("native auto search method bind");
}
On the use , Non static methods can be a bit laborious , It needs to be done first new Come out of this class Then use it
Explicit active registration
This method requires us to take the initiative to JVM Registration binding Native Method
Java We don't need to change , Let's take a look JNI Layer writing , stay native-lib.cpp Next create a JNI_OnLoad Method
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
// Find your class. JNI_OnLoad is called from the correct class loader context for this to work.
jclass c = env->FindClass("com/example/nativeevaldemo/MainNativeInterface");
if (c == nullptr) return JNI_ERR;
// Register your class' native methods.
static const JNINativeMethod methods[] = {
{
"stringFromJNI", "()Ljava/lang/String;", (void*) stringFromJNI}
};
int rc = env->RegisterNatives(c, methods, sizeof(methods)/sizeof(JNINativeMethod));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}
static jstring JNICALL
stringFromJNI(JNIEnv *jenv, jclass ths){
return jenv->NewStringUTF("native hand method bind");
}
What we need to pay attention to here is
- FindClass Inside , We need to use "/" Instead of “.”, To designate our class Complete package path
- The binding methods must be in your Class You can find , Otherwise, it will report a mistake
- methods The method signature in the array should correspond to Java Layer method , Specific rules can be found in https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html
- Finally, return to the desired JNI Version of
In this way, we have completed the binding of methods
Dynamic binding is recommended for these two methods , Because this method is more flexible , And it's more efficient , The only drawback is that you need to write more code than the static way
Callback How to register
Next, let's take an example callback The way
stay Java Layer of MainNativeInterface Class to add a method , And increase callback Of interface
public interface JNICallback {
void result(String message);
}
public native void callAsyncMethod(JNICallback callback);
JNI layer onLoad Method to dynamically bind methods
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
javaVM = vm;
// Find your class. JNI_OnLoad is called from the correct class loader context for this to work.
jclass c = env->FindClass("com/example/nativeevaldemo/MainNativeInterface");
if (c == nullptr) return JNI_ERR;
// Register your class' native methods.
static const JNINativeMethod methods[] = {
{
"stringFromJNI", "()Ljava/lang/String;", (void*) stringFromJNI},
// Add the method signature , Note that the parameters here are defined by us interface
{
"callAsyncMethod", "(Lcom/example/nativeevaldemo/MainNativeInterface$JNICallback;)V", (void*) callAsyncMethod}
};
int rc = env->RegisterNatives(c, methods, sizeof(methods)/sizeof(JNINativeMethod));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}
// Add real binding c++ Method
static void
callAsyncMethod(JNIEnv *env, jclass thiz, jobject callback) {
jclass clazz = env->GetObjectClass(callback);
jmethodID jmid = env->GetMethodID(clazz, "result", "(Ljava/lang/String;)V");
env->CallVoidMethod(callback, jmid, env->NewStringUTF("this is callback result message"));
}
callAsyncMethod In the method , It can be done through the incoming callback Of object obtain class class ( That is, the implementation class of the interface passed in ), And then find class The inside of the class result Methodical Id, And then through callxxxMethod Method call
On use
// Use lambda It will be very simple.
MainNativeInterface.callAsyncMethod {
Log.d("NativeTestActivity", "result message == $it")
}
call callAsyncMethod Method output 
This way callback Just a simple description of the callback method , In real use, it may be necessary to add threads to achieve asynchronous processing or in other .c or .cpp File for callback processing , This is the time to callback Keep it up
Expand
Have any curious friends noticed , What happens if we write both the explicit active registration and the implicit passive registration ?
Here you may as well try , In fact, it is bound by active registration , Because we know that implicit passive registration will find the binding only when the method is called native Method , and , After binding once , Will not bind again , And display the active registration mode onLoad Will execute first , For the first native Method binding
RegisterNatives The method may not be in onLoad Call in method , We can do this to experiment , Let's get rid of onLoad Registration method of
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
return JNI_VERSION_1_6;
}
Register a method with implicit passive registration , And use it internally RegisterNatives Method to register and bind another one we show native Method
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_nativeevaldemo_MainNativeInterface_stringFromJNI(JNIEnv *env, jclass thiz) {
// Find your class. JNI_OnLoad is called from the correct class loader context for this to work.
jclass c = env->FindClass("com/example/nativeevaldemo/MainNativeInterface");
// Register your class' native methods.
static const JNINativeMethod methodss[] = {
{
"stringFromJNI", "()Ljava/lang/String;", (void*) stringFromJNI}
};
int rc = env->RegisterNatives(c, methodss, sizeof(methodss)/sizeof(JNINativeMethod));
return env->NewStringUTF("native auto search method bind");
}
static jstring
stringFromJNI(JNIEnv *jenv, jclass ths){
return jenv->NewStringUTF("native hand method bind");
}
We call the method 2 Time , You will find that the binding of this method will be switched 
Isn't it very interesting
边栏推荐
- Yolov5 training personal data set summary
- ROS compilation error: could not find a package configuration file provided by "XXX“
- C language test question 3 (grammar multiple choice question - including detailed explanation of knowledge points)
- Solving graph problems with union search set
- How to purchase 25g optical network card
- Linked list de duplication
- 董明珠称“格力手机做得不比苹果差”哪里来的底气?
- 自定义View之基础篇
- Poverty has nothing to do with suffering
- Let me tell you how to choose a 10 Gigabit network card
猜你喜欢

Lianrui: how to rationally see the independent R & D of domestic CPU and the development of domestic hardware

NVIDIA SMI has failed because it could't communicate with the NVIDIA driver

高斯白噪声(white Gaussian noise,WGN)

Cross modal retrieval | visual representation learning

Network security construction in 5g Era

Comparison of gigabit network card chips: who is better, a rising star or a Jianghu elder?

Huawei equipment is configured with bgp/mpls IP virtual private network

Top 100 video information of station B

Restoration of binary tree -- number restoration

Differences between the four MQ
随机推荐
22、生成括号
Parametric contractual learning: comparative learning in long tail problems
Cascade EF gan: local focus progressive facial expression editing
Inventory | ICLR 2022 migration learning, visual transformer article summary
Google drive download failed, network error
Solving graph problems with union search set
Deep extension technology: intelligent OCR recognition technology based on deep learning has great potential
Huawei equipment is configured to access the virtual private network through GRE tunnel
Take stock of the AI black technologies in the Beijing Winter Olympic Games, and Shenzhen Yancheng Technology
2021 iccv paper sharing - occlusion boundary detection
Lianrui electronics made an appointment with you with SIFA to see two network cards in the industry's leading industrial automation field first
The solution "no hardware is configured for this address and cannot be modified" appears during botu simulation
Huawei equipment is configured with cross domain virtual private network
jvm调优五:jvm调优工具和调优实战
go MPG
Network adapter purchase guide
jvm调优六:GC日志分析和常量池详解
Traversal of binary tree -- restoring binary tree by two different Traversals
Share | defend against physically realizable image classification attacks
Leetcode 161 Editing distance of 1 (2022.06.10)