Zygote工作流程

Zygote的作用

1)启动SystemServer(使用zygote的资源:常用类,JNI函数,主题资源,共享库)
2)孵化app应用进程

如何启动的

1)通过init进程,init进程是系统启动后用户空间第一个进程,它通过读取init.rc读取那些系统服务需要启动,如zygote, service manager, 启动是通过fork() + execve()做的。

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

2)子进程会继承父进程的资源,但是如果调用execve()执行了新程序,那继承的资源就会被清掉,被新的二进制程序替换掉。

3)启动后的流程 native层:zygote启动后,执行了execve系统调用,执行了c++的二进制程序,有main函数做入口,虽然zygote天生就是native的,做好准备工作后,就切到java世界运行了。 java层:

int main(int argc, char *argv[]){
    javaVM *jvm;
    JNIEnv *env;
    JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);  //创建虚拟机
    jclass clazz = env->FindClass("ZygoteInit");    //找到zygoteinit java类
    jmethodID method = env->GetStaticMethodID(clazz, "Main", "([java/lang/String;)V"); //找到里面的main函数
    env->CallStaticVoidMethod(clazz, method, args); //运行main函数
    jvm->DestroyJavaVM();
}

整理流程为:
1)启动Android虚拟机
2)注册Android的JNI函数
3)通过JNI调用,进入JAVA世界

ZygoteInit的main方法

public static void main(String argv[]) {
    //zygote服务类 
    ZygoteServer zygoteServer = new ZygoteServer();
    //不允许创建新的线程否则会报错
    ZygoteHooks.startZygoteNoThreadCreation();
    //绑定进程
    try {
        Os.setpgid(0, 0);
    } catch (ErrnoException ex) {
        throw new RuntimeException("Failed to setpgid(0,0)", ex);
    }
    final Runnable caller;
    try {
        ....
        省略一些log输出
        ....
        //注册ddms
        RuntimeInit.enableDdms();
        //标识是否要启动系统服务
        boolean startSystemServer = false;
        //socket名称
        String socketName = "zygote";
        String abiList = null; // abi列表(armeabi、armeabi-v7a、x86等)
        //标识是否要预加载资源
        boolean enableLazyPreload = false;
        for (int i = 1; i < argv.length; i++) {
            if ("start-system-server".equals(argv[i])) {
                startSystemServer = true; //启动系统服务
            } else if ("--enable-lazy-preload".equals(argv[i])) {
                enableLazyPreload = true; //预加载资源
            } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                abiList = argv[i].substring(ABI_LIST_ARG.length());//获取abi
            } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                socketName = argv[i].substring(SOCKET_NAME_ARG.length());//获取socket名称
            } else {
                throw new RuntimeException("Unknown command line argument: " + argv[i]);
            }
        }
        if (abiList == null) {
            //异常情况
            throw new RuntimeException("No ABI list supplied.");
        }
        zygoteServer.registerServerSocketFromEnv(socketName); //注册socket
        if (!enableLazyPreload) {
            //启动预加载
            ....
            preload(bootTimingsTraceLog);
            ....
        } else {
            //降低进程优先级
            Zygote.resetNicePriority();
        }
        ...
        gcAndFinalize(); //进行一次gc
        ...
        //初始化native访问安全
        Zygote.nativeSecurityInit();
        //卸载storage空间
        Zygote.nativeUnmountStorageOnInit();
        //通知虚拟机可以创建线程了
        ZygoteHooks.stopZygoteNoThreadCreation();
        //启动系统服务
        if (startSystemServer) {
            Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
            //上文提到过fork进程会有两次回调,这里如果r==null则是Zygote进程,否则是SystemServer进程
            if (r != null) {
                r.run();
                return;//SystemServer进程就直接返回了
            }
        }
        //父进程中会执行到这里,轮询Socket发的命令
        caller = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with exception", ex);
        throw ex;
    } finally {
        zygoteServer.closeServerSocket();//子进程断开与Socket的连接
    }
    //执行子进程
    if (caller != null) {
        caller.run();
    }
}

main方法总结:
整体流程主要涉及获取c++调用层传递过来的参数,包括是否启动系统服务、是否预加载系统资源、获取abi和绑定socket名称。在进程创建开始前禁止创建新的线程,做好初始化之后才允许创建新的线程,最后绑定Socket进行轮询。

preload方法

static void preload(TimingsTraceLog bootTimingsTraceLog) {
    ....
    preloadClasses(); //Class.forName方式预加载Class
    ....
    preloadResources();//预加载系统资源resource,如drawable、color
    ....
    preloadOpenGL(); //加载openGL
    ....
    preloadSharedLibraries(); //System.loadLibrary方式加载一些公共库
    preloadTextResources();  //加载Text资源、字体等
    WebViewFactory.prepareWebViewInZygote(); //WebViewFactory在Zygote初始化
    endIcuCachePinning();
    warmUpJcaProviders();
    sPreloadComplete = true; //预加载完成标记
}

preload方法总结:

preloadClassess 将framework.jar里的preloaded-classes 定义的所有class load到内存里,preloaded-classes 编译Android后可以在framework/base下找到。而preloadResources 将系统的Resource(不是在用户apk里定义的resource)load到内存。资源preload到Zygoted的进程地址空间, 所有fork的子进程将共享这份空间而无需重新load, 这大大减少了应用程序的启动时间,但反过来增加了系统的启动时间。通过对preload 类和资源数目进行调整可以加快系统启动。Preload也是Android启动最耗时的部分之一。

forkSystemServer方法

private static Runnable forkSystemServer(String abiList, String socketName,
        ZygoteServer zygoteServer) {
    ... 省略一些参数
    //启动SystemServer命令
    String args[] = {
        "--setuid=1000",
        "--setgid=1000",
        "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
        "--capabilities=" + capabilities + "," + capabilities,
        "--nice-name=system_server",
        "--runtime-args",
        "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
        "com.android.server.SystemServer", //这个参数代表着系统进程fork成功后回执行SystemServer中的main方法
    };
    //处理参数信息
    ....
    int pid;
    try {
        ....
        处理参数信息
        ....
        //fork系统服务
        pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.runtimeFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }
    if (pid == 0) {
        //这里是子进程的回调
        if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }
        zygoteServer.closeServerSocket(); //子进程并不需要保持zygote socket的连接了,所以进行断开操作
        return handleSystemServerProcess(parsedArgs); //开始处理系统服务
    }
    return null;
}

handleSystemServerProcess方法最终的核心是调用ZygoteInit.zygoteInit

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
    //初始化log
    RuntimeInit.redirectLogStreams();
    //初始化log打印和线程崩溃回调
    RuntimeInit.commonInit();
    ZygoteInit.nativeZygoteInit();
    //RuntimeInit类去执行到SystemServer的main方法
    return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}

protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
        ClassLoader classLoader) {
    ....
    return findStaticMain(args.startClass, args.startArgs, classLoader);
}

protected static Runnable findStaticMain(String className, String[] argv,
        ClassLoader classLoader) {
    Class cl;
    ....
        cl = Class.forName(className, true, classLoader);
    ....
    Method m;
    ....
        m = cl.getMethod("main", new Class[] { String[].class });
    ....
    return new MethodAndArgsCaller(m, argv); //执行到SystemServer的main方法
}

ZygoteServer

ZygoteServer是Zygote用来与Socket建立连接的,主要涉及registerServerSocketFromEnvrunSelectLoop

registerServerSocketFromEnv方法

void registerServerSocketFromEnv(String socketName) {
    if (mServerSocket == null) {
        int fileDesc;
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;//socket全名
        try {
            String env = System.getenv(fullSocketName);
            fileDesc = Integer.parseInt(env); //socket句柄(int值)
        } catch (RuntimeException ex) {
            throw new RuntimeException(fullSocketName + " unset or invalid", ex);
        }
        try {
            FileDescriptor fd = new FileDescriptor();
            fd.setInt$(fileDesc);
            mServerSocket = new LocalServerSocket(fd);//通过LocalServerSocket进行监听
            mCloseSocketFd = true;
        } catch (IOException ex) {
            throw new RuntimeException(
                    "Error binding to local socket '" + fileDesc + "'", ex);
        }
    }
}

runSelectLoop

Runnable runSelectLoop(String abiList) {
    ArrayList fds = new ArrayList();
    ArrayList peers = new ArrayList();
    fds.add(mServerSocket.getFileDescriptor());
    peers.add(null);
    //开启一个死循环从socket中获取数据
    while (true) {
        StructPollfd[] pollFds = new StructPollfd[fds.size()];
        for (int i = 0; i < pollFds.length; ++i) {
            pollFds[i] = new StructPollfd();
            pollFds[i].fd = fds.get(i);
            pollFds[i].events = (short) POLLIN;
        }
        try {
            Os.poll(pollFds, -1);//系统的poll机制
        } catch (ErrnoException ex) {
            throw new RuntimeException("poll failed", ex);
        }
        for (int i = pollFds.length - 1; i >= 0; --i) {
            if ((pollFds[i].revents & POLLIN) == 0) {
                continue;
            }

            if (i == 0) {
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {
                try {
                    ZygoteConnection connection = peers.get(i);//每一次循环都是取出来ZygoteConnection
                    final Runnable command = connection.processOneCommand(this); //processOneCommand方法fork出进程,App的进程就是通过AMS向Zygote发送socket消息,通过这里经过ZygoteConnection执行的
                    if (mIsForkChild) {
                        if (command == null) {
                            throw new IllegalStateException("command == null");
                        }

                        return command;
                    } else {
                        ....
                        if (connection.isClosedByPeer()) {
                            connection.closeSocket();
                            peers.remove(i);
                            fds.remove(i);
                        }
                    }
                    ....
}

runSelectLoop方法通过轮询的方式不断从socket中取出消息,来完成进程的创建。AMS通过向Zygote绑定的socket中发送消息来请求Zygote来fork出app的进程。

zygote启动过程的2个细节:

1)zygote在fork时要保证单线程, 因为不管父进程有多少个线程,子进程创建时只有一个线程,多的线程就不见了,会导致很多奇怪的问题:子进程死锁,状态不一致,所以不如直接,fork子进程时,停掉其他线程,创建完了子进程再重启那些线程,zygote就是这么做的,它不只有主线程,还有与虚拟机相关的守护线程。
2)zygote的IPC没有采用binder机制, 它采用的是socket,所以应用的binder机制不是从zygote继承的,而是AP进程创建后自己启动的binder机。

1.孵化AP问啥不交给systemServer,而是专门设计一个zygote?
应用在启动的时候,需要做很多准备工作,如启动虚拟机,加载各个类系统资源,都非常耗时, 如果zygote把init工作做好,再在fork时共享给子进程,那效率就非常高。 这就是zygote存在的价值,systemServer不能做,因为它跑了一堆系统服务,他们不能被继承AP进程。 而且AP启动时,内存空间除了必要的资源外,最好是干净的,不要继承一堆乱七八糟的东西, 所以,不如给systemServer和AP进程都要用的资源抽出来单独放在一个进程里,这就是zygote进程.

2,zyogte的IPC为什么不用binder?用binder会有问题吗?
不用binder有个原因:
1)如果用了binder,zygote要先启动binder机制,打开binder驱动,获得描述符,mmap进程内存映射,注册binder线程,还要创建一个binder对象注册到serviceManager,另外AMS要想zygote发起创建应用进程请求的话,要先从serviceManager查询zygote的binder对象,再发起binder调用,非常繁琐。 相比之下,zygote和systemserver本就是父子关系,对于简单的消息通信,用管道或者socket非常方便。
2)如果zygote用了binder机制,再fork systemServer,那systemServer就继承了zygote的描述符和映射的内存,这两个进程在binder驱动层就会共用一套数据结构,这肯定是不行的。那还得把旧的描述符关掉,再重新启动一遍binder机制,自找麻烦。

你可能感兴趣的:(Zygote工作流程)