对Zygote启动流程的理解

Zygote的作用是什么?

Zygote主要作用有两点:
1.启动SystemServer。
2.孵化应用进程。
应用启动时会将常用类、JNI函数、主题资源、共享库等直接从Zygote继承,避免每个应用进程都加载一边相同的资源,达到资源共享提升性能的目的。

启动流程

进程启动

1.Linux系统启动之后,用户空间启动第一个进程init进程,init进程会读取init.rc文件,启动init.rc文件中记录的需要启动的进程。Zygote就是需要启动的进程之一。

启动配置文件init.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
writepid /dev/cpuset/foreground/tasks

2.进程是如何启动的?
Linux启动进程有两种方式,第一种是fork+handle,第二种是fork+execve.这里使用fork+execve启动进程。
fork+handle方式:

pid_t pid = fork();
if(pid==0){
    //child process 
}else{
    //parent process
}

fork+execve方式:

pid_t pid = fork();
if(pid==0){
    //child process 
    //@path 可执行程序的路径
    //@argv 执行程序的参数
    //@env 环境变量
    execve(path,argv,env);
}else{
    //parent process
}

fork函数会分别在父进程和子进程各返回一次,在子进程中返回的pid值为0,父进程中返回进程的pid,我们可以通过pid的值判断是在父进程还是子进程中。
默认情况下,创建的子进程会继承父进程的所以资源。如果调用了execve加载调用了另一个二进制程序,继承的父进程资源将被新启动程序的资源替换掉。
3.信号处理-SIGCHLD
父进程fork出子进程,如果子进程异常中止了,父进程就会收到一个SIGCHLD信号,重启子进程。如:init进程fork出zygote进程,如果zygote进程异常中止了,init进程会接收到SIGCHLD信号,然后重启zygote进程。

准备工作

Zygote进程启动之后做了什么?
Zygote启动之后,执行了execve系统调用,这个系统调用执行的是一个用C++编写的二进制可执行程序,做了一些准备工作后,Zygote就会切换到Java部分中运行。
-Zygote的Native部分
Zygote的Native部分主要有三个事情需要准备:
1.启动android虚拟机
2.注册Android的JNI函数
3.进入Java世界

int main(int argc,char *argv[]){
    JavaVM *jvm;
    JNIEnv *env;
    JNI_CreateJavaVM(&jvm,(void **)&env,&vm_args);
    jclass clazz = env->FindClass("ZygoteInit");
    jmethodID method = env-> GetStaticMethodId(clazz,"Main","([Ljava/lang/String;)V");
    env->CallStaticVoidMethod(clazz,method,args);
    jvm->DestroyJavaVM();
}

-Zygote的Java部分
1.Preload Resource
首先,zygote会预加载资源:常用类、JNI函数、主题资源、共享库等。
2.fork SystemServer
然后,zygote进程调用fork函数,启动SystemServer进程。
3.进入loop循环
接下来,SystemServer会使用Socket与Loop循环进行通信。

Loop循环

在Loop循环中。主要接收和处理Socket/MQ/Binder驱动等发来的消息。Loop循环是如何处理请求的?

boolean runOnce(){
    String[] args = readArgumentList();
    int pid = Zygote.forkAndSpecialize();
    if(pid==0){
        //in child process
        handleChildProc(args,...);
        return true;
    }
}

在runOnce函数中,先读取由AMS跨进程发送来的参数列表,然后根据参数fork出子进程,最后子进程中执行ActivityThread.main();函数。

注意:
1.Zygote在fork时要保证是单线程的。父进程中有多少个线程,如守护线程和多个虚拟机,子进程在创建的时候只有一个线程,对于子进程来说,为防止线程安全问题,如资源抢占导致死锁等情况,在fork时先暂停其他线程,fork进程结束后,再重启恢复其他线程。
2.Zygote的IPC没有采用Binder机制,而是采用了本地的socket。binder机制并不是从Zygote继承而来,而是应用程序启动之后,自己启动的binder机制。

你可能感兴趣的:(对Zygote启动流程的理解)