Dalvik虚拟机进程和线程的创建过程分析分类:Android2013-06-0301:0322995人阅读评论(31)收藏举报AndroidDalvikProcessThread我们知道,在Android系统中,Dalvik虚拟机是运行Linux内核之上的。如果我们把Dalvik虚拟机看作是一台机器,那么它也有进程和线程的概念。事实上,我们的确是可以在Java代码中创建进程和线程,也就是Dalvik虚拟机进程和线程。那么,这些Dalvik虚拟机所创建的进程和线程与其宿主Linux内核的进程和线程有什么关系呢?本文将通过Dalvik虚拟机进程和线程的创建过程来回答这个问题。老罗的新浪微博:,欢迎关注!此外,从前面Dalvik虚拟机的运行过程分析一文可以知道,Dalvik虚拟机除了可以执行Java代码之外,还可以执行Native代码,也就是C/C++函数。这些C/C++函数在执行的过程中,又可以通过本地操作系统提供的系统调用来创建本地操作系统进程或者线程,也就是Linux进程和线程。如果在Native代码中创建出来的进程又加载有Dalvik虚拟机,那么它实际上又可以看作是一个Dalvik虚拟机进程。另一方面,如果在Native代码中创建出来的线程能够执行Java代码,那么它实际上又可以看作是一个Dalvik虚拟机线程。这样事情看起来似乎很复杂,因为既有Dalvik虚拟机进程和线程,又有Native操作系统进程和线程,而且它们又可以同时执行Java代码和Native代码。为了理清它们之间的关系,我们将按照以下四个情景来组织本文:1.Dalvik虚拟机进程的创建过程;2.Dalvik虚拟机线程的创建过程;3.只执行C/C++代码的Native线程的创建过程;4.能同时执行C/C++代码和Java代码的Native线程的创建过程。对于上述进程和线程,Android系统都分别提供有接口来创建:1.Dalvik虚拟机进程可以通过android.os.Process类的静态成员函数start来创建;2.Dalvik虚拟机线程可以通过java.lang.Thread类的成员函数start来创建;3.只执行C/C++代码的Native线程可以通过C++类Thread的成员函数run来创建;4.能同时执行C/C++代码和Java代码的Native线程也可以通过C++类Thread的成员函数run来创建;接下来,我们就按照上述四个情况来分析Dalvik虚拟机进程和线程和Native操作系统进程和线程的关系。一.Dalvik虚拟机进程的创建过程Dalvik虚拟机进程实际上就是通常我们所说的Android应用程序进程。从前面Android应用程序进程启动过程的源代码分析一文可以知道,Android应用程序进程是由ActivityManagerService服务通过android.os.Process类的静态成员函数start来请求Zygote进程创建的,而Zyogte进程最终又是通过dalvik.system.Zygote类的静态成员函数forkAndSpecialize来创建该Android应用程序进程的。因此,接下来我们就从dalvik.system.Zygote类的静态成员函数forkAndSpecialize开始分析Dalvik虚拟机进程的创建过程,如图1所示:图1Dalvik虚拟机进程的创建过程这个过程可以分为3个步骤,接下来我们就详细分析每一个步骤。Step1.Zygote.forkAndSpecialize[java]viewplaincopyprint?1.publicclassZygote{2.......3.4.nativepublicstaticintforkAndSpecialize(intuid,intgid,int[]gids,5.intdebugFlags,int[][]rlimits);6.7.......8.}这个函数定义在文件libcore/dalvik/src/main/java/dalvik/system/Zygote.java中。Zygote类的静态成员函数forkAndSpecialize是一个JNI方法,它是由C++层的函数Dalvik_dalvik_system_Zygote_forkAndSpecialize来实现的,如下所示:[cpp]viewplaincopyprint?1./*nativepublicstaticintforkAndSpecialize(intuid,intgid,2.*int[]gids,intdebugFlags);3.*/4.staticvoidDalvik_dalvik_system_Zygote_forkAndSpecialize(constu4*args,5.JValue*pResult)6.{7.pid_tpid;8.9.pid=forkAndSpecializeCommon(args,false);10.11.RETURN_INT(pid);12.}这个函数定义在文件dalvik/vm/native/dalvik_system_Zygote.c中。注意,参数args指向的是一个u4数组,它里面包含了所有从Java层传递进来的参数,这是由Dalvik虚拟机封装的。另外一个参数pResult用来保存JNI方法调用结果,这是通过宏RETURN_INT来实现的。函数Dalvik_dalvik_system_Zygote_forkAndSpecialize的实现很简单,它通过调用另外一个函数forkAndSpecializeCommon来创建一个Dalvik虚拟机进程。Step2.forkAndSpecializeCommon[cpp]viewplaincopyprint?1./*2.*Utilityroutinetoforkzygoteandspecializethechildprocess.3.*/4.staticpid_tforkAndSpecializeCommon(constu4*args,boolisSystemServer)5.{6.pid_tpid;7.8.uid_tuid=(uid_t)args[0];9.gid_tgid=(gid_t)args[1];10.ArrayObject*gids=(ArrayObject*)args[2];11.u4debugFlags=args[3];12.ArrayObject*rlimits=(ArrayObject*)args[4];13.int64_tpermittedCapabilities,effectiveCapabilities;14.15.if(isSystemServer){16./*17.*Don'tuseGET_ARG_LONGherefornow.gccisgeneratingcode18.*thatusesregisterd8asatemporary,andthat'scomingout19.*scrambledinthechildprocess.b/313862120.*/21.//permittedCapabilities=GET_ARG_LONG(args,5);22.//effectiveCapabilities=GET_ARG_LONG(args,7);23.permittedCapabilities=args[5]|(int64_t)args[6]32;24.effectiveCapabilities=args[7]|(int64_t)args[8]32;25.}else{26.permittedCapabilities=effectiveCapabilities=0;27.}28.29.if(!gDvm.zygote){30.......31.return-1;32.}33.34.......35.36.pid=fork();37.38.if(pid==0){39.interr;40.......41.42.err=setgroupsIntarray(gids);43.......44.45.err=setrlimitsFromArray(rlimits);46.......47.48.err=setgid(gid);49.......50.51.err=setuid(uid);52.......53.54.err=setCapabilities(permittedCapabilities,effectiveCapabilities);55.......56.57.enableDebugFeatures(debugFlags);58.......59.60.gDvm.zygote=false;61.if(!dvmInitAfterZygote()){62.......63.dvmAbort();64.}65.}elseif(pid0){66./*theparentprocess*/67.}68.69.returnpid;70.}这个函数定义在文件dalvik/vm/native/dalvik_system_Zygote.c中。函数forkAndSpecializeCommon除了可以用来创建普通的Android应用程序进程之外,还用来创建System进程。Android系统中的System进程和普通的Android应用程序进程一样,也是由Zygote进程负责创建的,具体可以参考前面Android系统进程Zygote启动过程的源代码分析一文。当函数forkAndSpecializeCommon是调用来创建System进程的时候,参数isSystemServer的值就等于true,这时候在参数列表args就会包含两个额外的参数permittedCapabilities和effectiveCapabilities。其中,permittedCapabilities表示System进程允许的特权,而effectiveCapabilities表示System进程当前的有效特权,这两个参数的关系就类似于进程的uid和euid的关系一样。进程的特权是什么概念呢?从Linux2.2开始,Root用户的权限被划分成了一系列的子权限,每一个子权限都通过一个bit来表示,这些bit的定义可以参考CAPABILITIES(7)。每一个进程都关联有一个u32整数,用来描述它所具有的Root用户子权限,我们可以通过系统调用capset来进行设置。参考前面Android系统进程Zygote启动过程的源代码分析一篇文章可以知道,Zygote进程在创建System进程的时候,给它指定的permittedCapabilities和effectiveCapabilities均为130104352,因此,System进程在运行的时候,就可以获得一些Root用户特权。当参数isSystemServer的值等于false的时候,变量permittedCapabilities和effectiveCapabilities的值被设置为0,也就是说,由Zygote进程创建出来的Android应用程序进程是不具有任何的Root用户特权的。除了上述的permittedCapabilities和effectiveCapabilities之外,参数列表args还包含了其它的参数:--uid:要创建的进程的用户ID。一般来说,每一个应用程序进程都有一个唯一的用户ID,用来将应用程序进程封闭在一个沙箱里面运行。--gid:要创建的进程的用户组ID。一般来说,每一个应用程序进程都有一个唯一的用户组ID,也是用来将应用程序进程封闭在一个沙箱里面运行。--gids:要创建的进程的额外用户组ID。这个额外的用户组ID实际上对应的就是应用程序所申请的资源访权限。--debugFlags:要创建的进程在运行时的调试选项。例如,我们可以将debugFlags的DEBUG_ENAB