cm-14.1 Android系统启动过程分析(5)-Zygote进程启动过程

声明

  • 前阶段在项目中涉及到了Android系统定制任务,Android系统定制前提要知道Android系统是如何启动的。
  • 本文参考了一些书籍的若干章节,比如《Android进阶解密-第2章-Android系统启动》、《深入理解Android虚拟机-第8/9/10章-init进程详解/Dalvik VM的进程系统/Dalvik VM运作流程详解》、《深入理解Android系统-第6/7/8章-init启动进程详解/Zygote进程详解/System进程详解》等
  • 本文使用的代码是LineageOS的cm-14.1,对应Android 7.1.2,可以参考我的另一篇博客:cm-14.1 Android系统启动过程分析(1)-如何下载Nexus5的LineageOS14.1(cm-14.1)系统源码并编译、刷机
  • 很多代码注释待详细写

0 写在前面的

    Android系统中主要有三个重要的进程系统:

  1. Zygote进程:被称为孵化进程,功能和Linux中的fork类似,不同的是它在Android系统中用来产生Java层的子进程;
  2. System进程:系统进程,是Android Framework所在的进程,用于启动Android系统。核心进程为Zygote进程fork出来的system_server,由system_server再去启动Framework层各个系统服务;
  3. 应用程序进程:每个Android应用程序运行时都有自己的进程;

1 Zygote是什么

  Android系统是基于Linux内核搭建起来的开放系统,那么它也是遵循Linux操作系统的基本原理:即所有的进程都是由init进程fork出来的。Zygote进程也是由init进程根据解析的init.rc相关命令启动起来的。之所以Zygote进程在Android系统中处于重要位置,是因为它是Android系统中第一个Java进程、也是Framework系统服务的祖先,Zygote正是通常所说的Java运行环境(DVM/ART)。

  Zygote创建了第一个Java虚拟机,并且创建进程system server,这是绝大多数系统服务的守护进程。之后为每一个应用程序创建一个相应的Activity进程。具体步骤如下:

  1. 创建AppRuntime对象,并且调用该对象的start,由AppRuntime 来控制后续的活动。
  2. 调用startVM创建Java虚拟机,由startReg来注册JNI函数。
  3. 通过JNI调用com.androidinternal.os.Zygotelnit类的main函数,开始进入 Java 世界。
  4. 调用registerZygoteSocket()、preload() 两个函数,响应其他应用程序。
  5. 通过调用startSystemServer()分裂一个子进程system_server来提供服务。
  6. 调用runSelectLoopMode()函数。

  Zygote启动新应用的过程如图所示Zygote Service接受启动新程序的请求,通过调用Zygote loop函数,使用fork机制为这个程序设置一个启动进程,通过该进程启动程序。同时,通过COW(Copy on Write)方式对运行在内存中的进程实现最大程度的复用,并通过库共享有效地降低内存的使用量(footprint)。
  Zygote在Android系统中是一个C/S架构,其他进程作为客户端向Zygote发出fork请求,当Zygote接收到命令后就fork出一个Activity进程。

  用adb连接Nexus5手机,执行ps命令可观察各个系统进程的PID及PPID:

USER      PID   PPID  VSIZE  RSS   WCHAN            PC  NAME
root      1     0     7916   1388  sys_epoll_ 00000000 S /init
root      2     0     0      0       kthreadd 00000000 S kthreadd
...省略n行...
root      227   1     1559616 68852 poll_sched 00000000 S zygote
...省略n行...
system    806   227   1825696 136184 sys_epoll_ 00000000 S system_server
u0_a64    973   227   993120 48228 sys_epoll_ 00000000 S com.android.inputmethod.latin
u0_a33    987   227   1087016 106116 sys_epoll_ 00000000 S com.android.systemui
media_rw  992   157   8388   1852  inotify_re 00000000 S /system/bin/sdcard
u0_a1     1083  227   978064 37988 sys_epoll_ 00000000 S org.cyanogenmod.cmaudio.service
wifi      1124  1     7660   3164  poll_sched 00000000 S /system/bin/wpa_supplicant
u0_a7     1408  227   977836 38748 sys_epoll_ 00000000 S com.android.cellbroadcastreceiver
u0_a34    1465  227   977348 36624 sys_epoll_ 00000000 S org.cyanogenmod.weather.provider
u0_a10    1525  227   976332 37348 sys_epoll_ 00000000 S android.ext.services
root      1542  1     11392  1444  futex_wait 00000000 S /system/bin/mpdecision
u0_a47    1595  227   984276 42372 sys_epoll_ 00000000 S com.android.deskclock
u0_a31    1637  227   977884 37928 sys_epoll_ 00000000 S org.cyanogenmod.weatherservice
u0_a58    1642  227   982704 39360 sys_epoll_ 00000000 S com.android.printspooler
u0_a3     1658  227   981108 39668 sys_epoll_ 00000000 S org.cyanogenmod.audiofx
nfc       1673  227   1002016 47588 sys_epoll_ 00000000 S com.android.nfc
radio     1692  227   979008 38340 sys_epoll_ 00000000 S com.redbend.vdmc
u0_a9     1720  227   986664 50868 sys_epoll_ 00000000 S android.process.media
system    1736  227   977416 37228 sys_epoll_ 00000000 S com.android.keychain
u0_a60    1764  227   977408 36920 sys_epoll_ 00000000 S com.android.smspush
u0_a30    1779  227   1073396 88992 sys_epoll_ 00000000 S com.cyanogenmod.trebuchet
u0_a52    1832  227   979260 39432 sys_epoll_ 00000000 S com.cyanogenmod.lockclock
system    1854  227   986712 46544 sys_epoll_ 00000000 S org.cyanogenmod.cmparts
u0_a43    1883  227   995504 50448 sys_epoll_ 00000000 S com.android.calculator2
u0_a16    1909  227   993656 42248 sys_epoll_ 00000000 S com.android.dialer
u0_a41    1937  227   991976 41420 sys_epoll_ 00000000 S com.android.calendar
u0_a5     1954  227   977320 37408 sys_epoll_ 00000000 S com.android.carrierconfig
u0_a2     1971  227   987116 47844 sys_epoll_ 00000000 S android.process.acore
u0_a54    2009  227   993892 45456 sys_epoll_ 00000000 S com.android.email
u0_a4     2026  227   982520 40928 sys_epoll_ 00000000 S com.android.providers.calendar
u0_a56    2760  227   977208 36528 sys_epoll_ 00000000 S com.qualcomm.timeservice
u0_a67    2803  227   1109540 86768 sys_epoll_ 00000000 S com.alibaba.android.rimet:channel
shell     2951  212   3632   1312  sys_rt_sig b6e5839c S /system/bin/sh
shell     2978  2951  4576   1304           0 b6bff1e8 R ps

    其中,Zygote进程的PID为227,PPID为1;system_server进程的PID为806,PPID为227;

    Zygote启动之初进程名字叫app_process,Zygote启动之后Linux系统下的pctrl系统会调用app_process,将其名称换成zygote。

2 Zygote启动脚本

    init.rc脚本最前面就import了zygote相关的rc文件:

#对于Nexus5来说,${ro.zygote}的值为zygote32
import /init.${ro.zygote}.rc

    在源码目录~/LineageOS/system/core/rootdir中有四个zygote相关的rc文件,分别是:

init.zygote32.rc
init.zygote64.rc
init.zygote32_64.rc
init.zygote64_32.rc

    Android5.0以后是支持64位程序的,Zygote也就有了32和64的差别,这里利用ro.zygote值得不同进而选择启动不同的Zygote进程。

2.1 init.zygote32.rc文件

    支持纯32位程序,init.zygote32.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 audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    writepid /dev/cpuset/foreground/tasks

    根据其中的onrestart可知,如果audioserver、cameraserver、media、netd等进程终止了,就需要重启。

2.2 init.zygote32_64.rc文件

    支持32位程序和64位程序,init.zygote32_64.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 audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    writepid /dev/cpuset/foreground/tasks

service 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

    脚本中要启动Zygote进程,一个名称为zygote,执行程序为app_process32,作为主模式;另一个名为zygote_secondary,执行程序为app_process64,作为辅助模型。

    在我的上篇文章:cm-14.1 Android系统启动过程分析(4)-init进程的启动、rc脚本解析、zygote启动、属性服务中的【3.2.1 解析Zygote节】中介绍了Zygote进程是如何被init进程启动起来的。

3 Zygote进程启动过程分析

    先借鉴一张图来看看启动过程时序图:

3.1 入口函数main()

  通过上面我们知道Zygote进程要执行的程序便是app_process了,它位于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 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) {
        const char* arg = argv[i++];
        //Zygote进程是通过fork自身来创建创建子进程的,这样Zygote进程以及它的子进程都可以进入app_main.cpp的main函数,因此main函数为了区分当前运行在哪个进程,会判断arg中是否包含了参数“--zygote”,如果包含则说明main运行在Zygote进程中,将zygote设置为true;
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        //判断参数arg是否包含“--start-system-server”,如果包含则说明main运行在SystemServer进程中,并将startSystemServer设置为true
        } 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<String8> args;
    if (!className.isEmpty()) {
        // 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);
    } else {
        // 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());
    }
    //若zygote为true,说明当前运行在Zygote进程中,调用AppRuntime的start函数
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, 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;
    }
}

3.2 启动函数创建一个虚拟机实例,进入Java世界

  若zygote为true,说明当前运行在Zygote进程中,调用AppRuntime的start函数,AppRuntime的start方法在源码目录:~/LineageOS/frameworks/base/core/jni/AndroidRuntime.cpp

/*
 * 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<String8>& 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)));
        }
    }

    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;
    //启动Java虚拟机;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    onVmCreated(env);

    /*
     * Register android functions.
     */
    //为Java虚拟机注册JNI方法;
    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;

    stringClass = env->FindClass("java/lang/String");
    assert(stringClass != NULL);
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    assert(strArray != NULL);
    //从app_main的main函数得知className为com.android.internal.os.ZygoteInit;
    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.
     */
    //将className的.替换为“/”;
    char* slashClassName = toSlashClassName(className);
    //找到ZygoteInit
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        //找到ZygoteInit的main方法;
        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 {
            //通过JNI调用类com.android.internal.os.ZygoteInit的静态成员main()方法来启动Zygote进程;
            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");
}

   最终,Zygote进程成功通过JNI调用从Native层的app_process进入Java框架层的ZygotInit,真正进入了Java代码的世界!!
  打开源码目录:~/LineageOS/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java,查看其main方法:

    public static void main(String argv[]) {
        // Mark zygote start. This ensures that thread creation will throw
        // an error.
        ZygoteHooks.startZygoteNoThreadCreation();

        try {
            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit");
            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;
                } 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());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
           }
            //创建一个Server端的Socket,socketname的值为“zygote”,用于等待AMS请求Zygote来创建新的应用程序进程;
            registerZygoteSocket(socketName);
            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload");
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());
            //预加载类和资源;
            preload();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());
            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);

            // Finish profiling the zygote initialization.
            SamplingProfilerIntegration.writeZygoteSnapshot();

            // Do an initial gc to clean up after startup
            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC");
            gcAndFinalize();
            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);

            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);

            // Disable tracing so that forked processes do not inherit stale tracing tags from
            // Zygote.
            Trace.setTracingEnabled(false);

            // Zygote process unmounts root storage spaces.
            Zygote.nativeUnmountStorageOnInit();

            ZygoteHooks.stopZygoteNoThreadCreation();

            if (startSystemServer) {
                //启动SystemServer进程,Java层的系统服务线程将会由它启动起来
                startSystemServer(abiList, socketName);
            }

            Log.i(TAG, "Accepting command socket connections");
            //进入无限循环,在前面创建的Socket接口中等待ActivityManagerService请求,以创建新的应用程序进程;至于AMS如何与Zygote链接的等我分析AMS时再详细描述!
            runSelectLoop(abiList);

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

  ZygoteInit的main方法主要完成4件事情:

  1. 创建一个Server端的Socket;
  2. 预加载类和资源;
  3. 启动SystemServer进程;
  4. 等待AMS请求创建新的应用程序进程;

3.3 registerZygoteSocket方法

  进入源码目录:~/LineageOS/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java,查看其registerZygoteSocket方法:

    /**
     * Registers a server socket for zygote command connections
     *
     * @throws RuntimeException when open fails
     */
    private static void registerZygoteSocket(String socketName) {
        if (sServerSocket == null) {
            int fileDesc;
            //拼接Socket的名称,为"ANDROID_SOCKET_+zygote";
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {
                //得到Socket的环境变量的值,将fullSocketName转换为环境变量的值;
                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);
                //创建服务器端Socket,并将文件操作符作为参数传进去;Zygote进程将SystemServer进程启动后,就会在这个服务器端的Socket上等待AMS请求Zygote进程来创建新的应用程序进程;
                sServerSocket = new LocalServerSocket(fd);
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }

    Zygote进程将SystemServer进程启动后,就会在这个服务器端的Socket上等待AMS请求Zygote进程来创建新的应用程序进程;

3.4 启动SystemServer进程

    进入源码目录:~/LineageOS/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java,查看其startSystemServer方法:

    /**
     * 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_IPC_LOCK,
            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_PTRACE,
            OsConstants.CAP_SYS_TIME,
            OsConstants.CAP_SYS_TTY_CONFIG
        );
        /* Containers run without this capability, so avoid setting it in that case */
        if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER, false)) {
            capabilities |= posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND);
        }
        /* Hardcoded command line to start the system server */
        //创建args数组,用来保存启动SystemServer的启动参数;其中可看到SystemServer进程的用户id和用户组id被设置为1000,并且拥有用户组1001-1010、1018、1021、1032、3001-3010的权限;进程名为system_server,启动的类名为:com.android.server.SystemServer;
        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,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;

        int pid;

        try {
            //将args数组封装成Arguments对象并提供给forkSystemServer使用;
            parsedArgs = new ZygoteConnection.Arguments(args);
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

            /* Request to fork the system server process */
            //调用ZygoteInit的forkSystemServer方法(native层调用的是nativeForkSystemServer方法,最终通过fork函数),创建一个子进程,也就是SystemServer进程;
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        //当前代码逻辑运行在子进程中;
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            //处理SystemServer进程;
            handleSystemServerProcess(parsedArgs);
        }

        return true;
    }

   这样就去启动SystemServer进程了,SystemServer进程的启动过程参考:cm-14.1 Android系统启动过程分析(6)-SystemServer进程启动过程

3.5 runSelectLoop方法

    进入源码目录:~/LineageOS/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java,查看其runSelectLoop方法:

    /**
     * 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<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        //sServerSocket即在registerZygoteSocket方法中创建的服务器端Socket,调用sServerSocket.getFileDescriptor()函数来获得该Socket的fd字段的值并添加到fd列表fds中;
        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);
        //无限循环等待AMS请求Zygote进程创建新的应用程序进程;
        while (true) {
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            //通过遍历fds存储的信息转移到pollFds数组中;
            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);
            }
            //对pollFds进行遍历,如果i==0说明服务器端Socket与客户端连接上了,也就是当前Zygote进程和AMS建立了连接;
            for (int i = pollFds.length - 1; i >= 0; --i) {
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }
                if (i == 0) {
                    //acceptCommandPeer方法得到ZygoteConnection类并添加到Socket连接列表peers中,然后将该ZygoteConnection的fd添加到fds中,以便可以接收到AMS发送过来的请求;
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    //调用ZygoteConnection的runOnce函数来创建一个新的应用程序进程,并在成功创建后将这个连接从Socket连接列表peers和fd列表fds中清除;
                    boolean done = peers.get(i).runOnce();
                    if (done) {
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }

3.6 Zygote进程启动总结

Zygote进程启动共做了以下几波操作:

  1. 创建AppRuntime并调用其start方法,启动Zygote进程;
  2. 创建Java虚拟机并为Java虚拟机注册JNI方法;
  3. 通过JNI调用ZygoteInit的main函数进入Zygote的Java框架层;
  4. 通过registerZygoteSocket方法创建服务器端Socket,并通过runSelectLoop方法等待AMS的请求来创建新的应用程序进程;
  5. 启动SystemServer进程;

4 Zygote背后的逻辑

  读到这里你可能不禁要问:不就是启动一个新的 App 嘛,有必要搞得这么复杂吗?还真有必要!因为这样做有不少好处,还不止是在一个方面,这些好处体现在两个方面。

  • 应用启动所需的时间会被大大缩短:
    不论是哪个 App,所有的虚拟机都必须按照某种一样的而且是确定的方式初始化。加载 App 的类只不过是这个操作的最后一步罢了,但是这一操作产生的实际开销却主要是花在加载大量构成了 Android 各种丰富的框架的运行时类上的。如果你把 App 的加载想象成一场长跑赛,那么使用 Zygote 让 Android 可以在临近终点时才突然插进比赛,只用跑最后一个冲刺即可一一这样就省去了前面加载各种库的时间,耗时当然会相对短很多。
  • 优化共享内存:
    因为所有的虚拟机都是从 Zygote 这里 fork0出来的,所以它们无疑能够享受到由内核实现的内存共享的优势。特别是,尽管每个 app_process 的实例都有它自己的虚拟内存,但这些内存中的大部分是只读的(因为其中存放的是类的实现代码),在物理内存中只需保留一份,让各个进程共享就够了。而内存的其他部分 (存储的是类的数据,读写)也只要在绝对必要的时候才需要分配一些内存页来存储这些数据[这种技术叫“写时复制”(copy-on-write)]。因此,大多数 Android 应用都和其他应用(其中还包括system server,它是第一个真正的完整虚拟机的实例)共享了80%~90%的内存。这种被最大化了的内存使用方式,使得即使是在那些拥有物理内存相对较少的设备中仍可以“塞”进不少应用。这是 Zygote 特有的设计,这一设计使得它在Java跌倒的地方获得成功。
      所有的虚拟机都是从 Zygote 这里 fork()出来的,这种优化也不是没有缺点:所有的应用都是从同一个进程fork()出来的,这会有效地破坏地址空间布局随机化(ASLR,Address)----而这一技术却又是对抗代码注入攻击的重要安全手段。换句话说,需求量大的战胜了需求量小的,对性能的渴求压倒了安全需求。
      在使用ART(Android RunTime,Android 运行时)后,Zygote 甚至变得更有效了,因为所有预加载类也都已经经过预编译了。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小馬佩德罗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值