美文网首页
源码分析-Zygote进程启动到Launcher

源码分析-Zygote进程启动到Launcher

作者: 半只温柔 | 来源:发表于2018-01-30 12:16 被阅读0次

    上两篇聊了Launcher之后的流程,现在咱们再看一下之前的流程 --- 也就是Zygote进程启动之后:


    无标题.png

    Zygote, 意为“受精卵”,安卓进程孵化器
    上图可以看出,由linux kernel 的 init (一生万物)进程可以启动Zygote进程,Zygote又启动dalvik,初始化java环境,app需要的资源,系统服务... fork(孵化)桌面Launcher以及各个app进程

    在系统启动脚本system/core/rootdir/init.rc文件中,我们可以看到启动Zygote进程的脚本命令:

    service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server  
        socket zygote stream 666   # zygote需要一个套接字
        onrestart write /sys/android_power/request_state wake  # zygote重启的话,需要执行这个操作
        onrestart write /sys/power/state on  
        onrestart restart media  
        onrestart restart netd  
    

    app_process对应的源码在frameworks/base/cmds/app_process目录下,其入口函数main在文件app_main.cpp中:

    /*
    * 启动zygote的方式为/system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    * 所以 argc == 5
    *      argv里头存的就是这5个参数argv[0]=="/system/bin/app_process" ,argv[1] == "-Xzygote"....
    */
    int main(int argc, char* const argv[])
    {
        ......
        // These are global variables in ProcessState.cpp
        mArgC = argc;
        mArgV = argv;
    
        mArgLen = 0;
        for (int i=0; i<argc; i++) {
            mArgLen += strlen(argv[i]) + 1;
        }
        mArgLen--;
        // 以上代码主要是将参数相关信息保存到全局变量中
    
        AppRuntime runtime;
        const char* argv0 = argv[0];
    
        // Process command line arguments
        // ignore argv[0]
        argc--;
        argv++;
    
        // Everything up to '--' or first non '-' arg goes to the vm
    
        int i = runtime.addVmArguments(argc, argv); // 这个函数会返回1,表示只处理了-Xzytote这一个参数,所谓的处理实际上就是将这个参数添加到了runtime对象的mOptions 变量中。
    
        // Parse runtime arguments.  Stop at first unrecognized option.
        bool zygote = false;
        bool startSystemServer = false;
        bool application = false;
        const char* parentDir = NULL;
        const char* niceName = NULL;
        const char* className = NULL;
        // 进入循环之前 i == 1, argc == 4  argv 指向“-Xzygote” 
        while (i < argc) {
            const char* arg = argv[i++];
            if (!parentDir) {
                parentDir = arg;  // parentDir被赋值为"/system/bin"
            } else if (strcmp(arg, "--zygote") == 0) {  
                zygote = true;
                niceName = "zygote"; // 进程名
            } else if (strcmp(arg, "--start-system-server") == 0) {
                startSystemServer = true;
            } else if (strcmp(arg, "--application") == 0) { // 不走这个分支
                application = true;
            } else if (strncmp(arg, "--nice-name=", 12) == 0) {  // 不走这个分支
                niceName = arg + 12;
            } else {  // 不走这个分支
                className = arg;
                break;
            }
        }
    
        if (niceName && *niceName) {  // 设置进程名
            setArgv0(argv0, niceName);
            set_process_name(niceName);
        }
    
        runtime.mParentDir = parentDir;
    
        if (zygote) { // 走这个分支
            runtime.start("com.android.internal.os.ZygoteInit",
                    startSystemServer ? "start-system-server" : "");
        } else if (className) {
            // Remainder of args get passed to startup class main()
            runtime.mClassName = className;
            runtime.mArgC = argc - i;
            runtime.mArgV = argv + i;
            runtime.start("com.android.internal.os.RuntimeInit",
                    application ? "application" : "tool");
        } else {
            fprintf(stderr, "Error: no class name or --zygote supplied.\n");
            app_usage();
            LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
            return 10;
        }
    }
    

    main函数主要就是创建了runtime实例,并且解析参数,然后调用runtime的start函数,接着我们分析AppRuntime的start函数:

    /*
     * Start the Android runtime.  This involves starting the virtual machine
     * and calling the "static void main(String[] args)" method in the class
     * named by "className".
     *
     * Passes the main function two arguments, the class name and the specified
     * options string.
     */
     // 首先我们明确下传进来的参数  className == "com.android.internal.os.ZygoteInit"  options == "start-system-server"
    void AndroidRuntime::start(const char* className, const char* options)
    {
        ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
                className != NULL ? className : "(unknown)");
    
        /*
         * 'startSystemServer == true' means runtime is obsolete and not run from
         * init.rc anymore, so we print out the boot start event here.
         */
        if (strcmp(options, "start-system-server") == 0) {
            /* track our progress through the boot sequence */
            const int LOG_BOOT_PROGRESS_START = 3000;
            LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
                           ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
        }
    
        const char* rootDir = getenv("ANDROID_ROOT");
        if (rootDir == NULL) {
            rootDir = "/system";
            if (!hasDir("/system")) {
                LOG_FATAL("No root directory specified, and /android does not exist.");
                return;
            }
            setenv("ANDROID_ROOT", rootDir, 1);  //配置ANDROID_ROOT环境变量
        }
    
        //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
        //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
        //1:调用startVm函数创建虚拟机;
        /* start the virtual machine */
        JniInvocation jni_invocation;
        jni_invocation.Init(NULL);
        JNIEnv* env;
        if (startVm(&mJavaVM, &env) != 0) { // 创建虚拟机
            return;
        }
        onVmCreated(env);
        //2:调用startReg函数注册Android Natvie函数;
        /*
         * Register android functions.
         */
        if (startReg(env) < 0) {
            ALOGE("Unable to register all android natives\n");
            return;
        }
    
        /*
         * We want to call main() with a String array with arguments in it.
         * At present we have two arguments, the class name and an option string.
         * Create an array to hold them.
         */
        jclass stringClass;
        jobjectArray strArray;
        jstring classNameStr;
        jstring optionsStr;
    
        stringClass = env->FindClass("java/lang/String");
        assert(stringClass != NULL);
        strArray = env->NewObjectArray(2, stringClass, NULL);
        assert(strArray != NULL);
        classNameStr = env->NewStringUTF(className);
        assert(classNameStr != NULL);
        env->SetObjectArrayElement(strArray, 0, classNameStr);
        optionsStr = env->NewStringUTF(options);
        env->SetObjectArrayElement(strArray, 1, optionsStr);
    
        /*
         * Start VM.  This thread becomes the main thread of the VM, and will
         * not return until the VM exits.
         */
        char* slashClassName = toSlashClassName(className);
        jclass startClass = env->FindClass(slashClassName);
        if (startClass == NULL) {
            ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
            /* keep going */
        } else {
            jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
                "([Ljava/lang/String;)V");
            if (startMeth == NULL) {
                ALOGE("JavaVM unable to find main() in '%s'\n", className);
                /* keep going */
            } else {
                //3:让虚拟机去执行com.android.internal.os.ZygoteInit的main函数。
                /* 调用com.android.internal.os.ZygoteInit的main函数,strArray是参数,数组里面有两个元素,
                className == "com.android.internal.os.ZygoteInit"  options == "start-system-server" */
                env->CallStaticVoidMethod(startClass, startMeth, strArray);
    
    #if 0
                if (env->ExceptionCheck())
                    threadExitUncaughtException(env);
    #endif
            }
        }
        free(slashClassName);
    
        ALOGD("Shutting down VM\n");
        if (mJavaVM->DetachCurrentThread() != JNI_OK)
            ALOGW("Warning: unable to detach main thread\n");
        if (mJavaVM->DestroyJavaVM() != 0)
            ALOGW("Warning: VM did not shut down cleanly\n");
    }
    

    start函数主要做了以下几件事情:
    1:调用startVm函数创建虚拟机;
    2:调用startReg函数注册Android Natvie函数;
    3:让虚拟机去执行com.android.internal.os.ZygoteInit的main函数。

    public static void main(String argv[]) {
            try {
                // Start profiling the zygote initialization.
                SamplingProfilerIntegration.start();
                // 1、创建一个套接字,用于监听ams发过来的fork请求
                registerZygoteSocket(); 
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                    SystemClock.uptimeMillis());
                preload(); 
                // 2、加载classes 和resources, 后面会详细分析
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                    SystemClock.uptimeMillis());
    
                // Finish profiling the zygote initialization.
                SamplingProfilerIntegration.writeZygoteSnapshot();
    
                // Do an initial gc to clean up after startup
                gc();
    
                // If requested, start system server directly from Zygote
                if (argv.length != 2) {
                    throw new RuntimeException(argv[0] + USAGE_STRING);
                }
    
                if (argv[1].equals("start-system-server")) {
                    //3、 创建system server进程,ams wms pms等常见service都在该进程里面
                    startSystemServer(); 
                } else if (!argv[1].equals("")) {
                    throw new RuntimeException(argv[0] + USAGE_STRING);
                }
    
                Log.i(TAG, "Accepting command socket connections");
    
                if (ZYGOTE_FORK_MODE) {
                    runForkMode();
                } else {
                    // 4、进入循环监听模式,监听外来请求
                    runSelectLoopMode(); 
                }
    
                closeServerSocket();
            } catch (MethodAndArgsCaller caller) {
                caller.run();
            } catch (RuntimeException ex) {
                Log.e(TAG, "Zygote died with exception", ex);
                closeServerSocket();
                throw ex;
            }
        }
    

    com.android.internal.os.ZygoteInit的main函数主要做了四件事情:

    1:调用registerZygoteSocket()创建一个套接字,用于监听ams发过来的fork请求,如下:
    private static void registerZygoteSocket(String socketName) {
        if (sServerSocket == null) {
            int fileDesc;
            //此处的socket name,就是zygote
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {
                //记得么?在init.zygote.rc被加载时,就会创建一个名为zygote的socket
                String env = System.getenv(fullSocketName);
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
            }
    
            try {
                FileDescriptor fd = new FileDescriptor();
                //获取zygote socket的文件描述符
                fd.setInt$(fileDesc);
                //将zygote socket包装成一个server socket
                sServerSocket = new LocalServerSocket(fd);
            } catch (IOException ex) {
                throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }
    

    2:调用preload()预加载classes 和resources,如下;

    static void preload() {
        Log.d(TAG, "begin preload");
        //读取文件framework/base/preloaded-classes,然后通过反射加载对应的类
        //需要加载数千个类,启动慢的原因之一
        preloadClasses();
        //负载加载一些常用的系统资源
        preloadResources();
        //图形相关的
        preloadOpenGL();
        //一些必要库
        preloadSharedLibraries();
        //好像是语言相关的字符信息
        preloadTextResources();
        // Ask the WebViewFactory to do any initialization that must run in the zygote process, for memory sharing purposes.
        WebViewFactory.prepareWebViewInZygote();
        Log.d(TAG, "end preload");
    }
    

    3:调用startSystemServer()创建system server进程,ams wms pms等常见service都在该进程里面,如下;

    private static boolean startSystemServer(String abiList, String socketName) {
        //准备capabilities参数
        ........
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=.........",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;
    
        int pid;
    
        try {
            //将上面准备的参数,按照ZygoteConnection的风格进行封装
            parsedArgs = new ZygoteConnection.Arguments(args);
            ...........
    
            //通过fork"分裂"出system server
            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.debugFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }
    
        if (pid == 0) {
            ............
            //pid = 0, 在进程system server中
            //system server进程处理自己的工作
            handleSystemServerProcess(parsedArgs);
        }
    
        return true;
    }
    

    4:调用runSelectLoopMode()进入循环监听模式,监听外来请求,如下。

    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    
        //首先将server socket加入到fds
        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);
    
        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);
            } 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;
                }
                //server socket最先加入fds, 因此这里是server socket收到数据
                if (i == 0) {
                    //收到新的建立通信的请求,建立通信连接
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    //加入到peers和fds
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                 } else {
                    //其它通信连接收到数据,runOnce执行对应命令
                    boolean done = peers.get(i).runOnce();
                    if (done) {
                        //对应通信连接不再需要执行其它命令,关闭并移除
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }
    

    从上面代码可知,初始时,fds中仅有server socket,因此当有数据到来时,将执行i ==0 的部分。
    此时,显然是需要创建新的通信连接,因此acceptCommandPeer将被调用。

    private static ZygoteConnection acceptCommandPeer(String abiList) {
        try {
            return new ZygoteConnection(sServerSocket.accept(), abiList);
        } catch (IOException ex) {
            throw new RuntimeException("IOException during accept()", ex);
        }
    }
    总结
    1:acceptCommandPeer封装了socket的accpet函数。于是我们知道,对应的新的连接,zygote将会创建出一个新的socket与其通信,并将该socket加入到fds中。因此,一旦通信连接建立后,fds中将会包含有多个socket。
    2:当poll监听到这一组sockets上有数据到来时,就会从阻塞中恢复。于是,我们需要判断到底是哪个socket收到了数据。
    3:在runSelectLoop中采用倒序的方式轮询,由于server socket第一个被加入到fds,因此最后轮询到的socket才需要处理新建连接的操作;其它socket收到数据时,仅需要调用zygoteConnection的runonce函数执行数据对应的操作。
    4:若一个连接处理完所有对应消息后,该连接对应的socket和连接等将被移除。
    

    那么从 system server 到 ActivityManager 到 Launcher 又是如何沟通的呢,也就是第一篇提到的
    AMS.startProcessLocked()-->Process.start()-->zygoteSendArgsAndGetResult()-->ZygoteInit.invokeStaticMain(cloader, className, mainArgs)(ActivityThread.main)
    system server,具体的过程在介绍system server时再分析

    相关文章

      网友评论

          本文标题:源码分析-Zygote进程启动到Launcher

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