我正在尝试了解Android应用程序的启动方式。问题是Zygote为什么要分叉一个新的Dalvik虚拟机?而且为什么不能在同一个Dalvik虚拟机中运行多个应用程序?
问:Zygote如何精确地分叉Dalvik VM?
简短回答: Zygote进程在系统启动时冷启动Java VM。然后监听一个套接字以获取传入的命令。其他进程(例如ActivityManagerService)在需要应用程序的新进程时向此套接字写入命令。这些命令由Zygote进程读取,必要时调用fork()。子进程获得一个预热的VM来运行。这就是Zygote如何分叉Dalvik VM。
详细回答:内核加载后,解析init.rc并启动本地服务。然后运行/system/bin/app_process
。最终调用AndroidRuntime.start()
,将参数com.android.internal.os.ZygoteInit
和start-system-server
传递给它。
AndroidRuntime.start()
启动Java虚拟机,然后调用ZygoteInit.main()
,将参数start-system-server
传递给它。
ZygoteInit.main()
注册Zygote套接字(Zygote进程侦听传入命令的套接字,并在接收到新命令时按请求生成新进程)。然后,它预加载许多类(如frameworks/base/preloaded-classes中列出的类,在Android 8.0中超过4500个),以及所有系统范围的资源,如可绘制对象、xml等。然后它调用startSystemServer()
为com.android.server.SystemServer
分叉一个新进程。这个分支是特殊的,不像Zygote代表请求进程执行的常规分支那样执行。
在fork SystemServer之后,会调用runSelectLoopMode()
函数。这是一个while(true)
循环,它与Zygote套接字建立了一个ZygoteConnection
并等待命令。当接收到命令时,ZygoteConnection.runOnce()
被调用。
ZygoteConnection.runOnce()
然后调用Zygote.forkAndSpecialize()
,然后调用本地函数来进行实际的fork。因此,就像SystemServer的情况一样,创建了一个子进程,该进程继承了一个预热的Dalvik VM。
问:为什么不能在同一个Dalvik VM中运行多个应用程序?
据我所知,这是一个设计决策。Android开发人员只是决定为每个进程fork一个新的VM,以通过沙箱实现安全性。
不,Dalvik不跨进程。
然而,Binder IPC机制可以让对象看起来像是迁移到其他进程和其Dalvik实例中。此外,内存管理非常擅长在所有需要它们的进程之间共享只读页面。托管典型应用程序的Dalvik进程是从zygote分叉出来的,并且已经映射了所有常见的Android库,因此不需要打开新的唯一副本。
还请查看以下链接:
http://davidehringer.com/software/android/The_Dalvik_Virtual_Machine.pdf
Zygote并不是与Dalvik紧密相关的,它只是一个初始化过程。Zygote是Android用于启动应用程序的方法。它不必每次启动新进程时都从头开始加载整个系统和Android框架,而是在Zygote还没有执行任何特定于应用程序的操作之前,仅执行一次该过程,然后停止在那一点上。然后,当您想要启动应用程序时,Zygote进程会分叉,并且子进程在其离开的位置继续进行,将应用程序本身加载到VM中。
Dalvik VM
? - PcAF