总的层次调用为:html
ZygoteInit.java的main()会作什么?java
源码位置:frameworks/base/core/java/com/android/internal/os/ZygoteInit.javalinux
建立ZygoteServer,它的职能是借助socket暴露API(后边会详细介绍ZygoteServer)android
然后经过ZygoteHooks和虚拟机进行交互,告知虚拟机在zygote建立期间不要开启新的线程,不然会报错安全
Os.setpgid(0,0)并非真的能将本身的pid设置成0,详见其底层方法的官方解释架构
![]()
无关部分隐去。Linux API手册中说的是,若是都给0,那么会跟随当前所处的进程的pid和pgid(对于zygote来讲就是init在调用app_process时产生的进程的pid和pgid了)app
RuntimeInit.enableDdms()socket
android.ddm.DdmRegister.registerHandlers()函数
咱们在App中经常使用来调试查看线程、内存、UI布局等方法都是在这里注册的。oop
若是作性能收集专项,学习下系统是如何作的,能够从这里入手。
还记得传入ZygoteInit#main()方法的参数吗?
因此for循环里i从1开始计数,天然也是能够理解的了。而socket又是哪里来的呢?这个能够回头看一下init在start service时作了什么。
回忆init.zygote64.rc
在作rc文件解析时,Service解析过程当中:
system/core/init/service.cpp
待Service:Start()被调用时:
即,在Service启动时就同时建立了名为zygote的socket,具体的socket地址是:
/dev/socket/zygote
建立完成后,将socket句柄数据以环境变量的方式,放置在了 ANDROID_SOCKET_zygote 的key下。
回到参数解析。默认给了
socketName = zygote
,而以前咱们记录的参数中也并没有socket配置,因此最后生效的socket名字就是zygote
无疑
zygoteServer的链接也是后边详细说明,这里直接说结论:这里是将init所建立的名为zygote的socket给注册到Java空间来。
上边的参数解析中,并无指定lazy-perload,因此这里enableLazyPreload是false的,那么会进行preload()。这里的逻辑是:
preload的内容:
其中和咱们最息息相关的就是class的预加载了,这里边包含了众多API的Java类、Android内部类,最多见的好比Activity、Fragment、Service等也在预加载之列,而预加载的方式就是经过Class.forName:
以个人AOSP源码环境为例,体量巨大,高达6500+行:
接下来,调用了Zygote.nativeSecurityInit();
进行native的初始化,对应着:framworks/base/core/jni/com_android_internal_os_Zygote.cpp# com_android_internal_os_Zygote_nativeSecurityInit()
随时复习,这个是在AndroidRuntime初始化时进行注册的,就是在进入Java世界前的事情,详细参见上一篇
具体的内容是对SELinux进行了操做,由于系统设计上,只有系统能作SELinux相关的操做,App进程是不容许的。做为Java世界的头号玩家,Zygote在作fork(衍生出其余App前)天然要先作好安全这一步。
在这一步调用了com_android_internal_os_Zygote.cpp中的com_android_internal_os_Zygote_nativeUnmountStorageOnInit()方法。目的是将总体的存储目录/storage卸载,取而代之的是挂载临时目录,这个动做和Android9及10所说的 隔离存储 有关,也能够叫作 沙盒存储 。这一部分能够参照官方说明。
与上边呼应,告诉ART虚拟机,如今能够在zygote进程中建立线程了,下图是虚拟机中实际建立线程的入口方法,能够看到,会经过对应的标记为去判断到底是否能够建立线程,若是触发红线的话,会抛出InternalError:
在继续跟进以前,须要理清楚一个关键的角色 ZygoteServer
其在ZygoteInit.java#main(),除了构造,其被调用到的方法和顺序是:
前面说到,在init运行zygote server时候,建立了名为zygote的socket,而后将对应的socket句柄(int值)以环境变量的方式存储在了key => ANDROID_SOCKET_zygote 中。
在此方法中,经过对应的环境变量获取到了这个socket的句柄数据,而后将其转换为了Java空间的ServerSocket:
在 LocalServerSocket 中,又透过 LocalSocketImpl 开始了真正的监听。
这里只是注册,开始了监听,但尚未去获取其中的数据
ZygoteServer经过poll的方式轮训检查zygote socket。检查时对两类socket作区分处理:
ZygoteConnection.processOneCommand()
解析命令,得到对应的Runnable可执行命令,这个过程当中也就发生了fork。fork后在父进程中关闭链接,而子进程中就返回了这个Runnable大概流程如上图,忽略序号的顺序,由于有fork产生了子进程,因此顺序上看连线断定吧
最后,顾名思义,关闭ServerSocket,再也不接受链接。也就是说,zygote进程的服务终止了,这对于Android系统来讲是致命错误,正常运行状况下是绝无可能发生的。那为何还有这个方法呢?
上边的时序图中,有一个点:fork后,在父进程是不返回的,只是在ZygoteConnection中关闭了来自客户端的链接(由于此时已经处理完了)。而在fork出来的子进程中是不须要在有zygote服务的,因此这里的关闭理论上是为了在子进程中关闭无用的zygote服务所说。
分析完ZygoteServer三个关键的方法后,发现其定位就是zygote服务和客户端的链接器、处理器。客户端经过名为zygote的socket发来一些启动请求,由zygote进程fork出来子进程,享用zygote在启动初期所作好的一切(JVM初始化、JNI初始化、class预加载、资源预加载等),然后执行经过命令解析出的Runnable(下边会直接列出解析的流程)。这就是一个新的App启动过程当中相当重要的一个部分,后边会分析App启动,也会碰触到这一块。
通过了ZygoteServer的梳理,如今回到ZygoteHooks.stopZygoteNoThreadCreation()后的systemserver fork进程中
下面是用来启动system_server的关键参数:
uid、gid和组别信息,niceName、runtime参数、以及最重要的 classPath=com.android.server.SystemServer 。
以上的参数会被ZygoteConnection的内部类Arguments解析,解析过程大致以下:
--
会被视为是要跳过的参数字符当全部已知的内容被解析过以后,会检查剩余是否还有参数:
根据上述用于启动system_server的参数,咱们在这里能够断定,会走到最后的case中,即剩余的参数会被保存在remainingArgs中,即com.android.server.SystemServer
参数解析完成后,ZygoteInit调用Zygote.forkSystemServer()
着手进行fork。
此方运行调用后,会触发两次返回,前后顺序不必定(一样也不重要)。
- 一次返回是带着大于0的pid回来,此时runtime处于父进程,这个pid就是fork出来的子进程的pid
- 另外一次返回是带着等于0的pid回来,此时runtime处于子进程
这里是作fork前的准备,主要是经过调用Daemon.stop()
来操做守护线程的中止:
重置进程(主线程)优先级为 5 ,这一点经过咱们本身开发的App线程信息能够查看到
这里进行了真正的fork,使得整个流程在这里发起了两次的返回。一个比较关键的细节是:
在fork进行完成后,在 system_server 进程(子)中透过JNI触发了Java空间的回调(Zygote.java):
这个调用最终在ART虚拟机中生效,虚拟机为从zygote衍生出来的子进程作了一系列的配置。固然,这个过程当中,对于system_server有过不少特殊的待遇(好比,关闭JIT)。
在这里又会启动上边所说的四个守护线程,而且从新设置线程优先级。很关键的一点是,这里会分别在父进程、子进程执行。zygote进程中,此时也是首次开启这几个守护线程。而system_server进程,以及后边可能的其余三方App的守护线程也是在这里开启的。
至此,system_server进程的fork就完成了,后边才开始在进程中作事
这里优先解释下最后的return null,把上文呼应的问题说清楚。
在ZygoteInit#main()方法中,咱们以前对最后一段作过度析,回头复习一下:
在fork完成system_server进程后,父进程中直接返回了null。这样,在zygote的进程中就会执行到runSelectLoop,也就是上边所解释过的:处理zygote socket接收到的命令。
若是ABI(arm64等架构)有多个,那么会有第二个zygote socket,优先会去等待这第二个socket就绪。方法很传统,等待20s:
这部分不作过多讨论,咱们聚焦于主线。
关于zygoteServer的关闭,在上边也解释过,子进程并不须要保持zygote socket的链接了,因此进行断开操做。这并不会影响主进程的server socket继续工做。
很关键的一点,关于入参,上边有一笔带过,在parsedArgs中还存留着一个叫作remainingArgs的变量,其内容是com.android.server.SystemServer
。
Process.setArgV0(parsedArgs.niceName)
将system_server进程的名字真正命名为了system_server
在这里,最终调用了com.android.server.SystemServer#main()
方法,具体内容留做下次分析。