美文网首页
对Zygote启动流程的理解

对Zygote启动流程的理解

作者: young蛘 | 来源:发表于2020-09-15 01:46 被阅读0次

    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启动流程的理解

          本文链接:https://www.haomeiwen.com/subject/zehxyktx.html