Zygote进程1 - 概述

第一部分 why zygote
1 加快应用进程创建速度,通过fork和写时复制技术copyOnwrite
zygote通过共享已运行的虚拟机的代码和内存信息,缩短应用程序运行所耗费的时间,并且,它会事先将应用程序要使用的Android framework要使用的类和资源加载到内存中,并组织成所用资源的链接信息。新运行的Android应用程序在使用所需资源时不必每次重新形成资源的链接信息,这会节省大量时间,提高程序运行速度。
2 复制android虚拟机,以便运行android应用程序
android应用程序是由Java编写的,它们不能直接以本地进程的形态运行在linux上,只能运行在android虚拟机中,每个进程都运行在各自的虚拟机中,应用程序每次运行都要重新初始化并启动虚拟机,这个过程会耗费相当长时间,是拖慢应用进程的原因之一。


几个常见的进程uid,pid情况
USER PID PPID VSIZE RSS WCHAN PC NAME
root 1 0 8504 1516 SyS_epoll_ 00000000 S /init //android进程祖先
root 2 0 0 0 kthreadd 00000000 S kthreadd //daemon守护进程祖先,运行在内核态
install 174 1 1160 380 ffffffff 00000000 S /system/bin/installd
root 178 1 1498368 50552 ffffffff 00000000 S zygote
shell 181 1 5684 212 ffffffff 00000000 S /sbin/adbd
system 474 178 1578360 92828 ffffffff 00000000 S system_server
从中可以知道init进程的uid是root,0号进程(idle进程,swapper进程)是所有进程的祖先,0号进程是第一个内核进程。

在Android系统中,所有的应用程序进程以及系统服务进程SystemServer都是由Zygote进程孕育(fork)出来的,这也许就是为什么要把它称为Zygote(受精卵)的原因吧。
Android系统是基于Linux内核的,而在Linux系统中,所有的进程都是init进程的子孙进程,也就是说,所有的进程都是直接或者间接地由init进程fork出来的。Zygote进程也不例外,它是在系统启动的过程,由init进程创建的。在系统启动脚本system/core/rootdir/init.rc文件中,
import /init.${ro.zygote}.rc
这里就会根据具体的ro.zygote的值,import对应的rc文件,比如system/core/rootdir/init.zygote32.rc文件
代码如下:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd

前面的关键字service告诉init进程创建一个名为"zygote"的进程,这个zygote进程要执行的程序是/system/bin/app_process,后面是要传给app_process的参数。
class main表示这个服务在main分组中,随main分组启动,init进程 先启动core class, 至于main class的启动是由vold.decrypt的以下4个值的设置所决定的, 该过程位于system/vold/cryptfs.c文件。
on nonencrypted class_start main class_start late_start on property:vold.decrypt=trigger_restart_min_framework class_start mainon property:vold.decrypt=trigger_restart_framework class_start main class_start late_starton property:vold.decrypt=trigger_reset_main class_reset main on property:vold.decrypt=trigger_shutdown_framework class_reset late_start class_reset main
2018/06/01 09:13 补充vold知识

        接下来的socket关键字表示这个zygote进程需要一个名称为"zygote"的socket资源,这样,系统启动后,我们就可以在/dev/socket目录下看到有一个名为zygote的文件。这里定义的socket的类型为unix domain socket,它是用来作本地进程间通信用的,具体可以参考前面一篇文章 Android学习启动篇 提到的一书《Linux内核源代码情景分析》的第七章--基于socket的进程间通信。前面我们说到的ActivityManagerService就是通这个socket来和zygote进程通信请求fork一个应用程序进程的了。
        最后的一系列onrestart关键字表示这个zygote进程重启时需要执行的命令。
        关于init.rc文件的更多信息,请参考system/core/init/readme.txt文件。
        了解了这个信息之后,我们就知道Zygote进程要执行的程序便是system/bin/app_process了,它的源代码位于frameworks/base/cmds/app_process/app_main.cpp文件中,入口函数是main。在继续分析Zygote进程启动的过程之前,我们先来看看它的启动序列图:

这里多讲一句frameworks/base/cmds/app_process/里面生成的模块就是app_process
根据情况会生成app_process app_process32或者app_process64

第二部分 linux进程和android进程

linux中父进程调用fork函数创建新的子进程A’,新创建的进程A’共享父进程的内核结构信息和库链接信息,而后子进程A'调用exec(B),将新进程B的代码加载到内存中,此时,A'的内存信息被清除,以供进程B使用。若进程B使用的共享库已被装载至内存,则只需要更新连接信息。不然,还要添加一个步骤,即将存储器中相关库转入内存之中。每当运行新进程时,会重复以上过程。这种方式在android中有驱动进程、守护进程servicemanager、ueventd、rild等

Zygote进程调用fork创建Zygote'子进程,子进程Zygote'共享父进程的代码区和连接信息,但是,新的Android应用并非通过exec系统调用来重新装载应用进程的代码区,而是被动态加载到复制出的android虚拟机上,而后Zygote'子进程将执行流交给应用程序A类的方法,Android应用程序开始运行。新生的应用进程A会使用已有Zygote进程的库和资源的链接信息,所以运行速度很快。

第三部分 Android应用进程的运行过程

如图所示,Zygote进程启动后,初始化并运行android虚拟机,而后将需要的类和资源加载到内存中。随后调用fork创建Zygote’子进程,接着Zygote'子进程动态加载并运行Android应用程序A,运行的应用程序A会使用Zygote已经初始化并启动运行的android虚拟机代码,通过已加载至内存中的类和资源来加载运行速度。

COW(copy on write)
在创建新进程后,新进程会共享父进程的内存空间,即新进程会复制所以与父进程内存空间相关的信息并使用它。COW就是针对内存复制的一种技术。一般来说,复制内存的开销非常大,因此创建的子进程在引用父进程的内存空间时,不需要进行复制,而要直接共享父进程的内存空间,当需要修改共享内存时,子进程才会将父进程中相关的内存信息复制到自身的内存空间,并进行修改,这就是COW技术。linux上线程(轻量级进程)就可以利用这种技术

需要注意的是当调用fork直接运行exec时,新进程的内存空间与父进程的内存空间内容不同,此时复制父进程内存空间的做法就变得毫无意义,并且会增加新进程运行的系统开销。


Zygote进程类图

Android应用进程相关类。比如四大组件Activity、Service、ContentProvider、Broadcast的运行都是通过反射机制来完成的,就不像是am、logd那样编译成一个可执行程序文件通过系统调用execve来执行。

参考:Android框架揭秘

猜你喜欢

转载自blog.csdn.net/xuning2516/article/details/80558718