@Dlive
本文档:
使用的Android源码版本为:Android-4.4.3_r1 kitkat
(源码下载: http://source.android.com/source/index.html)
使用的源码阅读工具为Source Insight
源码结构:
0x00 Zygote介绍
Zygote是在设备开启的时候init启动的其中一个进程。在Android系统中,所有的应用程序进程,以及用来运行系统关键服务的System进程都是由Zygote进程负责创建的,因为其行为很想受精卵的分裂行为,故取名Zygote。
Zygote进程是通过复制自身的方式创建System进程和应用程序进程的。由于Zygote进程在启动时会在内部创建一个虚拟机实例,因此通过复制Zygote进程而得到的System进程和应用程序进程可以快速地在内部获得一个虚拟机实例拷贝。
0x01 Zygote的启动过程
1.1 从init到app_process
Zygote由init进程启动,init是Linux系统中用户空间的第一个进程,由于Android是基于Linux内核的。所以init也是Android系统中用户空间的第一个进程。内核启动之后,系统就通过启动一个用户级程序init的方法来完成引导。init是第一个进程,进程id为1。
init进程需要做很多重要的工作,它负责创建系统中几个关键进程,比如我们这里要说的Zygote。
Zygote启动脚本:system/core/rootdir/init.rc
第1行:从启动脚本中可以看出Zygote进程是以服务形式启动的,并且对应的应用程序为/system/bin/app_process,启动参数—start-system-server表示启动Zygote之后需要马上将System进程启动起来
第3行:Zygote进程在启动过程中,在内部创建一个名称为Zygote的Socket,这个Socket使用来执行进程间通信的,权限设置为666即 rw-rw-rw-
第4-7行:onrestart表示Zygote进程重启时需要执行的命令
从上面的信息我们可以知道Zygote进程要执行的程序是/system/bin/app_process,它的源代码在
framework/base/cmds/app_process/app_main.cpp文件中
接下来我们分析app_main.cpp中的代码
这个main函数的功能很简单,检查传入的命令行参数,之前我们看到init.rc中传入了两个选项—zygote, --start-system-server,之后调用AppRuntime的start方法。
1.2 AppRuntime分析
AppRuntime对应的源码同样在
frameworks/base/cmds/app_process/app_main.cpp中,它继承自AndroidRuntime。
AppRuntime重载了onStarted, onZygote和onExit函数,前面app_main中调用的start方法在AndroidRuntime定义。
所以下面主要分析AndroidRuntime的源码
AndroidRuntime类定义在framework/base/core/jni/AndroidRuntime.cpp中。
AndroidRuntime的start函数的主要作用是启动Android系统运行时库,它主要做了三件事情
一是调用函数startVm启动虚拟机
startVm函数就是调用JNI的虚拟机创建函数,创建函数时的一些参数是在startVm中确定的
设置JNI check选项:
设置虚拟机的heapsize,默认为16MB
还有一些其他的选项如code cache的大小
二是调用函数startReg注册JNI方法
注册一些JNI函数,因为之后在Java层很多函数是使用native方式实现的,所以要提前注册JNI函数。
调用register_jni_procs进行JNI函数注册
注册的函数:
三是调用了com.android.internal.os.ZygoteInit类的main函数。
在之前app_main.c中的main函数调用start函数时传递的参数为:com.android.internal.os.ZygoteInit,即className的值
获取到类的完整名称后,调用toSlashClassName将类名转换为JN规范的类名com/android/internal/os/ZygoteInit
之后通过JNI的findClass方法,获取jclass,之后获取类中main函数ID,然后通过CallStaticVoidMethod方法调用Java层静态方法。
自此进入Java层。
关于JNI的介绍可以参考我的博客上的《Android JNI总结》这篇文章:
http://www.cnblogs.com/dliv3/p/5423243.html
1.3 进入Java层
之前在AndroidRuntime的start方法中通过JNI调用了Java层ZygoteInit的main方法。
main方法主要做了三件事情
一是调用registerZygoteSocket函数创建了一个socket接口,用来和ActivityManagerService通讯
registerZygoteSocket创建一个服务端Socket
二是调用startSystemServer函数来启动SystemServer组件
startSystemServer会创建Java层中系统Service所驻留的进程system_server,该进程是framework的核心。
startSystemServer的关键代码如下,Zygote fork出一个system_server进程
三是调用函数进入一个无限循环在前面创建的socket接口上等待ActivityManagerService请求创建新的应用程序进程。
runSelectLoop关键代码如下:
runSelectLoop处理客户端和客户请求,客户在zygote中用ZygoteConnection对象来表示,客户请求由ZygoteConnection的runOnce来处理。
1.4 Zygote启动过程总结
用一个时序图来简要展现Zygote启动过程
0x02 Zygote的分裂
之前Zygote通过runSelectLoop等待并处理来自客户的消息,以一个Activity的启动为例,具体分析Zygote的分裂过程。
2.1 客户端请求
ActivityManagerService由SystemServer创建。
ActivityManagerService源码位置
frameworks\base\services\java\com\android\server\am\ActivityManagerService.java
ActivityManagerService的startProcessLocked函数源码如下:
调用了Process.start函数:
接着在Process.start中调用了startViaZygote
startViaZygote中调用了zygoteSendArgsAndGetResult函数
接着又调用了openZygoteSocketIfNeed,跟到openZygoteSocketIfNeed函数实现可以看到函数中打开了Socket并进行读写操作,即ActivityManagerService向Zygote发生请求。请求参数中有一个字符串值为“android.app.ActivityThread”
2.2 Zygote响应请求
在之前分析Zygote的启动过程时,Zygote最后调用了runSelectLoop,runSelectLoop中处理客户端请求。
处理过程如下:
当有请求数据发来时,Zygote就会调用ZygoteConnection的runOnce函数。
ZygoteConnection.runOnce函数关键代码如下:
可以看到Zygote又分裂出一个子进程,子进程会调用handleChildProc函数如下所示(同样在ZygoteConnection.runOnce函数代码中)
2.3 Zygote分裂过程总结
和启动过程一样,也用一个时序图来简要展现Zygote的分裂过程
0x03 参考资料
1. 《深入理解Android 卷1》 邓凡平
2. 《Android系统源代码情景分析》 罗升阳
3. 《Android源码分析实录》 李忠良
4. Android系统进程Zygote启动过程的源码分析
http://blog.csdn.net/luoshengyang/article/details/6768304
5. Zygote进程 – Zygote的分裂
http://blog.csdn.net/zhgxhuaa/article/details/24584807
6. Android JNI总结