Android -- 系统进程Zygote的启动分析

 

我们知道,Android系统是基于Linux内核的。Linux中,所有的进程都是由init进程创建出来的,即所有的进程都是直接或间接被init进程fork产生的。Android进程的孵化器Zygote同样如此,它在系统启动过程中,被init进程创建出来。Android系统启动时,会解析init.rc初始化文件,我们先看init.rc中对Zygote配置文件的处理:

import /init.${ro.zygote}.rc

可以看到,此处配置文件的导入,是由ro.zygote属性控制的,由此来引入不同的文件。出现这种情况的原因是,Android 5.0以后,Android开始支持64位编译,Zygote进程也随之引入了32/64位的区别。所以,这里通过ro.zygote属性来控制启动不同版本的Zygote进程。
ro.zygote属性会有四种不同的值:

  • zygote32:代表32位模式
  • zygote32_64:代表32模式为主,64位模式为辅
  • zygote64:代表64位模式
  • zygote64_32:代表64模式为主,32位模式为辅

在init.rc同级目录下一共4个和Zygote进程有关的rc配置文件:

双模式下,Zygote的配置文件下会有两个服务声明,这里以init.zygote64_32.rc为例:

service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote    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/tasksservice zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary    class main    socket zygote_secondary stream 660 root system    onrestart restart zygote    writepid /dev/cpuset/foreground/tasks

这两个服务声明最大的区别就是对应的可执行文件不一样。我们分析还是以纯32位模式为例,来看Zygote进程的启动过程。
纯32位模式下启动Zygote进程的命令如下:

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

关键字service告诉我们要创建一个名为Zygote的进程,并通过应用程序/system/bin/app_process来启动它;之后的内容是此次启动传入的参数:

  1. -Xzygote:jvm使用的参数
  2. /system/bin:一个未被使用的父目录
  3. --zygote、--start--system--server:启动Zygote进程要使用的参数
  4. class main:将Zygote声明为主要服务,用于后续class_start main启动服务用
  5. socket xxx:表示需要为此服务创建一个socket
  6. onrestart xxx:当Zygote服务重启时,需要执行的命令

socket关键字说明该进程需要创建一个套接字资源用于进程间通信,类型是unix domain socket,权限设置为660。onrestart关键字描述的都是该进程重启时需要执行的命令操作。
这里再介绍下app_process启动参数的格式:

  • 虚拟机参数:以"-"开头。启动虚拟机时传递给虚拟机使用
  • 运行目录:程序的运行目录,通常是/system/bin
  • 参数:以"--"开头。"--zygote"表示要启动zygote进程。参数"--application"表示以普通进程的方式执行Java代码
  • Java类:将要执行的Java类,它必须有main()方法;使用"--zygote"时,不会执行这个类,而是固定执行ZygoteInit类

在Init进程解析init.rc时,会解析并启动这个服务,最后通过系统调用exec()去执行zygote进程对应的应用程序。

它对应的文件是/frameworks/base/cmds/app_process/app_main.cpp;直接看它的main()函数:

int main(int argc, char* const argv[]){    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {        // Older kernels don't understand PR_SET_NO_NEW_PRIVS and return        // EINVAL. Don't die on such kernels.        if (errno != EINVAL) {            LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));            return 12;        }    }    //AppRuntime是AndroidRuntime的子类,这里初始化runtime对象时Androidruntime中的gCurRuntime变量会被初始化为AppRuntime对象:runtime    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));    // Process command line arguments    // ignore argv[0]    argc--;    argv++;    // Everything up to '--' or first non '-' arg goes to the vm.    //    // The first argument after the VM args is the "parent dir", which    // is currently unused.    //    // After the parent dir, we expect one or more the following internal    // arguments :    //    // --zygote : Start in zygote mode    // --start-system-server : Start the system server.    // --application : Start in application (stand alone, non zygote) mode.    // --nice-name : The nice name for this process.    //    // For non zygote starts, these arguments will be followed by    // the main class name. All remaining arguments are passed to    // the main method of this class.    //    // For zygote starts, all remaining arguments are passed to the zygote.    // main function.    //    // Note that we must copy argument string values since we will rewrite the    // entire argument block when we apply the nice name to argv0.    int i;    for (i = 0; i < argc; i++) {        if (argv[i][0] != '-') {            break;        }        if (argv[i][1] == '-' && argv[i][2] == 0) {            ++i; // Skip --.            break;        }        runtime.addOption(strdup(argv[i]));    }    // Parse runtime arguments.  Stop at first unrecognized option.    bool zygote = false;    bool startSystemServer = false;    bool application = false;    String8 niceName;    String8 className;    ++i;  // Skip unused "parent dir" argument.    while (i < argc) {//忽略第一个参数:-Xzygote        const char* arg = argv[i++];        if (strcmp(arg, "--zygote") == 0) { //由参数列表可知,该项成立            zygote = true;            niceName = ZYGOTE_NICE_NAME;        } 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.setTo(arg + 12);        } else if (strncmp(arg, "--", 2) != 0) {            className.setTo(arg);            break;        } else {            --i;            break;        }    }    Vector args;//启动Zygote进程时使用的参数列表    if (!className.isEmpty()) {//非Zygote模式        // We're not in zygote mode, the only argument we need to pass        // to RuntimeInit is the application argument.        //        // The Remainder of args get passed to startup class main(). Make        // copies of them before we overwrite them with the process name.        args.add(application ? String8("application") : String8("tool"));        runtime.setClassNameAndArgs(className, argc - i, argv + i);//如果不是zygote模式,则把要启动的Java类的名字保存到mClassName字段中    } else {//Zygote模式        // We're in zygote mode.        maybeCreateDalvikCache();        if (startSystemServer) {            args.add(String8("start-system-server"));//添加参数        }        char prop[PROP_VALUE_MAX];        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {            LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",                ABI_LIST_PROPERTY);            return 11;        }        String8 abiFlag("--abi-list=");        abiFlag.append(prop);        args.add(abiFlag);//添加参数        // In zygote mode, pass all remaining arguments to the zygote        // main() method.        for (; i < argc; ++i) {            args.add(String8(argv[i]));//添加剩余的参数        }    }    if (!niceName.isEmpty()) {//设置进程名        runtime.setArgv0(niceName.string());        set_process_name(niceName.string());    }    if (zygote) {//zygote为TRUE        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);//附带参数列表,在Zygote模式下,同过AndroidRuntime::start()启动Zygote进程    } else if (className) {        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);    } 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;    }}

首先我们创建了一个AppRuntime实例runtime,它是AndroidRuntime的子类,重写了一些AndroidRuntime的方法。
app_process除了能启动Zygote进程外,还能启动某个系统的Java类(非zygote模式下)。我们经常使用的"am"命令就是通过app_process实现的。
runtime.start()实际是调用父类的同名方法AndroidRuntime::start()函数,分析它是怎么启动ZygoteInit的:

/* * 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. */void AndroidRuntime::start(const char* className, const Vector& options, bool zygote){    ALOGD(">>>>>> START %s uid %d <<<<<<\n",            className != NULL ? className : "(unknown)", getuid());    static const String8 startSystemServer("start-system-server");    /*     * 'startSystemServer == true' means runtime is obsolete and not run from     * init.rc anymore, so we print out the boot start event here.     */    for (size_t i = 0; i < options.size(); ++i) {        if (options[i] == startSystemServer) {           /* 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)));        }    }    //获取系统根目录,缺省是/system,如果没有/system目录,Zygote进程就会终止。系统目录是在Init进程中创建的    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);    }    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");    //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);    /* start the virtual machine */    JniInvocation jni_invocation;    jni_invocation.Init(NULL);    JNIEnv* env;    if (startVm(&mJavaVM, &env, zygote) != 0) {//1、启动虚拟机        return;    }    onVmCreated(env);    /*     * Register android functions.     */    if (startReg(env) < 0) { //2、注册所需的JNI函数        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;    stringClass = env->FindClass("java/lang/String");    assert(stringClass != NULL);    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);    assert(strArray != NULL);    classNameStr = env->NewStringUTF(className);    assert(classNameStr != NULL);    env->SetObjectArrayElement(strArray, 0, classNameStr);    for (size_t i = 0; i < options.size(); ++i) {        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());        assert(optionsStr != NULL);        env->SetObjectArrayElement(strArray, i + 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);//com.android.internal.os.ZygoteInit    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");//通过JNI获取com.android.internal.os.ZygoteInit类的main()方法的jmethodID值        if (startMeth == NULL) {            ALOGE("JavaVM unable to find main() in '%s'\n", className);            /* keep going */        } else {            env->CallStaticVoidMethod(startClass, startMeth, strArray);//通过JNI调用com.android.internal.os.ZygoteInit类的main()方法,进入Java层代码#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");}

AndroidRuntime是Android底层一个很重要的类,它负责启动JVM和Java类。AndroidRuntime在一个进程中只会有一个实例,在构造时,它的实例会保存在全局变量gCurRuntime中。
在start()函数中首先会获取系统根目录,然后调用startVMm()启动虚拟机。onVmCreated()函数在zygote模式下,并没有实际用处,但我们还是有必要看下它的处理,该函数定义在AppRuntime中:

    virtual void onVmCreated(JNIEnv* env)    {        if (mClassName.isEmpty()) {//zygote模式下,mClassName为空,直接return            return; // Zygote. Nothing to do here.        }        /*         * This is a little awkward because the JNI FindClass call uses the         * class loader associated with the native method we're executing in.         * If called in onStarted (from RuntimeInit.finishInit because we're         * launching "am", for example), FindClass would see that we're calling         * from a boot class' native method, and so wouldn't look for the class         * we're trying to look up in CLASSPATH. Unfortunately it needs to,         * because the "am" classes are not boot classes.         *         * The easiest fix is to call FindClass here, early on before we start         * executing boot class Java code and thereby deny ourselves access to         * non-boot classes.         */        char* slashClassName = toSlashClassName(mClassName.string());//转换Java类的路径字符串        mClass = env->FindClass(slashClassName);//在当前的虚拟机环境下,根据类名查找这个类        if (mClass == NULL) {            ALOGE("ERROR: could not find class '%s'\n", mClassName.string());        }        free(slashClassName);        mClass = reinterpret_cast(env->NewGlobalRef(mClass));    }

如果当前的启动模式不是zygote,那我们在通过app_process启动某个类时会为它指定一个要启动的类。首先,会转换指定的类的路径名,并在当前的虚拟机环境下查找这个类。这表明app_process将要调用的Java类必须是系统类。如果当前的启动模式是zygote,则直接返回。随后调用startReg()注册系统的JNI函数。
最后会将启动类用到的参数封装到strArray数组,并通过JNI的方式在native代码中直接调用ZygoteInit.java的main()函数,处理流程转而进入Java层。

ZygoteInit类是zygote进程的启动类,看它的main()函数:

 public static void main(String argv[]) {        try {            RuntimeInit.enableDdms();            // Start profiling the zygote initialization.            SamplingProfilerIntegration.start();            boolean startSystemServer = false;            String socketName = "zygote";            String abiList = null;            for (int i = 1; i < argv.length; i++) {                if ("start-system-server".equals(argv[i])) {                    startSystemServer = true; //该标志为true                } else if (argv[i].startsWith(ABI_LIST_ARG)) {                    abiList = argv[i].substring(ABI_LIST_ARG.length());                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());//值为zygote                } else {                    throw new RuntimeException("Unknown command line argument: " + argv[i]);                }            }            if (abiList == null) {                throw new RuntimeException("No ABI list supplied.");            }            registerZygoteSocket(socketName); // 1、创建socket,用来与ActivityManagerService进行通信            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,                SystemClock.uptimeMillis());            preload(); // 2、预加载资源文件            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            gcAndFinalize();            // Disable tracing so that forked processes do not inherit stale tracing tags from            // Zygote.            Trace.setTracingEnabled(false);            if (startSystemServer) {                startSystemServer(abiList, socketName); // 3、启动system_server进程            }            Log.i(TAG, "Accepting command socket connections");            runSelectLoop(abiList); // 4、开启一个循环,处理ActivityManagerService创建应用进程的请求            closeServerSocket();  // 程序退出时,清除socket资源        } catch (MethodAndArgsCaller caller) {            caller.run(); // 5、注意        } catch (RuntimeException ex) {            Log.e(TAG, "Zygote died with exception", ex);            closeServerSocket();            throw ex;        }    }

代码中共标记出了5个较为重要的处理过程,下面一一分析。

 

(1)、registerZygoteSocket(socketName)

 

registerZygoteSocket()函数会注册Zygote的socket监听端口,用来接收启动应用程序的消息,查看其代码处理:

 /**     * Registers a server socket for zygote command connections     *     * @throws RuntimeException when open fails     */    private static void registerZygoteSocket(String socketName) {        if (sServerSocket == null) {            int fileDesc;            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;// fullSocketName:ANDROID_SOCKET_zygote            try {                String env = System.getenv(fullSocketName);//获取该环境变量的值,即此socket对应的文件描述符                fileDesc = Integer.parseInt(env);            } catch (RuntimeException ex) {                throw new RuntimeException(fullSocketName + " unset or invalid", ex);            }            try {                FileDescriptor fd = new FileDescriptor();                fd.setInt$(fileDesc);//将该fd保存到descriptor中                sServerSocket = new LocalServerSocket(fd);//用该文件描述符创建一个LocalServerSocket对象,并开始监听该socket            } catch (IOException ex) {                throw new RuntimeException(                        "Error binding to local socket '" + fileDesc + "'", ex);            }        }    }

从系统环境变量中获取到“ANDROID_SOCKET_zygote”这个socket对应的文件描述符,创建LocalServerSocket对象并监听该socket;此时名为zygote的socket就可以接收消息了。细心地人可能发现了,在我们的分析过程中并没有看到socket和Zygote进程的创建过程。其实这个过程在init.cpp解析init.rc文件时,已经处理完成了。下面来看这一部分内容。

系统启动解析init.rc时,每当碰到一个由service关键字声明的服务,就会给他创建一个进程、并初始化该服务相关的资源;这些资源就包括socket的创建。

在init.cpp中,void service_start(struct service *svc, const char *dynamic_args)函数负责启动每个声明的service服务,我们提出一段重要的处理过程:

pid_t pid = fork();//创建一个进程    if (pid == 0) {        struct socketinfo *si;        struct svcenvinfo *ei;        char tmp[32];        int fd, sz;        umask(077);        if (properties_initialized()) {            get_property_workspace(&fd, &sz);            snprintf(tmp, sizeof(tmp), "%d,%d", dup(fd), sz);            add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);        }        for (ei = svc->envvars; ei; ei = ei->next)            add_environment(ei->name, ei->value);        for (si = svc->sockets; si; si = si->next) { //socket创建            int socket_type = (                    !strcmp(si->type, "stream") ? SOCK_STREAM :                        (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));            int s = create_socket(si->name, socket_type,                                  si->perm, si->uid, si->gid, si->socketcon ?: scon);            if (s >= 0) {                publish_socket(si->name, s);//socket发布            }        }       ...    }

当系统为每个service通过调用fork()创建进程时,如果发现需要创建socket,它就会通过调用create_socket()创建一个socket:

/* * create_socket - creates a Unix domain socket in ANDROID_SOCKET_DIR * ("/dev/socket") as dictated in init.rc. This socket is inherited by the * daemon. We communicate the file descriptor's value via the environment * variable ANDROID_SOCKET_ENV_PREFIX ("ANDROID_SOCKET_foo"). */int create_socket(const char *name, int type, mode_t perm, uid_t uid,                  gid_t gid, const char *socketcon){    struct sockaddr_un addr;    int fd, ret;    char *filecon;    if (socketcon)        setsockcreatecon(socketcon);    fd = socket(PF_UNIX, type, 0);    if (fd < 0) {        ERROR("Failed to open socket '%s': %s\n", name, strerror(errno));        return -1;    }    if (socketcon)        setsockcreatecon(NULL);    memset(&addr, 0 , sizeof(addr));    addr.sun_family = AF_UNIX;    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",             name);//设置此socket的地址    ret = unlink(addr.sun_path);    if (ret != 0 && errno != ENOENT) {        ERROR("Failed to unlink old socket '%s': %s\n", name, strerror(errno));        goto out_close;    }    filecon = NULL;    if (sehandle) {        ret = selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK);        if (ret == 0)            setfscreatecon(filecon);    }    ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));//绑定该socket,启动listen在ZygoteInit::registerZygoteSocket()处理    if (ret) {        ERROR("Failed to bind socket '%s': %s\n", name, strerror(errno));        goto out_unlink;    }    setfscreatecon(NULL);    freecon(filecon);    chown(addr.sun_path, uid, gid);    chmod(addr.sun_path, perm);    INFO("Created socket '%s' with mode '%o', user '%d', group '%d'\n",         addr.sun_path, perm, uid, gid);    return fd;//返回该socket的文件描述符out_unlink:    unlink(addr.sun_path);out_close:    close(fd);    return -1;}

socket创建完成后,要以环境变量键值对的形式把它发布到系统中:

static void publish_socket(const char *name, int fd){    char key[64] = ANDROID_SOCKET_ENV_PREFIX;    char val[64];    strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,            name,            sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));    snprintf(val, sizeof(val), "%d", fd);    add_environment(key, val);//ANDROID_SOCKET_zygote -- socket的文件描述符    /* make sure we don't close-on-exec */    fcntl(fd, F_SETFD, 0);}

到这里,socket的创建、注册处理流程就联系起来了。

ANDROID_SOCKET_ENV_PREFIX、ANDROID_SOCKET_DIR两个宏定义在/system/core/include/cutils/Socket.h中:

#define ANDROID_SOCKET_ENV_PREFIX"ANDROID_SOCKET_"#define ANDROID_SOCKET_DIR"/dev/socket"

 

(2)、preload()

 

preload()函数用于加载系统资源,包括预加载系统类、Framework资源和OpenGL资源等,它的处理如下:

    static void preload() {        Log.d(TAG, "begin preload");        preloadClasses();//加载/system/etc/preloaded-classes和framework.jar中的类资源        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");    }

这里调用了5个函数去加载需要使用的类资源、图片资源、库资源等。这几个函数功能单一,我们可以自己阅读代码;这里就不详述了。但由于这部分内容涉及到很多I/O操作,而且加载的资源较多,会影响Android系统启动的时间。一些开机时间优化就是在这一部分处理的。

 

(3)、startSystemServer()


startSystemServer()函数用于启动system_server进程,它的具体处理如下:

 /**     * Prepare the arguments and fork for the system server process.     */    private static boolean startSystemServer(String abiList, String socketName)            throws MethodAndArgsCaller, RuntimeException {        long capabilities = posixCapabilitiesAsBits(            OsConstants.CAP_BLOCK_SUSPEND,            OsConstants.CAP_KILL,            OsConstants.CAP_NET_ADMIN,            OsConstants.CAP_NET_BIND_SERVICE,            OsConstants.CAP_NET_BROADCAST,            OsConstants.CAP_NET_RAW,            OsConstants.CAP_SYS_MODULE,            OsConstants.CAP_SYS_NICE,            OsConstants.CAP_SYS_RESOURCE,            OsConstants.CAP_SYS_TIME,            OsConstants.CAP_SYS_TTY_CONFIG        );        /* Hardcoded command line to start the system server */        String args[] = {            "--setuid=1000",            "--setgid=1000",            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007",            "--capabilities=" + capabilities + "," + capabilities,            "--nice-name=system_server",            "--runtime-args",            "com.android.server.SystemServer",/*指明需要启动的进程的主类入口*/        };//创建system_server的参数列表。设置了进程的uid、gid和进程名                ZygoteConnection.Arguments parsedArgs = null;        int pid;        try {            parsedArgs = new ZygoteConnection.Arguments(args);            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);            /* Request to fork the system server process */            pid = Zygote.forkSystemServer(                    parsedArgs.uid, parsedArgs.gid,                    parsedArgs.gids,                    parsedArgs.debugFlags,                    null,                    parsedArgs.permittedCapabilities,                    parsedArgs.effectiveCapabilities);//根据参数,为systemserver创建进程        } catch (IllegalArgumentException ex) {            throw new RuntimeException(ex);        }        /* For child process */        if (pid == 0) {//子进程,即system_server进程            if (hasSecondZygote(abiList)) {                waitForSecondaryZygote(socketName);            }            handleSystemServerProcess(parsedArgs);//进程创建完毕后,调用该函数进一步处理        }        return true;//函数返回之后,重新返回到ZygoteInit.main()中,即进入Zygote父进程中    }

首先根据设置的参数列表创建system_server进程,然后在子进程中调用handleSystemServerProcess()做进一步处理:

/**     * Finish remaining work for the newly forked system server process.     */    private static void handleSystemServerProcess(            ZygoteConnection.Arguments parsedArgs)            throws ZygoteInit.MethodAndArgsCaller {        closeServerSocket();//根据fork()机制,system_server是zygote的子进程,它也拥有zygote这个socket资源;但由于system_server不需要使用socket,这里将它关闭        // set umask to 0077 so new files and directories will default to owner-only permissions.        Os.umask(S_IRWXG | S_IRWXO);        if (parsedArgs.niceName != null) {            Process.setArgV0(parsedArgs.niceName);//system_server        }        final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");        if (systemServerClasspath != null) {            performSystemServerDexOpt(systemServerClasspath);//com.android.server.SystemServer        }        if (parsedArgs.invokeWith != null) {            String[] args = parsedArgs.remainingArgs;            // If we have a non-null system server class path, we'll have to duplicate the            // existing arguments and append the classpath to it. ART will handle the classpath            // correctly when we exec a new process.            if (systemServerClasspath != null) {                String[] amendedArgs = new String[args.length + 2];                amendedArgs[0] = "-cp";                amendedArgs[1] = systemServerClasspath;                System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length);            }            WrapperInit.execApplication(parsedArgs.invokeWith,                    parsedArgs.niceName, parsedArgs.targetSdkVersion,                    VMRuntime.getCurrentInstructionSet(), null, args);        } else {            ClassLoader cl = null;            if (systemServerClasspath != null) {                cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());                Thread.currentThread().setContextClassLoader(cl);            }            /*             * Pass the remaining arguments to SystemServer.             */            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);//重要        }        /* should never reach here */    }

直接查看函数末尾调用RuntimeInit.zygoteInit()函数:

 /**     * The main function called when started through the zygote process. This     * could be unified with main(), if the native code in nativeFinishInit()     * were rationalized with Zygote startup.

* * Current recognized args: *

    *
  • [--] *
* * @param targetSdkVersion target SDK version * @param argv arg strings */ public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote"); Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit"); redirectLogStreams(); commonInit();//通用的初始化部分,包括设置默认的uncaught exception handler等 nativeZygoteInit();//调用AppRuntime.cpp::onZygoteInit(),开启线程池,用于Binder通信 applicationInit(targetSdkVersion, argv, classLoader);//通过反射调用SystemServer.java的main函数 }

函数主要做了三个个处理:通用初始化部分;native层开启线程池,用于Binder通信;

    private static final void commonInit() {        if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");        /* set default handler; this applies to all threads in the VM */        Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());        /*         * Install a TimezoneGetter subclass for ZoneInfo.db         */        TimezoneGetter.setInstance(new TimezoneGetter() {            @Override            public String getId() {                return SystemProperties.get("persist.sys.timezone");            }        });        TimeZone.setDefault(null);        /*         * Sets handler for java.util.logging to use Android log facilities.         * The odd "new instance-and-then-throw-away" is a mirror of how         * the "java.util.logging.config.class" system property works. We         * can't use the system property here since the logger has almost         * certainly already been initialized.         */        LogManager.getLogManager().reset();        new AndroidConfig();        /*         * Sets the default HTTP User-Agent used by HttpURLConnection.         */        String userAgent = getDefaultUserAgent();        System.setProperty("http.agent", userAgent);        /*         * Wire socket tagging to traffic stats.         */        NetworkManagementSocketTagger.install();        /*         * If we're running in an emulator launched with "-trace", put the         * VM into emulator trace profiling mode so that the user can hit         * F9/F10 at any time to capture traces.  This has performance         * consequences, so it's not something you want to do always.         */        String trace = SystemProperties.get("ro.kernel.android.tracing");        if (trace.equals("1")) {            Slog.i(TAG, "NOTE: emulator trace profiling enabled");            Debug.enableEmulatorTraceOutput();        }        initialized = true;    }

通用部分的初始化,包括设置默认的uncaught exception handler(UncaughtHandler类);设置默认时区;为HttpURLConnection准备默认的Http User-Agent;开启trace模式等。

nativeZygoteInit()是重要的本地初始化函数,根据JNI实现其最终调用:

static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz){    gCurRuntime->onZygoteInit();//gCurRuntime实际指向AndroidRuntime的子类AppRuntime实例,即调用AppRuntime::onZygoteInit()}
    virtual void AppRuntime::onZygoteInit()    {        sp proc = ProcessState::self();        ALOGV("App process: starting thread pool.\n");        proc->startThreadPool();//开启Binder线程池以保证其他进程可以正确访问到Zygote所提供的服务    }

启动线程池,用于Binder通信。然后进入applicationInit():

    private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)            throws ZygoteInit.MethodAndArgsCaller {        // If the application calls System.exit(), terminate the process        // immediately without running any shutdown hooks.  It is not possible to        // shutdown an Android application gracefully.  Among other things, the        // Android runtime shutdown hooks close the Binder driver, which can cause        // leftover running threads to crash before the process actually exits.        nativeSetExitWithoutCleanup(true);        // We want to be fairly aggressive about heap utilization, to avoid        // holding on to a lot of memory that isn't needed.        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);        final Arguments args;        try {            args = new Arguments(argv);        } catch (IllegalArgumentException ex) {            Slog.e(TAG, ex.getMessage());            // let the process exit            return;        }        // The end of of the RuntimeInit event (see #zygoteInit).        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);        // Remaining arguments are passed to the start class's static main        invokeStaticMain(args.startClass, args.startArgs, classLoader);//通过反射调用SystemServer.java的main方法    }

再看invokeStaticMain():

/**     * Invokes a static "main(argv[]) method on class "className".     * Converts various failing exceptions into RuntimeExceptions, with     * the assumption that they will then cause the VM instance to exit.     *     * @param className Fully-qualified class name     * @param argv Argument vector for main()     * @param classLoader the classLoader to load {@className} with     */    private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)            throws ZygoteInit.MethodAndArgsCaller {        Class<?> cl;        try {            cl = Class.forName(className, true, classLoader);        } catch (ClassNotFoundException ex) {            throw new RuntimeException(                    "Missing class when invoking static main " + className,                    ex);        }        Method m;        try {            m = cl.getMethod("main", new Class[] { String[].class });//获取SystemServer.java的main()函数的域名,但并没有立即调用main函数;        } catch (NoSuchMethodException ex) {            throw new RuntimeException(                    "Missing static main on " + className, ex);        } catch (SecurityException ex) {            throw new RuntimeException(                    "Problem getting static main on " + className, ex);        }        int modifiers = m.getModifiers();        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {            throw new RuntimeException(                    "Main method is not public and static on " + className);        }        /*         * This throw gets caught in ZygoteInit.main(), which responds         * by invoking the exception's run() method. This arrangement         * clears up all the stack frames that were required in setting         * up the process.         */        throw new ZygoteInit.MethodAndArgsCaller(m, argv);//在ZygoteInit.java的main()中第5步处理时,调用SystemServer.java的main()函数    }

通过ZygoteInit.MethodAndArgsCaller异常的处理来调用SystemServer.java的main()函数启动各个系统服务,看MethodAndArgsCaller的定义:

    /**     * Helper exception class which holds a method and arguments and     * can call them. This is used as part of a trampoline to get rid of     * the initial process setup stack frames.     */    public static class MethodAndArgsCaller extends Exception            implements Runnable {        /** method to call */        private final Method mMethod;        /** argument array */        private final String[] mArgs;        public MethodAndArgsCaller(Method method, String[] args) {            mMethod = method;            mArgs = args;        }        public void run() {            try {                mMethod.invoke(null, new Object[] { mArgs });            } catch (IllegalAccessException ex) {                throw new RuntimeException(ex);            } catch (InvocationTargetException ex) {                Throwable cause = ex.getCause();                if (cause instanceof RuntimeException) {                    throw (RuntimeException) cause;                } else if (cause instanceof Error) {                    throw (Error) cause;                }                throw new RuntimeException(ex);            }        }    }

由代码注释可知:这种调用方式会清理堆栈,可以让SystemServer.java的main函数认为自己是system_server进程的入口,虽然这之前已经做了大量的工作。

 

(4)、 runSelectLoop()

 

system_server进程处理完毕后,函数调用重新返回到ZygoteInit.main()中。Zygote进程此时会进入一个loop循环,等待处理来自运行在system_server中的AMS的创建应用进程的请求。runSelectLoop()函数会进入监听和接收socket消息的循环之中,它的处理如下:

/**     * Runs the zygote process's select loop. Accepts new connections as     * they happen, and reads commands from connections one spawn-request's     * worth at a time.     *     * @throws MethodAndArgsCaller in a child process when a main() should     * be executed.     */    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {        ArrayList fds = new ArrayList();        ArrayList peers = new ArrayList();        fds.add(sServerSocket.getFileDescriptor());        peers.add(null);//添加null,是为了保持fds和peers的一致性(对应Zygote Server 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);            } 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 {                    boolean done = peers.get(i).runOnce();                    if (done) {                        peers.remove(i);                        fds.remove(i);                    }                }            }        }    }

acceptCommandPeer()函数会和客户端建立一个socket连接;而ZygoteConnection对象可以进行请求通信。如果ActivityManagerService发送的创建新应用进程的请求在此处收到后,就会进入ZygoteConnection::runOnce()处理。

    /**     * Reads one start command from the command socket. If successful,     * a child is forked and a {@link ZygoteInit.MethodAndArgsCaller}     * exception is thrown in that child while in the parent process,     * the method returns normally. On failure, the child is not     * spawned and messages are printed to the log and stderr. Returns     * a boolean status value indicating whether an end-of-file on the command     * socket has been encountered.     *     * @return false if command socket should continue to be read from, or     * true if an end-of-file has been encountered.     * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main()     * method in child process     */    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) {//参数读取失败时,会关掉当次socket连接            // 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);//将读到的参数保存到Arguments对象中            if (parsedArgs.abiListQuery) {                return handleAbiListQuery();            }            if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {                throw new ZygoteSecurityException("Client may not specify capabilities: " +                        "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +                        ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));            }            applyUidSecurityPolicy(parsedArgs, peer);            applyInvokeWithSecurityPolicy(parsedArgs, peer);            applyDebuggerSystemProperty(parsedArgs);            applyInvokeWithSystemProperty(parsedArgs);            int[][] rlimits = null;            if (parsedArgs.rlimits != null) {                rlimits = parsedArgs.rlimits.toArray(intArray2d);            }            if (parsedArgs.invokeWith != null) {                FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);                childPipeFd = pipeFds[1];                serverPipeFd = pipeFds[0];                Os.fcntlInt(childPipeFd, F_SETFD, 0);            }            /**             * In order to avoid leaking descriptors to the Zygote child,             * the native code must close the two Zygote socket descriptors             * in the child process before it switches from Zygote-root to             * the UID and privileges of the application being launched.             *             * In order to avoid "bad file descriptor" errors when the             * two LocalSocket objects are closed, the Posix file             * descriptors are released via a dup2() call which closes             * the socket and substitutes an open descriptor to /dev/null.             */            int [] fdsToClose = { -1, -1 };            FileDescriptor fd = mSocket.getFileDescriptor();            if (fd != null) {                fdsToClose[0] = fd.getInt$();            }            fd = ZygoteInit.getServerSocketFileDescriptor();            if (fd != null) {                fdsToClose[1] = fd.getInt$();            }            fd = null;            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,                    parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,                    parsedArgs.appDataDir);//调用forkAndSpecialize()函数创建新进程        } 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) {//pid = 0,表示在新创建的子进程中                // in child                IoUtils.closeQuietly(serverPipeFd);                serverPipeFd = null;                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);//调用handleChildProc()来启动子进程                // 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()的主要工作就是会为这个请求fork一个新的进程,并做一些其他的处理。这一部分的内容会在后续分析Application启动时,再做详细介绍。

 

(5)、MethodAndArgsCaller异常处理

 

我们退回到ZygoteInit::main()函数中,看MethodAndArgsCaller异常的捕获处理过程:

catch (MethodAndArgsCaller caller) {            caller.run(); // 5、注意        } catch (RuntimeException ex) {            Log.e(TAG, "Zygote died with exception", ex);            closeServerSocket();            throw ex;        }
 /**     * Helper exception class which holds a method and arguments and     * can call them. This is used as part of a trampoline to get rid of     * the initial process setup stack frames.     */    public static class MethodAndArgsCaller extends Exception            implements Runnable {        /** method to call */        private final Method mMethod;        /** argument array */        private final String[] mArgs;        public MethodAndArgsCaller(Method method, String[] args) {            mMethod = method;            mArgs = args;        }        public void run() {            try {                mMethod.invoke(null, new Object[] { mArgs });//调用mMethod本身代表的方法            } catch (IllegalAccessException ex) {                throw new RuntimeException(ex);            } catch (InvocationTargetException ex) {                Throwable cause = ex.getCause();                if (cause instanceof RuntimeException) {                    throw (RuntimeException) cause;                } else if (cause instanceof Error) {                    throw (Error) cause;                }                throw new RuntimeException(ex);            }        }    }

run()方法中通过invoke()调用SystemServer.java的main()方法:

    /**     * The main entry point from zygote.     */    public static void main(String[] args) {        new SystemServer().run();    }

SystemServer.run()方法中做了大量的工作,其中就包括启动各种重要的Android系统服务,如PackageManagerService、PowerManagerService等,run()函数的实现如下:

    private void run() {        // If a device's clock is before 1970 (before 0), a lot of        // APIs crash dealing with negative numbers, notably        // java.io.File#setLastModified, so instead we fake it and        // hope that time from cell towers or NTP fixes it shortly.        if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {//如果系统时间不正确,则调整系统时间            Slog.w(TAG, "System clock is before 1970; setting to 1970.");            SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);        }        // If the system has "persist.sys.language" and friends set, replace them with        // "persist.sys.locale". Note that the default locale at this point is calculated        // using the "-Duser.locale" command line flag. That flag is usually populated by        // AndroidRuntime using the same set of system properties, but only the system_server        // and system apps are allowed to set them.        //        // NOTE: Most changes made here will need an equivalent change to        // core/jni/AndroidRuntime.cpp        if (!SystemProperties.get("persist.sys.language").isEmpty()) {            final String languageTag = Locale.getDefault().toLanguageTag();            SystemProperties.set("persist.sys.locale", languageTag);            SystemProperties.set("persist.sys.language", "");            SystemProperties.set("persist.sys.country", "");            SystemProperties.set("persist.sys.localevar", "");        }        // Here we go!        Slog.i(TAG, "Entered the Android system server!");        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());        // In case the runtime switched since last boot (such as when        // the old runtime was removed in an OTA), set the system        // property so that it is in sync. We can't do this in        // libnativehelper's JniInvocation::Init code where we already        // had to fallback to a different runtime because it is        // running as root and we need to be the system user to set        // the property. http://b/11463182//设置当前的虚拟机的运行库路径        SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());        // Enable the sampling profiler.        if (SamplingProfilerIntegration.isEnabled()) {            SamplingProfilerIntegration.start();            mProfilerSnapshotTimer = new Timer();            mProfilerSnapshotTimer.schedule(new TimerTask() {                @Override                public void run() {                    SamplingProfilerIntegration.writeSnapshot("system_server", null);                }            }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);        }        // Mmmmmm... more memory!        VMRuntime.getRuntime().clearGrowthLimit();        // The system server has to run all of the time, so it needs to be        // as efficient as possible with its memory usage.        VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);        // Some devices rely on runtime fingerprint generation, so make sure        // we've defined it before booting further.        Build.ensureFingerprintProperty();        // Within the system server, it is an error to access Environment paths without        // explicitly specifying a user.        Environment.setUserRequired(true);        // Ensure binder calls into the system always run at foreground priority.        BinderInternal.disableBackgroundScheduling(true);        // Prepare the main looper thread (this thread).        android.os.Process.setThreadPriority(                android.os.Process.THREAD_PRIORITY_FOREGROUND);        android.os.Process.setCanSelfBackground(false);        Looper.prepareMainLooper();        // Initialize native services.        System.loadLibrary("android_servers");//装载libandroid_servers.so库        // Check whether we failed to shut down last time we tried.        // This call may not return.        performPendingShutdown();        // Initialize the system context.        createSystemContext();//初始化系统Context对象,这块详细内容会在分析ActivityManagerService时介绍        // Create the system service manager.        mSystemServiceManager = new SystemServiceManager(mSystemContext);        LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);        // Start services.        try {            startBootstrapServices();            startCoreServices();            startOtherServices();        } catch (Throwable ex) {            Slog.e("System", "******************************************");            Slog.e("System", "************ Failure starting system services", ex);            throw ex;        }        // For debug builds, log event loop stalls to dropbox for analysis.        if (StrictMode.conditionallyEnableDebugLogging()) {            Slog.i(TAG, "Enabled StrictMode for system server main thread.");        }        // Loop forever.        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");    }

SystemServer::run()函数中,重要的服务启动操作都工作在主线程中,并且最后会开启一个消息循环。
其中:

        // Start services.        try {            startBootstrapServices();            startCoreServices();            startOtherServices();        } catch (Throwable ex) {            Slog.e("System", "******************************************");            Slog.e("System", "************ Failure starting system services", ex);            throw ex;        }

会启动Android系统中各种重要的系统服务。到此,Zygote进程的启动过程就结束了。







 

 

 

更多相关文章

  1. C语言函数的递归(上)
  2. AIDL跨进程通信和Service调用
  3. Android(安卓)GSM驱动模块(rild)详细分析(三)response流程
  4. Android计算器功能的实现
  5. 【Java/Android性能优5】 Android(安卓)ImageCache图片缓存,使用
  6. Android(安卓)JNI知识简介
  7. Android(安卓)动画框架的基本原理
  8. Android中SoundPool放声音
  9. Android(安卓)进程间通信AIDL简单使用

随机推荐

  1. Android集成融云IM踩坑记录
  2. Android(安卓)帧动画 补间动画 属性动画
  3. android在ubuntu桌面系统下编译可能的错
  4. 解决安卓webview不支持input type=file问
  5. 基于XMPP实现的Openfire的配置安装+Andro
  6. Android的各种分辨率
  7. Android文档学习05_网络1
  8. android 兼容性测试
  9. Android(安卓)Debug Bridge(ADB)的配置
  10. Android(安卓)开始支持Vulkan图形编程接