Zygote简析

 Zygote是什么?



Zygote 【n.<生物>合子,受精卵】
在Android系统中,它是一个非常重要的进程,所有的APP都是由Zygote来启动的。可以认为Zygote是所有APP的始祖。


通过ps命令可以看到以下信息:


    root      255   1     473392 18716 ffffffff 40076720 S zygote


从上面可以得到一些信息:


* Zygote是具备root权限的
* Zygote的parent pid是1,也就是说Zygote是直接由init启动的




由此可见,Zygote应该是个非常关键的进程。


如何找到Zygote的源代码?



如果我们从Framework里面去找,是断然找不到名为Zygote的LOCAL_MODULE的。那么Zygote到底是怎么来的呢?


我们知道linux系统有个非常关键的配置文件: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


第一句定义了一个名为“zygote”的service,这个service的二进制程序文件是/system/bin/app_process。然后还有一些参数


由此可见,zygote其实就是/system/bin/app_process的别名,启动zygote其实就是启动的/system/bin/app_process。


然后再在framework里面去着app_process,果然有这个LOCAL_MODULE,路径是:frameworks/base/cmds/app_process


 Zygote源码分析



现在我们就来看看zygote也就是app_process的源码吧:


源码文件是: frameworks/base/cmds/app_process/app_main.cpp


这个文件非常简单,里面主要有一个main函数以及AppRuntime类的定义,先来看看main函数:


 
int main(int argc, const 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);
    
    // 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;
    while (i < argc) {
        const char* arg = argv[i++];
        if (!parentDir) {
            parentDir = arg;
        } 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;
    }
  }





上面代码中有一段是解析参数的,主要读取了 --zygote、--start-system-server、--application、--nice-name=等参数


而在init.rc里面定义的是:service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server


也就是说,经过解析,可以得到如下初始化变量:


* parentDir 二进制文件路径
* zygote == true
* niceName == zygote
* startSystemServer == true
* application == false


因为这里zygote == true,所以会走到如下代码:


    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit",
                startSystemServer ? "start-system-server" : "");
    } 


这里会调用runtime的start方法,而runtime是什么呢?


    AppRuntime runtime;


runtime即使AppRuntime的一个实例,AppRuntime定义代码如下:


  class AppRuntime : public AndroidRuntime
 
也就是说AppRuntime是AndroidRuntime的一个派生类。


 AndroidRuntime 分析



源码文件:frameworks/base/core/jni/AndroidRuntime.cpp


我们来看看它的AndroidRuntime::start函数的代码,接下来会分段分析:


    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 即android系统的根目录,默认值是 /system


    /* start the virtual machine */
    JNIEnv* env;
    if (startVm(&mJavaVM, &env) != 0) {
        return;
    }
    onVmCreated(env);



启动java虚拟机


    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }



注册Android函数,很多java层的函数其实都是通过JNI注册的native函数




   
/*
     * 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 {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
    
        }
    }
    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");


    


上面这段就是通过className找到对应的类(注意将类名从类似com.xxx.yyy转换成com/xxx/yyy),然后调用类中的静态函数main。这样流程就又回到了java层,类的main函数被执行。




Zygote之java层分析



刚才在app_process里面有启动java层zygote的代码: 


    runtime.start("com.android.internal.os.ZygoteInit",
        startSystemServer ? "start-system-server" : "");


由上面的分析可知,这其实就是调用了com.android.internal.os.ZygoteInit里面的main函数,那我们就来看看com.android.internal.os.ZygoteInit源码。






   
public static void main(String argv[]) {
        try {
            /// M: Added for BOOTPROF
            MTPROF_DISABLE = "1".equals(SystemProperties.get("ro.mtprof.disable"));
            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();
    
            registerZygoteSocket();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());
            /// M: Added for BOOTPROF
            addBootEvent(new String("Zygote:Preload Start"));
            preload();
            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);
            }
            /// M: Added for BOOTPROF
            addBootEvent(new String("Zygote:Preload End"));
    
            if (argv[1].equals("start-system-server")) {
                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 {
                runSelectLoopMode();
            }
    
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }



Zygote的main函数确实很简单,就上面这么点儿代码。关键流程可以概括为:


registerZygoteSocket() ---> preload() ---> startSystemServer() ---> runForkMode()/runSelectLoopMode() ---> closeServerSocket()


* registerZygoteSocket 注册local socket
* preload 预加载各个类和资源
* startSystemServer 启动systemserver
* runForkMode/runSelectLoopMode 以fork或者selectloop模式去监听和处理客户端请求
* closeServerSocket 关闭local socket (正常情况下,程序会一直在上一步循环,走不到这里)


------------
Zygote的main函数主要做了两件事: 1. 启动systemserver 2. 监听和处理客户端请求
------------


那么zygote的客户端是什么呢?

zygote启动APP过程分析





为了简单地分析启动过程,我们不去追寻请求的来源,仅仅从zygote这一段来分析。


在上面的分析中,可以知道runForkMode/runSelectLoopMode使用来处理客户端请求的,那么就从它们入手吧:


* runForkMode


   
private static void runForkMode() throws MethodAndArgsCaller {
        while (true) {
            ZygoteConnection peer = acceptCommandPeer();
    
            int pid;
    
            pid = Zygote.fork();
    
            if (pid == 0) {
                // The child process should handle the peer requests
    
                // The child does not accept any more connections
                try {
                    sServerSocket.close();
                } catch (IOException ex) {
                    Log.e(TAG, "Zygote Child: error closing sockets", ex);
                } finally {
                    sServerSocket = null;
                }
    
                peer.run();
                break;
            } else if (pid > 0) {
                peer.closeSocket();
            } else {
                throw new RuntimeException("Error invoking fork()");
            }
        }
    }




runForkMode函数里面就一个while循环,ZygoteConnection peer = acceptCommandPeer(); 从字面上可以猜测是接收客户端请求的:
    
    private static ZygoteConnection acceptCommandPeer() {
        try {
            return new ZygoteConnection(sServerSocket.accept());
        } catch (IOException ex) {
            throw new RuntimeException(
                    "IOException during accept()", ex);
        }
    }




果然,是accept一个socket连接,然后生成ZygoteConnection对象返回。


然后在runForkMode函数里,得到一个ZygoteConnection对象之后就fork一个子进程,在子进程里面调用peer.run(),也就是ZygoteConnection的run函数。


   
void run() throws ZygoteInit.MethodAndArgsCaller {
    
        int loopCount = ZygoteInit.GC_LOOP_COUNT;
    
        while (true) {
            /*
             * Call gc() before we block in readArgumentList().
             * It's work that has to be done anyway, and it's better
             * to avoid making every child do it.  It will also
             * madvise() any free memory as a side-effect.
             *
             * Don't call it every time, because walking the entire
             * heap is a lot of overhead to free a few hundred bytes.
             */
            if (loopCount <= 0) {
                ZygoteInit.gc();
                loopCount = ZygoteInit.GC_LOOP_COUNT;
            } else {
                loopCount--;
            }
    
            if (runOnce()) {
                break;
            }
        }
    }




run函数里就是不停的执行runOnce函数,直到runOnce返回true为止。中间会间断地执行内存回收。


   
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
    
        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;
    
        try {
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            Log.w(TAG, "IOException on command socket " + ex.getMessage());
            closeSocket();
            return true;
        }
    
        if (args == null) {
            // EOF reached.
            closeSocket();
            return true;
        }
    
        /** the stderr of the most recent request, if avail */
        PrintStream newStderr = null;
    
        if (descriptors != null && descriptors.length >= 3) {
            newStderr = new PrintStream(
                    new FileOutputStream(descriptors[2]));
        }
    
        int pid = -1;
        FileDescriptor childPipeFd = null;
        FileDescriptor serverPipeFd = null;
    
        try {
            parsedArgs = new Arguments(args);
    
            applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyCapabilitiesSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);
    
            applyDebuggerSystemProperty(parsedArgs);
            applyInvokeWithSystemProperty(parsedArgs);
    
            int[][] rlimits = null;
    
            if (parsedArgs.rlimits != null) {
                rlimits = parsedArgs.rlimits.toArray(intArray2d);
            }
    
            if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) {
                FileDescriptor[] pipeFds = Libcore.os.pipe();
                childPipeFd = pipeFds[1];
                serverPipeFd = pipeFds[0];
                ZygoteInit.setCloseOnExec(serverPipeFd, true);
            }
    
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName);
        } catch (IOException ex) {
            logAndPrintError(newStderr, "Exception creating pipe", ex);
        } catch (ErrnoException ex) {
            logAndPrintError(newStderr, "Exception creating pipe", ex);
        } catch (IllegalArgumentException ex) {
            logAndPrintError(newStderr, "Invalid zygote arguments", ex);
        } catch (ZygoteSecurityException ex) {
            logAndPrintError(newStderr,
                    "Zygote security policy prevents request: ", ex);
        }
    
        try {
            if (pid == 0) {
                // in child
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
    
                // should never get here, the child is expected to either
                // throw ZygoteInit.MethodAndArgsCaller or exec().
                return true;
            } else {
                // in parent...pid of < 0 means failure
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }




runOnce的函数看似很复杂,但是仍然可以简单地归纳成以下几个关键流程:
------
readArgumentList() ---> Zygote.forkAndSpecialize() ---> handleChildProc()/handleParentProc()


读取参数            --->  fork子进程                  ---> 处理子进程/父进程
------


*handleChildProc


  private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws ZygoteInit.MethodAndArgsCaller 




handleChildProc函数中有以下代码:


            String className;
            try {
                className = parsedArgs.remainingArgs[0];
            } catch (ArrayIndexOutOfBoundsException ex) {
                logAndPrintError(newStderr,
                        "Missing required class name argument", null);
                return;
            }
    
            String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];
            System.arraycopy(parsedArgs.remainingArgs, 1,
                    mainArgs, 0, mainArgs.length);
    
            if (parsedArgs.invokeWith != null) {
                WrapperInit.execStandalone(parsedArgs.invokeWith,
                        parsedArgs.classpath, className, mainArgs);
            } else {
                ClassLoader cloader;
                if (parsedArgs.classpath != null) {
                    cloader = new PathClassLoader(parsedArgs.classpath,
                            ClassLoader.getSystemClassLoader());
                } else {
                    cloader = ClassLoader.getSystemClassLoader();
                }
    
                try {
                    ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
                } catch (RuntimeException ex) {
                    logAndPrintError(newStderr, "Error starting.", ex);
                }
            }




上面的代码就是通过参数中指定的类名来加载类,然后在通过ZygoteInit.invokeStaticMain(cloader, className, mainArgs);来调用类的main函数


这样,一个java程序就被启动起来了,它所在的进程空间就是通过Zygote.forkAndSpecialize产生的子进程。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值