Dalvik虚拟机的运行过程分析.docx
《Dalvik虚拟机的运行过程分析.docx》由会员分享,可在线阅读,更多相关《Dalvik虚拟机的运行过程分析.docx(19页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、从前面Dalvik虚拟机的启动过程分析一文可以知道,Dalvik虚拟机在Zygote进程中启动完成之后,就会获得一个JavaVM实例和一个JNIEnv实例。其中,获得的JavaVM实例就是用来描述Zygote进程的Dalvik虚拟机实例,而获得的JNIEnv实例描述的是Zygote进程的主线程的JNI环境。紧接着,Zygote进程就会通过前面获得的JNIEnv实例的成员函数CallStaticVoidMethod来调用com.android.internal.os.ZygoteInit类的静态成员函数main。这就相当于是将com.android.internal.os.ZygoteInit类
2、的静态成员函数main作为Java代码的入口点。 接下来,我们就从JNIEnv类的成员函数CallStaticVoidMethod开始,分析Dalvik虚拟机的运行过程,如图1所示:图1 Dalvik虚拟机的运行过程 这个过程可以分为9个步骤,接下来我们就详细分析每一个步骤。 Step 1.JNIEnv.CallStaticVoidMethodcppview plaincopy1. struct_JNIEnv;2. .3. typedef_JNIEnvJNIEnv;4. .5. 6. struct_JNIEnv7. /*donotrenamethis;itdoesnotseemtobeenti
3、relyopaque*/8. conststructJNINativeInterface*functions;9. .10. 11. voidCallStaticVoidMethod(jclassclazz,jmethodIDmethodID,.)12. 13. va_listargs;14. va_start(args,methodID);15. functions-CallStaticVoidMethodV(this,clazz,methodID,args);16. va_end(args);17. 18. 19. .20. ; 这个函数定义在文件dalvik/libnativehelpe
4、r/include/nativehelper/jni.h中。 JNIEnv实际上是一个结构,它有一个成员变量functions,指向的是一个回调函数表。这个回调函数表使用一个JNINativeInterface对象来描述。JNIEnv结构体的成员函数CallStaticVoidMethod的实现很简单,它只是调用该回调函数表中的CallStaticVoidMethodV函数来执行参数clazz和methodID所描述的Java代码。 Step 2.JNINativeInterface.CallStaticVoidMethodVcppview plaincopy1. structJNINativ
5、eInterface2. .3. 4. void(*CallStaticVoidMethodV)(JNIEnv*,jclass,jmethodID,va_list);5. 6. .7. ; 这个函数定义在文件dalvik/libnativehelper/include/nativehelper/jni.h中。 JNINativeInterface是一个结构体,它的成员变量CallStaticVoidMethodV是一个函数指针。 从前面Dalvik虚拟机的启动过程分析一文可以知道,Dalvik虚拟机在内部为Zygote进程的主线程所创建的Java环境是用一个JNIEnvExt结构体来描述的,并
6、且这个JNIEnvExt结构体会被强制转换成一个JNIEnv结构体返回给Zygote进程。 JNIEnvExt结构体定义在文件dalvik/vm/JniInternal.h中,如下所示:cppview plaincopy1. typedefstructJNIEnvExt2. conststructJNINativeInterface*funcTable;/*mustbefirst*/3. 4. .5. JNIEnvExt; 从这里就可以看出,虽然结构体JNIEnvExt和JNIEnv之间没有继承关系,但是它们的第一个成员变量的类型是一致的,也就是它们都是指向一个类型为JNINativeInte
7、rface的回调函数表,因此,Dalvik虚拟机可以将一个JNIEnvExt结构体强制转换成一个JNIEnv结构体返回给Zygote进程,这时候我们通过JNIEnv结构体来访问其成员变量functions所描述的回调函数表时,实际访问到的是对应的JNIEnvExt结构体的成员变量funcTable所描述的回调函数表。 为什么不直接让JNIEnvExt结构体从JNIEnv结构体继承下来呢?这样把一个JNIEnvExt结构体转换为一个JNIEnv结构体就是相当直观的。然而,Dalvik虚拟机的源代码并一定是要以C+语言的形式来编译的,它也可以以C语言的形式来编译的。由于C语言没有继承的概念,因此,
8、为了使得Dalvik虚拟机的源代码能同时兼容C+和C,这里就使用了一个Trick:只要两个结构体的内存布局相同,它们就可以相互转换访问。当然,这并不要求两个结构体的内存布局完全相同,但是至少开始部分要求是相同的。在这种情况下,将一个结构体强制转换成另外一个结构体之外,只要不去访问内存布局不一致的地方,就没有问题。在Android系统的Native代码中,我们可以常常看到这种Trick。 接下来,我们需要搞清楚的是JNIEnvExt结构体的成员变量funcTable指向的回调函数表是什么。同样是从前面Dalvik虚拟机的启动过程分析一文可以知道,Dalvik虚拟机在创建一个JNIEnvExt结构
9、体的时候,会将它的成员变量funcTable指向全局变量gNativeInterface所描述的一个回调函数表。 gNativeInterface定义在文件dalvik/vm/Jni.c中,如下所示:cppview plaincopy1. staticconststructJNINativeInterfacegNativeInterface=2. .3. 4. CallStaticVoidMethodV,5. 6. .7. ; 在这个回调函数表中,名称为CallStaticVoidMethodV的函数指针指向的是一个同名函数CallStaticVoidMethodV。 函数CallStatic
10、VoidMethodV同样是定义在文件dalvik/vm/Jni.c中,不过它是通过宏CALL_STATIC来定义的,如下所示:cppview plaincopy1. #defineCALL_STATIC(_ctype,_jname,_retfail,_retok,_isref)2. .3. static_ctypeCallStatic#_jname#MethodV(JNIEnv*env,jclassjclazz,4. jmethodIDmethodID,va_listargs)5. 6. UNUSED_PARAMETER(jclazz);7. JNI_ENTER();8. JValueres
11、ult;9. dvmCallMethodV(_self,(Method*)methodID,NULL,true,&result,args);10. if(_isref&!dvmCheckException(_self)11. result.l=addLocalReference(env,result.l);12. JNI_EXIT();13. return_retok;14. 15. .16. CALL_STATIC(void,Void,false); 通过上面的分析就可以知道,在JNIEnvExt结构体的成员变量funcTable所描述的回调函数表中,名称为CallStaticVoidMet
12、hodV的函数指针指向的是一个同名函数CallStaticVoidMethodV。这就是说,我们通过JNIEnv结构体的成员变量functions所访问到的名称为CallStaticVoidMethodV函数指针实际指向的是函数CallStaticVoidMethodV。 Step 3.CallStaticVoidMethodV 我们将上面的CALL_STATIC宏开之后,就可以得到函数CallStaticVoidMethodV的实现,如下所示:cppview plaincopy1. static_ctypeCallStaticVoidMethodV(JNIEnv*env,jclassjcla
13、zz,2. jmethodIDmethodID,va_listargs)3. 4. UNUSED_PARAMETER(jclazz);5. JNI_ENTER();6. JValueresult;7. dvmCallMethodV(_self,(Method*)methodID,NULL,true,&result,args);8. if(_isref&!dvmCheckException(_self)9. result.l=addLocalReference(env,result.l);10. JNI_EXIT();11. return_retok;12. 函数CallStaticVoidMe
14、thodV的实现很简单,它通过调用另外一个函数dvmCallMethodV来执行由参数jclazz和methodID所描述的Java代码,因此,接下来我们就继续分析函数dvmCallMethodV的实现。 Step 4.dvmCallMethodVcppview plaincopy1. voiddvmCallMethodV(Thread*self,constMethod*method,Object*obj,2. boolfromJni,JValue*pResult,va_listargs)3. 4. .5. 6. if(dvmIsNativeMethod(method)7. TRACE_MET
15、HOD_ENTER(self,method);8. /*9. *Becauseweleavenospaceforlocalvariables,curFramepoints10. *directlyatthemethodarguments.11. */12. (*method-nativeFunc)(self-curFrame,pResult,method,self);13. TRACE_METHOD_EXIT(self,method);14. else15. dvmInterpret(self,method,pResult);16. 17. 18. .19. 这个函数定义在文件dalvik/v
16、m/interp/Stack.c中。 函数dvmCallMethodV首先检查参数method描述的函数是否是一个JNI方法。如果是的话,那么它所指向的一个Method对象的成员变量nativeFunc就指向该JNI方法的地址,因此就可以直接对它进行调用。否则的话,就说明参数method描述的是一个Java函数,这时候就需要继续调用函数dvmInterpret来执行它的代码。 Step 5.dvmInterpretcppview plaincopy1. voiddvmInterpret(Thread*self,constMethod*method,JValue*pResult)2. 3. In
17、terpStateinterpState;4. .5. 6. /*7. *Initializeworkingstate.8. *9. *Noneedtoinitializeretval.10. */11. interpState.method=method;12. interpState.fp=(u4*)self-curFrame;13. interpState.pc=method-insns;14. .15. 16. typedefbool(*Interpreter)(Thread*,InterpState*);17. InterpreterstdInterp;18. if(gDvm.exe
18、cutionMode=kExecutionModeInterpFast)19. stdInterp=dvmMterpStd;20. #ifdefined(WITH_JIT)21. elseif(gDvm.executionMode=kExecutionModeJit)22. /*Ifprofilingoverheadcanbekeptlowenough,wecanuseaprofiling23. *mterpfastforbothJitandfastmodes.Ifoverheadistoohigh,24. *createaspecializedprofilinginterpreter.25.
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Dalvik 虚拟机 运行 过程 分析
限制150内