1 Zygote 进程
Zygote 的父进程是 init 进程,Zygote 的子进程更多是我们的 APP 进程。 init 的子进程很多是后台的,Zygote 是能 native 进程中唯一能运行的 java 和 Kotlin 的
fork
Fork是什么,Fork是孵化子进程的方法,优势是快,创建一个父进程的副本,继承内存布局,环境变量,打开文件的描述符,也就是子进程和父进程会共享很多数据,内核只需要创建很少的数据就可以,还有个写时复制
:共享的数据当被改变了才会拷贝复制;类似懒加载的感觉。
Zygote64 :孵化 64 位用户进程,还负责孵化systemserver
Zygote : 孵化 32 位用户进程
进程的父子关系
- init pid=1
- zygote pid=1222
- zygote64 pid=1221
- system_server
- systemui
- phone
- ime
- settings
- …
- init也有很多子进程
为什么不用systemsserver来fork子进程
- systemsserver里的数据很重要和安全的,不能给子进程共享
- 很多数据子进程是不需要的,会浪费,比如子进程需要自己的binder,父进程的就浪费了,
- zygote 干净,和提前加载JVM以及一些公共资源
2init脚本文件 zygote的出生
init进程要fork很多子进程,各不相同,就配置各自的init脚本
init.zygote64_32配置了两个服务分别孵化了zygote和zygote64
- zygote服务: 执行文件 /system/bin/app_process64 参数zygote --start-system-server --socket-name=zygote
- zygote_secondary服务:执行文件 /system/bin/app_prcess32 参数 --zygote --socket-name=zygote_secondary --enable-lazy-preload
init启动这两个服务执行两个文件,带参数都走到了 app_main.cpp的main方法
//文件路径:cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
省略代码......
}
3zygote做了什么?
zygote职责
- 解析参数
- 启动JVM
- 拦截native线程创建
- 注册JNI方法
- 进入Java世界
- 解析参数
- 预加载资源
- 启动Systemserver进程
- 孵化其他app进程
参数区别
zygote 比 zygote64多一个 --enable-lazy-preload 意味不需要加载公共资源
4启动JVM
目的
启动JVM供给后续的app进程使用,这样启动更快,JVM的启动时走AppRuntime 继承AndroidRuntime
//文件路径:cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
//构造AppRuntime实例
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
省略代码......
//zygote值为true
if (zygote) {
//调用start方法开始启动JVM,并做一些其他的初始化工作
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
}
省略代码......
}
启动哪种JVM
AnroidRuntime会启动前进行目录对比,检查通过后,解耦启动,就是把启动和启动哪种JVM分开,定义规范和接口
实际中,Anroid13启动是ART
jvm版本5.0后是ARt
5拦截native线程创建
Android线程
- java线程
- native线程
- 纯native
- 可调用java的native-----拦截的是他 为了做交互
可调用java代码的native线程,需要JNIEnv对象来调用java,拦截就是为把JNIev对象交给他,JNIEnv是每个进程都有的,
6注册JNI
JNI Java Native Interface 让java能调用native
代码
例如:nativeZygoteInit 的调用
public class ZygoteInit{
省略代码......
private static native void nativeZygoteInit();
省略代码......
}
//文件路径:core/jni/AndroidRuntime.cpp
const JNINativeMethod methods[] = {
{ "nativeZygoteInit", "()V",
(void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
};
系统中具有native功能的泪有 Parcel Binder,
此处的注册JNI方法 就是调用JNIEnv的RegisterNatives方法注册,注册后才能调用,再次注册后子进程就可以继承了
7进入Java世界
前面准备好了 就可以进入java了 ,启动JVM的时候,入口是ZygoteInit的main方法,
8解析参数
解析出来的 参数64 需要start systemserev 或者加载资源相关的,32不需要,因为32用的很少,不需要浪费
9预加载资源
加载通用的,静态的,包括各种java类,图片字体等等,供给子进程继承复用
10 启动SystemServer
前面准备好后,具备了fork能力后,第一个fork的 systemserver进程,—systemserver和 zggote进程通信是socket
为什么用socket?
binder确实更快,但是此处数据量很小 ,速度影响很小,binder不合适的点:
- 子进程fork要关父进程的binder
- 父进程的mmap的共享内存也不能复用
- 父进程的多进程要需要处理锁相关的,否则可能死锁
- 子进程后续还是需要开自己的binder
所以此处socket更合适,systemserver作为client端,zygote是服务端,systemserver通知zygote去fork,
11 可孵化APP进程
启动systemserver进程后,就可以孵化app了!