Zygote进程是Android和Java世界的开创者。
在Android系统中,所有的应用进程和SystemServer进程都是由Zygote进程fork而来。
Zygote进程相当于Android系统的根进程,但是事实上它也是由Linux系统的init进程启动的。
各个进程的先后顺序为:
init进程 –-> Zygote进程 –> SystemServer进程 –>应用进程
Zygote进程在init进程启动过程中被以service服务的形式启动:
init.rc中有这么一句,
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
第一行表示zygote进程是以服务的形式启动的,其对应的可执行程序是/system/bin/app_process,后面四个参数是它的启动参数。
第二行表示在Zygote启动过程中,要在其内部创建一个名为zygote的socket,它在Linux下的权限是666,即所有用户多可以对它进行读写。
因为Zygote是以service的形式启动,所以在init启动过程中,android-5.1.0_r3\android5.1\system\core\init\init.c的service_start()函数会被调用。
service_start函数的主要工作是:
•通过fork()方法创建一个新的子线程,即Zygote进程
•调用create_socket()函数创建启动脚本中的zygote socket,并保存该socket的int型的文件描述符。创建时,还会为此socket创建一个类型为AF_UNIX的Socket地址,并调用bind()方法将socket与此地址进行绑定。该socket还有一个对应的设备文件,/dev/socket/zygote。
•创建完socket后,会调用publish_socket()函数将该socket发布到系统中。采用环境变量的方式,ANDROID_SOCKET_zygote – socket的文件描述符。
•调用execve(svc->args[0]),执行app_process的主程序app_main.cpp。
app_main.cpp的main函数的主要工作是:
•通过调用AppRuntime::start()函数,通过JNI的方式,进一步启动Zygote:
AppRuntime.start(“com.android.internal.os.ZygoteInit”, args);args是参数列表,
其中较重要的是标记是否要启动System进程、记录socket名称。
ZygoteInit的main函数的主要工作是:
1、初始化DDMS
2、注册Zygote进程的Socket
3、调用registerZygoteSocket(“zygote”)函数获取到zygote socket文件描述,并根据此描述符创建一个本地服务Socket:LocalServerSocket。
这个服务Socket是用来等待Activity管理服务ActivityManagerService请求Zygote进程创建新的应用程序进程的。
4、加载framework的class、resource、OpenGL、WebView等各种系统资源
5、fork出SystemServer进程
6、启动SystemServer进程,上述的"–runtime-init"表示需要提供Binder服务,Binder服务正是在此进程。
7、最后进入runSelectLoop(),循环监听Socket信息,收到创建应用程序Socket消息,在runOnce()中调用Zygote#forkAndSpecialize()创建和启动应用进程
查看AMS代码,会看到AMS启动应用进程,就是通过socket与zygote进程通信,通知zygote进程去孵化应用进程
Zygote 会监听其 Socket (/dev/socket/zygote) 来判断是否需要启动 App。
每当监听到需要创建 App 的请求时,就 fork 一个进程即可。
fork出的应用进程,便继承了父进程zygote进程的已加载资源,所有的framework.jar的 Class 、so和 res资源,立即拥有,无需再重新加载
SystemServer的main函数的主要工作是:
•启动一个线程,启动系统的关键服务。
一旦系统服务在内存中跑起来了,Android就完成了引导过程。在这个时候“ACTION_BOOT_COMPLETED”开机启动广播就会发出去。
ActivityManagerService.java
public void systemReady(final Runnable goingCallback) {
......
// Start up initial activity.
mBooting = true;
startHomeActivityLocked(mCurrentUserId, "systemReady");
......
}
startHomeActivityLocked()方法会向PMS查询具有HOME类别的应用,即在AndroidManifest.xml有如下的声明
取其中一个包名,然后启动之,此后便是应用进程启动的部分了。
接上,AMS确定HOME应用,找到目标HOME的Activity之后,发出intent启动之,走正常的Activity启动流程。
Activity启动流程
这里,HOME首次启动时,Launcher进程不存在,所以,
AMS通过socket向Zygote进程发送启动进程的命令,从Zygote进程fork出子进程作为应用程序的进程,之后跑主线程,加载应用进程ActivityThread.java类去进行,入口是ActivityThread.main()
应用进程,主线程启动后,ActivityThread.main()里干的就是,与AMS,SMS,WMS等各种相关系统服务搭建通信桥梁,之后 ,进入Looper.loop()的主线程消息死循环!
(这便是主线程,消息循环,Handler的奥秘所在)
而后,回到AMS启动HOME目标Activity,它启动完目标进程后,消息通信了建立了,于是乎,向目标Launcher进程,发送启动目标Activity的消息
最后,ActivityThread主线程接到消息后,创建目标Activity的实例,进行一系列的Create动作(主要是创建View,窗口等),调用其生命周期,便开始了应用界面之旅…
此后,应用进程所有的事件,严重依赖其与AMS的Binder消息通道(四大组件的消息,各种广播,各种事件,都是从此消息通道过来),而主线程则一直在Handler/Looper消息循环机制中,所以应用进程,在主线程,最好只作消息处理,部分轻量UI处理,其余的,都要子线程来处理。
为何在 Android 中 fork Zygote 进程如此高效了?
Linux Kernel 采用了 Copy-On-Write 的技术,Copy-On-Write 的意思是只有在写的时候才单独复制一份,而读的时候不进行操作。 换而言之 fork zygote 实际上并未实际复制什么东西,只有在发生写操作时,才单独复制一份。而另一方面,class 和 Resource 资源文件并不需要重新写,这些文件在绝大多数时候都是只读的。
最后,实际的效果就是尽管运行着多个 APP,但实际只有一份 class 和 resource 文件在 Zygote 进程中。
关于 preloadClassed “preloaded-classes”
是一个简单的包含一系列需要预加载类的文本文件
你可以在/frameworks/base找到“preloaded-classes”文件。
preloadResources() preloadResources也意味着本地主题、布局以及android.R文件中包含的所有东西都会用这个方法加载。