When analyzing the old version of an app today, I accidentally found JNI_ Onload doesn’t exist, but so is really a Java layer load, and each native function also has a declaration and call, thinking that it will encounter some black technology. It is found that this function does not exist in the earliest NDK development versions
JNI in current versions of NDK_ Onload functions are called automatically when loading. If not, dvmresolvenativemethod is called. The following is a detailed process explanation
Excerpt from http://yanbober.github.io/2015/02/25/android_ studio_ jni_ 3/
There are two ways to load JNI lib on Android OS:
there are two ways to load JNI lib on Android OS
through JNI_ OnLoad。
If JNI is not defined in the implementation of JNI Lib_ Onload, DVM calls dvmresolvenativemethod for dynamic parsing
PS: the first part above is that DVM calls dvmresolvenativemethod for dynamic parsing, so log print no JNI_ OnLoad found。
In depth analysis found on the Internet (this analysis module code is quoted from the Internet)
JNI_ Onload mechanism analysis
The calling process of system. Loadlibrary is as follows:
System.loadLibrary-> Runtime.loadLibrary->( Java)nativeLoad->( C: java_ lang_ Runtime.cpp)Dalvik_ java_ lang_ Runtime_ nativeLoad-> dvmLoadNativeCode->( dalvik/vm/Native.cpp)
Then it goes as follows:
dlopen(pathName, RTLD_ Lazy) (add. So MMAP to process space, and fill func and other related information into soinfo)
dlsym(handle, “JNI_ OnLoad”)
JNI_ OnLoad-> RegisterNatives-> dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName, const char* signature, void* fnPtr)-> dvmUseJNIBridge(method, fnPtr)->( method-> nativeFunc = func)
The starting address of JNI function in process space is saved in classobject – > In directmethods
structClassObject:Object{/*static,private,and<init>methods*/intdirectMethodCount;Method*directMethods;/*virtualmethodsdefinedinthisclass;invokedthroughvtable*/intvirtualMethodCount;Method*virtualMethods;}
This classobject is obtained through gdvm.jniglobalreftable or gdvm.jniweakglobalreflock
dvmresolvenative method delay resolution mechanism
If there is no JNI in JNI Lib_ Onload, that is, when executing system. Loadlibrary, the address of the function implemented by JNI Lib in the process cannot be increased to classobject – > directMethods。 These javah style functions will not be parsed until they need to be called. Such a function dvmresolvenativemethod (Dalvik/VM/native. CPP) is used for parsing, and its execution process is as follows:
void dvmResolveNativeMethod(const u4* args, JValue* pResult, const Method* method, Thread* self)->( Resolve a native method and invoke it.)
Then it goes as follows:
void * func = lookupshardlibmethod (method) (find this function implementation in all opened. So according to signature) dvmhashforeach (gdvm. Nativelibs, findmethodinlib, (void *) method) – > findMethodInLib(void* vlib, void* vmethod)-> dlsym(pLib-> handle, mangleCM)
dvmUseJNIBridge((Method*) method, func)
(*method-> nativeFunc)(args, pResult, method, self);( Call execution
What should be done after the end of the load foundation
In fact, the answer is to recommend the method of loading JNI lib on Android OS through JNI_ OnLoad。 Because you can do many custom things through it, such as realizing your own local registration. Because JNI has been seen in the above analysis_ OnLoad-> RegisterNatives->… These are two key methods. Let’s talk about the details now
Let’s start with JNI_ Onload function
JNI_ The onload() function is mainly used for two purposes:
informs the VM of the JNI version used by this C component. If your. So file does not provide JNI_ Onload() function, VM will default that. So uses the oldest JNI 1.1 version. The new version of JNI has made many extensions. If you need to use the new functions of JNI, such as Java. NiO. ByteBuffer of JNI 1.4, you must use JNI_ The onload() function tells the VM
because when VM executes the system. Loadlibrary() function, it will immediately call JNI first_ Onload (), so the developers of C components can be created by JNI_ Onload() to initialize the initial value in the C component
Since there is JNI_ Onload (), then there is a corresponding function, that is JNI_ Onunload (), when VM releases JNI component, it will call it. Therefore, in this method, resource release is the most appropriate action to clean up
Let’s look at the registernatives function
In the first part above, we see the IO generated by the javah command_ github_ yanbober_ ndkapplication_ The name of function in ndkjniutils. H is so long that it hurts to look at it. You must have thought about how to take such a long time, and sometimes when the class name changes due to project requirements, the function name must be changed one by one, which is even more painful. When I first came into contact, I was inexperienced at that time, so I met this egg pain problem. Tears run
In this case, there is a solution, which is the great move of register natives. Next, let’s take a look at this big move:
The process of finding C local methods in app’s Java programs generally relies on VM to find the local functions in *. So. If it needs to be continuously transferred many times, it will take a lot of time to find them every time. Therefore, in order to solve this problem, we can register the local function with the VM, and then let the VM call the registernativemethods() function
There are two main functions for VM to call registernativemethods() function
more efficient to find C language functions
it can be swapped during execution, because the methods [] array of the self defined JNI native method type is a name function pointer cross reference table. During program execution, you can call the registernativemethods() function many times to replace the local function pointer, so as to achieve the effect of flexible swapping of local functions
The JNI native method structure mentioned above is the key structure of the mapping relationship between C/C + + methods and Java methods. The structure is defined in JNI. H, as follows:
typedefstruct{constchar*name;//java name constchar*signature;//java name void*fnPtr;//c/c++}JNINativeMethod;
The methods [] array of the so-called custom jninarivemethod type is naturally similar to the following:
staticJNINativeMethodmethods[]={{"generateKey","(Ljava/lang/String;)Ljava/lang/String;",(void*)generateKey},};
The above is the so-called dynamic registration of JNI