Android mostly uses Java to develop, there is a concept in Java called JNI. Of course, when it comes to JNI, native code must be indispensable. The so library is in Android. To analyze the use of JNI in Android Dalvik, the following is my study and annotation of the registration process analysis article for the Dalvik virtual machine Jni method. Before that, let's say a few concepts:
JAVAVM: Virtual machine instance can also be described by a member variable vmlist of a dvmglobals struct described by the global variable GDVM;
JNIENV: A Java environment that describes the current thread, which can be used to invoke the JNI method registered in the zygote (see zygote boot process) to Dalvik
Jobject: To describe the Java object that is currently executing the JNI method
From Lao Luo's blog (the following is the map to expand)
We are in the Java function in the load so library:
System.loadlibrary ("Nanosleep");
So library writing:
StaticJint Shy_luo_jni_classwithjni_nanosleep (jnienv*env, Jobject clazz, jlong seconds, Jlong nanoseconds) { structTimespec req; Req.tv_sec=seconds; Req.tv_nsec=nanoseconds; returnNanosleep (&req, NULL);}Static ConstJninativemethod method_table[] = { {"Nanosleep","(JJ) I", (void*) Shy_luo_jni_classwithjni_nanosleep},};extern "C"Jint jni_onload (javavm* vm,void*reserved) {jnienv* env =NULL; Jint result= -1; if(Vm->getenv (void* *) &env, jni_version_1_4)! =JNI_OK) { returnresult; } jniregisternativemethods (env,"Shy/luo/jni/classwithjni", Method_table, Nelem (method_table)); returnjni_version_1_4;}
When the Java layer is in the LoadLibrary so library, the system actually does a few things (step 4):
1 call Dlopen in process to load so library;
2 Call Dlsym to obtain the address of the function named "Jni_onload" in the so library and save it in the function pointer func: func= dlsym (handle, "Jni_onload");
3 Execute the Jni_onload function in the so library: Version = (*func) (Gdvm.vmlist, NULL);
this time our gaze shifts to the C + + layer: Jni_onload (the JNI method is registered here). Look at the code, actually call the jniregisternativemethods function. But let's see if we know how some of the actual functions actually break, or rely on Dvmregisterjnimethod to perform:
static bool Dvmregisterjnimethod ( classobject* Clazz, const char * MethodName, const char * Signature, void * Fnptr) {
//interpret the following parameters:
// Clazz: Class name "Shy/luo/jni/classwithjni";
///MethodName: The Jni method name to be registered Nanosleep;
//Signature: The signature of the method is essentially the parameter and return value of the method, Functions that distinguish different parameters
//Fnptr:jni method function address is shy_luo_jni_classwithjni_nanosleep function; Dalvik is the function, it's important.
Method* method; ...... = Dvmfinddirectmethodbydescriptor (clazz, MethodName, signature); ...... Dvmusejnibridge (method, fnptr); ......}
What I'm going to add here is the attention. The dvmfinddirectmethodbydescriptor function. The function that the JNI method corresponds to in the Java layer is empty, and the JNI registration is to bind the Jni method to the corresponding Java layer function body. So how do we find them to match up? Dvmfinddirectmethodbydescriptor uses MethodName and signature parameters to achieve the above purpose. In Dvmfinddirectmethodbydescriptor, the function List of class is methods, and the args, ReturnType and signature of Methods[index] are equal, If equal, the Jni method finds the function in the Java layer (JNI: I am also a ^_^ on the upper level). Ok, find method, quickly bound Ah also don't let her escape ah.
void void* func) { = Shouldtrace (method) ? dvmtracecalljnimethod Dvmselectjnibridge(method); Dvmsetnativefunc (Method, Bridge, func); }
There is a bridge in the east, we do not look at the following will be mentioned (see the details of Lao Luo's article). See Dvmsetnativefunc directly
void dvmsetnativefunc (method* Method, Dalvikbridgefunc func, const u2* Insns) { ...//parameter Func = Bridge
//Parameter Insns = func ( Dvmsetnativefunc (method, Bridge, Func)); That is, Func = (void*) shy_luo_jni_classwithjni_nanosleep
if (Insns!= /* update both, ensuring that "Insns" is observed first */ Method->insns = Insns; Android_atomic_release_store ((int32_t) func, (void*) &method->
NATIVEFUNC);
} else { /* */ Span style= "color: #000000;" > method ->nativefunc = Func; } ...... }
in the Dvmsetnativefunc function, since bridge is assigned to Method->nativefunc,shy_luo_jni_classwithjni_ Nanosleep assigned to Method->insns, when will be executed to Shy_luo_jni_classwithjni_nanosleep AH (in Dalvik, If the method is native the Method->nativefunc will be executed )! With this question, we look back at Dvmselectjnibridge:
/** Returns the appropriate JNI bridge for ' method ', also taking to account * The-xcheck:jni setting. */ StaticDalvikbridgefunc Dvmselectjnibridge (Constmethod*method) { enum{kjnigeneral=0, Kjnisync=1, Kjnivirtualnoref=2, Kjnistaticnoref=3,} kind; Static ConstDalvikbridgefunc stdfunc[] ={dvmcalljnimethod_general, dvmcalljnimethod_synchronized, Dvmcalljnimethod_virtualnoref, DVMCALLJNIMETHOD_STATICNOREF}; Static ConstDalvikbridgefunc checkfunc[] ={dvmcheckcalljnimethod_general, dvmcheckcalljnimethod_synchronized, Dvmcheckcalljnimethod _virtualnoref, dvmcheckcalljnimethod_staticnoref}; BOOLHasrefarg =false; if(Dvmissynchronizedmethod (method)) {/*Use version with synchronization; calls to General handler*/Kind=Kjnisync; .....if(hasrefarg) {/*Use General handler to slurp up reference args*/Kind=kjnigeneral; } Else { /*virtual methods has a ref in Args[0] (not in signature)*/ if(Dvmisstaticmethod (method)) Kind=Kjnistaticnoref; ElseKind=Kjnivirtualnoref; } } returnDvmischeckjnienabled ()?Checkfunc[kind]: Stdfunc[kind]; }
look directly at the last return dvmischeckjnienabled ()? Checkfunc[kind]: stdFunc[ Kind]; Suppose to return stdfunc [kind]. Look at the above stdfunc definition, that bridge is actually a function. We then assume that the most common dvmcalljnimethod_general, then in the dvmcalljnimethod_general. OK, so let's take a look at dvmcalljnimethod_general is executing our shy_luo_jni_classwithjni_nanosleep.
void dvmcalljnimethod_general (const u4* args, jvalue* pResult, const method* method, thread* self ) ... Dvmplatforminvoke (env, Staticmethodclass, method->jniarginfo, Method->inssize, Modargs, method-> Shorty, (void*) method->Insns, pResult); ......}
Then look at Dvmplatforminvoke:
void dvmplatforminvoke (voidintint argc, constconst charvoid* func, jvalue* preturn) { ... Ffi_call (&CIF, FFI_FN (func), Preturn, values);}
Wow, see no end or call Method->insns (in Java functions, the Method->insns in Dalvik is the DEX code of the function body) Shy_luo_jni_classwithjni_nanosleep.
OK, the steps in are all gone. Discovering the essence of JNI registration is to bind the native function body to the corresponding Java layer function body, so that Dalvik discovers that the function is native when native code can be executed.
Thinking:
1 method is native, Dalvik will call Method->nativefunc to execute; When is this native flag set? When Dex is loaded into Dalvik?
2 So library loads the process when Dlopen loads and then executes calls to its jni_onload function. What is the specific implementation process? is the reinforcement of so library a fuss here?
Resources:
1 Lao Luo's Android tour
Dalvik Analysis II: JNI, so