对zygote的理解

Zygote进程是怎么启动的?

Linux启动后启动的第一个用户进程是Init进程,Init进程启动后会加载启动配置文件(init.rc),判断配置文件中定义了哪些配置服务是需要启动的,Zygote就是需要启动的服务之一。

启动进程的方式有两种:

  1. fork + handle
pid_t pid = fork();
if(pid == 0) {
	//child process
} else {
	//parent process
}
  1. fork + execve
pid_t pid = fork();
if(pid == 0) {
	//child process
	execve(path,argv,env);
} else {
	//parent process
}

两种方式都会首先调用fork函数,fork函数会返回两次,分别在子进程和父进程中各返回一次

  • 在子进程中pid返回0
  • 在父进程中pid返回子进程的pid

根据pid是否为0来判断当前是子进程还是父进程
子进程默认继承了父进程的所有资源,如果调用了execev系统调用去加载另外的二进制程序,继承的父进程资源就会被新加载的资源替换掉

信号处理-SIGCHLD
父进程fork出了子进程,如果子进程挂掉了,则父进程会收到SIGCHLD信号,这时可以去做一些处理。
例如Zygote如果挂掉了,这时候Init进程将会收到SIGCHLD信号,然后去重启Zygote进程。

Zygote进程启动后做了什么?

Zygote的Native世界

  1. 启动Android虚拟机
  2. 注册Android的JNI函数
  3. 进入Java世界

Native切换到Java

int main(int argc,char *argv[]){
	JavaVM *jvm;
	JNIEnv *env;
	JNI_CreateJavaVM(&jvm,(void**)&env,&vm_args); //创建Java虚拟机
	jclass clazz = env->FindClass("ZygoteInit"); //找到叫ZygoteInit的Java类
	jmethodID method = env->GetStaticMethodID(clazz,"Main","[Ljava/lang/String;)V"); //找到ZygoteInit类中的Main的静态函数
	env->CallStaticVoidMethod(clazz,method,args); //调用main函数
	jvm->DestroyJavaVM();
}

Zygote的Java世界

//ZygoteInit.java
public static void main(String argv[]){
    //1.预加载frameworks/base/preloaded-classes和framework_res.apk资源,linux在fork进程时,只是为子进程创建一个数据结构,使子进程地址空间映射到与父进程相同的物理内存空间。虚拟机的创建也是实例拷贝,共享系统资源,如果每创建一个虚拟机都加载一份系统资源,将会非常耗时和浪费。子进程在刚fork生成时,完全共享父进程的进程物理空间,采用写时复制的方式共享资源。
    preloadClasses();
    preloadResources();
    preloadSharedLibraries();
       
    // 2. 启动system_server进程。该进程是framework的核心。
    if(argv[1].equals("start-system-server")){
        startSystemServer(); 
    } 
  
   //3.创建Socket服务
   registerZygoteSocket();
  
   //4.进入Loop循环,等待连接(socket消息),用以处理来自AMS申请进程创建的请求
   runSelectLoopMode();  
}

进入Loop循环后,如果接收到socket请求,则会执行runOnce

boolean runOnce() {
	String[] args = readArgumentList(); //读取参数列表
	int pid = Zygote.forkAndSpecialize(); //根据读取到的参数启动子进程
	if(pid == 0) {
		//in child
		//执行ActivityThread的入口函数(main)
		handleChildProc(args,...);
		return true;
	}
}

注意

  • Zygote fork要单线程
  • Zygote的IPC是采用socket

相关问题

孵化应用进程为什么不交给SystemServer来做,而是专门设计一个Zygote?

我们知道,应用在启动的时候需要做很多准备工作,包括启动虚拟机,加载各类系统资源等等,这些都是非常耗时的,如果能在zygote里就给这些必要的初始化工作做好,子进程在fork的时候就能直接共享,那么这样的话效率就会非常高。这个就是zygote存在的价值,这一点呢systemServer是替代不了的,主要是因为systemServer里跑了一堆系统服务,这些是不能继承到应用进程的。而且我们应用进程在启动的时候,内存空间除了必要的资源外,最好是干干净净的,不要继承一堆乱七八糟的东西。所以呢,不如给systemServer和应用进程里都要用到的资源抽出来单独放在一个进程里,也就是这的zygote进程,然后zygote进程再分别孵化出systemServer进程和应用进程。孵化出来之后,systemServer进程和应用进程就可以各干各的事了。

Zygote的IPC通信机制为什么不采用binder?如果采用binder会有什么问题?

因为服务端的Binder必须运行在线程池中,而客户端在连接服务端的Binder时会导致本线程挂起,如果服务端Binder意外死亡,会导致客户端本线程死锁。另外Linux的fork()方法不允许多线程。

Zygote的作用是什么?

  1. 预加载需要使用到的类和系统资源,子进程在刚fork的时候共享父进程的资源,加快了应用程序的启动速度
  2. 启动SystemServer
  3. 启动Loop循环用于监听AMS发送过来的消息,然后调用ActivityThread来启动相对应的app
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值