基于Android 7.0源码,分析zygote进程的启动过程。

  • 一app_mainmain
    • 1app_maincomputeArgBlockSize
    • 2AppRuntimeAppRuntime
      • 1AndroidRuntimeAndroidRuntime
    • 3app_mainmaybeCreateDalvikCache
  • 二AndroidRuntimestart
    • 1AndroidRuntimestartVm
    • 2AndroidRuntimestartReg
  • 三ZygoteInitmain
    • 1ZygoteInitregisterZygoteSocket
    • 2ZygoteInitpreload
    • 2ZygoteInitstartSystemServer
    • 3ZygoteInitrunSelectLoop
  • Zygote总结

  Zygote是由init进程通过解析init.zygoteXX.rc文件而创建的,其中的“XX”根据CPU平台的不同,可能是不同的数字。

  init进程会首先解析在\system\core\rootdir\init.rc文件内容,咋一看init.rc文件中并没有发现与zygote有关的语句;仔细看init.rc文件的前5行,发现已经隐蔽的import了init.${ro.zygote}.rc。

import /init.environ.rcimport /init.usb.rcimport /init.${ro.hardware}.rcimport /init.${ro.zygote}.rcimport /init.trace.rc......

  ro.zygote是一个属性值,对于Nexus 7二代平板而言,由于其使用的是高通的32位处理器,故ro.zygote的值为zygote32。

  我们以Nexus 7二代硬件平台为例,接着看\system\core\rootdir\init.zygote32.rc文件。

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server    class main #指定入口为main函数    socket zygote stream 660 root system #指定zygote服务所使用到的socket,该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的所对应的可执行程序是app_process,位于手机中的/system/bin/目录下,是一个可执行bin文件,并且也指明了四个启动参数,分别是”-Xzygote”、”/system/bin”、”–zygote”和”–start-system-server”。

  • -Xzygote
      该参数将作为虚拟机启动时所需要的参数,是在AndroidRuntime.cpp类的startVm()函数中调用JNI_CreateJavaVM()时被使用的。

  • /system/bin
      代表虚拟机程序所在目录,因为app_process完全可以不和虚拟机在同一个目录,而在app_process内部的AndroidRuntime类内部需要知道虚拟机所在的目录。

  • –zygote
      指明以ZygoteInit类作为虚拟机执行的入口,如果没有–zygote参数,则需要明确指定需要执行的类名。

  • –start-system-server
      仅在指定–zygote参数时才有效,意思是告知ZygoteInit启动完毕后孵化出第一个进程SystemServer。

  命令”socket zygote stream 660 root system”,用于指定zygote服务所使用到的socket,该socket的名称为zygote,类型为stream,读写权限为660,用户为root,用户组为system。

  那么这个位于/system/bin目录下的app_process这个bin文件又是如何生成的呢?
  通过在代码中全局搜索”app_process”,我们查找到负责编译生成”app_process”模块的Android.mk文件存放在\frameworks\base\cmds\app_process这个目录下。

  app_process的入口是该目录下的app_main.cpp中的main函数。下面就从该文件入手,分析Zygote进程的启动流程。

app_main.main

一、app_main.main

[===>frameworks\base\cmds\app_process\app_main.cpp]

#if defined(__LP64__)static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";static const char ZYGOTE_NICE_NAME[] = "zygote64";#elsestatic const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";static const char ZYGOTE_NICE_NAME[] = "zygote";#endifint main(int argc, char* const argv[]){    ......    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++];        if (strcmp(arg, "--zygote") == 0) {//条件成立            zygote = true;            niceName = ZYGOTE_NICE_NAME;//将niceName设置为"zygote"或者"zygote64"        } 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;//该参数接下来要传入AndroidRuntime.start函数    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();//进入zygote模式,创建/data/dalvik-cache路径        if (startSystemServer) {            args.add(String8("start-system-server"));        }        char prop[PROP_VALUE_MAX];        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {            ......        }        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()) {//条件不成立        ......    }    if (zygote) {//条件成立        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);    } else if (className) {//条件不成立        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);    } else {//条件不成立      return 10;//没有指定类名或zygote,参数错误    }}

  根据init.zygote.rc文件内容,之前提到传入main函数四个参数(”-Xzygote“、”/system/bin“、”–zygote“和”–start-system-server“),因此我们知道argc和argv分别为:

int argc = 4;char* const argv[] = "-Xzygote /system/bin --zygote --start-system-server\0";//参数之间为一个空格

1、app_main.computeArgBlockSize

[===>frameworks\base\cmds\app_process\app_main.cpp]

static size_t computeArgBlockSize(int argc, char* const argv[]) {    // TODO: This assumes that all arguments are allocated in    // contiguous memory. There isn't any documented guarantee    // that this is the case, but this is how the kernel does it    // (see fs/exec.c).    //    // Also note that this is a constant for "normal" android apps.    // Since they're forked from zygote, the size of their command line    // is the size of the zygote command line.    //    // We change the process name of the process by over-writing    // the start of the argument block (argv[0]) with the new name of    // the process, so we'd mysteriously start getting truncated process    // names if the zygote command line decreases in size.    uintptr_t start = reinterpret_cast(argv[0]);    uintptr_t end = reinterpret_cast(argv[argc - 1]);    end += strlen(argv[argc - 1]) + 1;    return (end - start);}

  这里计算并且返回了传入参数的字节数,这样的目的可以确保传入的四个参数是在一个连续的内存中。

// TODO: This assumes that all arguments are allocated incontiguous memory.

  回到app_main.main函数,在知道了传入参数的字节长度后,创建了AppRuntime。

2、AppRuntime.AppRuntime

[===>frameworks\base\cmds\app_process\app_main.cpp]

class AppRuntime : public AndroidRuntime{public:    AppRuntime(char* argBlockStart, const size_t argBlockLength)        : AndroidRuntime(argBlockStart, argBlockLength)        , mClass(NULL)    {    }    ......}

2.1、AndroidRuntime.AndroidRuntime

[===>frameworks\base\core\jni\AndroidRuntime.cpp]

static AndroidRuntime* gCurRuntime = NULL;AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :        mExitWithoutCleanup(false),        mArgBlockStart(argBlockStart),        mArgBlockLength(argBlockLength){    SkGraphics::Init();    // There is also a global font cache, but its budget is specified in code    // see SkFontHost_android.cpp    // Pre-allocate enough space to hold a fair number of options.    mOptions.setCapacity(20);    assert(gCurRuntime == NULL);        // one per process    gCurRuntime = this;}

  静态全局变量gCurRuntime指向AndroidRuntime对象本身,这样之后如果我们需要获取AndroidRuntime对象时,只要获取gCurRuntime即可。

  在启动zygote进程流程中,需要为zygote创建/data/dalvik-cache路径。

3、app_main.maybeCreateDalvikCache

[===>frameworks\base\core\jni\AndroidRuntime.cpp]

static void maybeCreateDalvikCache() {    #if defined(__aarch64__)        static const char kInstructionSet[] = "arm64";    #elif defined(__x86_64__)        static const char kInstructionSet[] = "x86_64";    #elif defined(__arm__)        static const char kInstructionSet[] = "arm";    #elif defined(__i386__)        static const char kInstructionSet[] = "x86";    #elif defined (__mips__) && !defined(__LP64__)        static const char kInstructionSet[] = "mips";    #elif defined (__mips__) && defined(__LP64__)        static const char kInstructionSet[] = "mips64";    #else    #error "Unknown instruction set"    #endif    const char* androidRoot = getenv("ANDROID_DATA");//androidRoot为“data”    LOG_ALWAYS_FATAL_IF(androidRoot == NULL, "ANDROID_DATA environment variable unset");    char dalvikCacheDir[PATH_MAX];    const int numChars = snprintf(dalvikCacheDir, PATH_MAX,            "%s/dalvik-cache/%s", androidRoot, kInstructionSet);    LOG_ALWAYS_FATAL_IF((numChars >= PATH_MAX || numChars < 0),            "Error constructing dalvik cache : %s", strerror(errno));    int result = mkdir(dalvikCacheDir, 0711);//创建/data/dalvik-cache路径    LOG_ALWAYS_FATAL_IF((result < 0 && errno != EEXIST),            "Error creating cache dir %s : %s", dalvikCacheDir, strerror(errno));    // We always perform these steps because the directory might    // already exist, with wider permissions and a different owner    // than we'd like.    result = chown(dalvikCacheDir, AID_ROOT, AID_ROOT);//更改/data/dalvik-cache路径的用户与用户组为root用户、root用户组    LOG_ALWAYS_FATAL_IF((result < 0), "Error changing dalvik-cache ownership : %s", strerror(errno));    result = chmod(dalvikCacheDir, 0711);//更改/data/dalvik-cache路径的权限    LOG_ALWAYS_FATAL_IF((result < 0),            "Error changing dalvik-cache permissions : %s", strerror(errno));}

  这里创建了/data/dalvik-cache路径,并修改该路径的用户、用户组和权限信息。这里暂时还不清楚/data/dalvik-cache路径的作用,得留意一下,看看后面有没有用到。

  在分析AndroidRuntime.start之前,根据zygote的启动参数,参数zygote为true,变量args的实际值为:

"start-system-server""--abi-list=ro.product.cpu.abilist32""-Xzygote""/system/bin""--zygote""--start-system-server"

  参数中带有“–zygote,所以bool型变量zygote的值为true,就执行runtime.start(“com.android.internal.os.ZygoteInit”, args),调用了runtime.start函数。

  由于AppRuntime继承自AndroidRuntime,但是又未实现其start函数,故这里实际上调用的是AndroidRuntime.start函数。

二、AndroidRuntime.start

[===>frameworks\base\core\jni\AndroidRuntime.cpp]

/* 1. Start the Android runtime.  This involves starting the virtual machine 2. and calling the "static void main(String[] args)" method in the class 3. named by "className". 4.  5. Passes the main function two arguments, the class name and the specified 5. options string. */ //className为"com.android.internal.os.ZygoteInit"void AndroidRuntime::start(const char* className, const Vector<String8>& options){    ......    static const String8 startSystemServer("start-system-server");    ......    const char* rootDir = getenv("ANDROID_ROOT");//设置rootDir为"/system"目录,ANDROID_ROOT为"/system"    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);    }    ......    /* start the virtual machine */    JniInvocation jni_invocation;    jni_invocation.Init(NULL);    JNIEnv* env;    if (startVm(&mJavaVM, &env) != 0) {//启动虚拟机        return;    }    onVmCreated(env);    /*     * Register android functions.     */    if (startReg(env) < 0) {//注册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);    jclass startClass = env->FindClass(slashClassName);    if (startClass == NULL) {        ......    } else {        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",            "([Ljava/lang/String;)V");//获取"com.android.internal.os.ZygoteInit"类main函数        if (startMeth == NULL) {            ......        } else {            env->CallStaticVoidMethod(startClass, startMeth, strArray);//调用ZygoteInit.main函数        }    }    free(slashClassName);    ......}

  AndroidRuntime.start函数主要做了三个工作:
  1、启动虚拟机
  调用AndroidRuntime.startVm启动虚拟机
  2、注册jni函数
  调用AndroidRuntime.startReg注册jni函数
  3、调用ZygoteInit.main函数
  下面分别来看看这三个步骤的工作内容。

2.1、AndroidRuntime.startVm

[===>frameworks\base\core\jni\AndroidRuntime.cpp]
  创建Java虚拟机方法的主要篇幅是关于虚拟机参数的设置,下面只列举部分在调试优化过程中常用参数。

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote){    // JNI检测功能,用于native层调用jni函数时进行常规检测,比较弱字符串格式是否符合要求,资源是否正确释放。该功能一般用于早期系统调试或手机Eng版,对于User版往往不会开启,引用该功能比较消耗系统CPU资源,降低系统性能。    bool checkJni = false;    property_get("dalvik.vm.checkjni", propBuf, "");    if (strcmp(propBuf, "true") == 0) {        checkJni = true;    } else if (strcmp(propBuf, "false") != 0) {        property_get("ro.kernel.android.checkjni", propBuf, "");        if (propBuf[0] == '1') {            checkJni = true;        }    }    if (checkJni) {        addOption("-Xcheck:jni");    }    //虚拟机产生的trace文件,主要用于分析系统问题,路径默认为/data/anr/traces.txt    parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");    //对于不同的软硬件环境,这些参数往往需要调整、优化,从而使系统达到最佳性能    parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");    parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");    parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");    parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");    parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");    parseRuntimeOption("dalvik.vm.heaptargetutilization",                       heaptargetutilizationOptsBuf, "-XX:HeapTargetUtilization=");    //preloaded-classes文件内容是由WritePreloadedClassFile.java生成的,在ZygoteInit类中会预加载工作将其中的classes提前加载到内存,以提高系统性能    if (!hasFile("/system/etc/preloaded-classes")) {        return -1;    }    //创建虚拟机    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {        ALOGE("JNI_CreateJavaVM failed\n");        return -1;    }}

2.2、AndroidRuntime.startReg

[===>frameworks\base\core\jni\AndroidRuntime.cpp]

/* * Register android native functions with the VM. *//*static*/ int AndroidRuntime::startReg(JNIEnv* env){    ATRACE_NAME("RegisterAndroidNatives");    /*     * This hook causes all future threads created in this process to be     * attached to the JavaVM.  (This needs to go away in favor of JNI     * Attach calls.)     */    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);    ALOGV("--- registering native functions ---\n");    /*     * Every "register" function calls one or more things that return     * a local reference (e.g. FindClass).  Because we haven't really     * started the VM yet, they're all getting stored in the base frame     * and never released.  Use Push/Pop to manage the storage.     */    env->PushLocalFrame(200);    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {        env->PopLocalFrame(NULL);        return -1;    }    env->PopLocalFrame(NULL);    //createJavaThread("fubar", quickTest, (void*) "hello");    return 0;}

Threads.androidSetCreateThreadFunc
[===>system\core\libutils\Threads.cpp]

void androidSetCreateThreadFunc(android_create_thread_fn func){    gCreateThreadFn = func;}

  具体分析下来,虚拟机启动后,在startReg()注册过程,会设置线程创建函数指针gCreateThreadFn指向javaCreateThreadEtc。
  回到AndroidRuntime.startReg(),紧接着会调用register_jni_procs,进行jni接口的注册工作。

AndroidRuntime.register_jni_procs

static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env){    for (size_t i = 0; i < count; i++) {        if (array[i].mProc(env) < 0) {#ifndef NDEBUG            ALOGD("----------!!! %s failed to load\n", array[i].mName);#endif            return -1;        }    }    return 0;}

RegJNIRec.mProc

#ifdef NDEBUG    #define REG_JNI(name)      { name }    struct RegJNIRec {        int (*mProc)(JNIEnv*);    };#else    ......#endiftypedef void (*RegJAMProc)();static const RegJNIRec gRegJNI[] = {    REG_JNI(register_com_android_internal_os_RuntimeInit),    REG_JNI(register_android_os_SystemClock),    REG_JNI(register_android_util_EventLog),    ......}

  array[i]是指gRegJNI数组, 该数组有100多个成员。其中每一项成员都是通过REG_JNI宏定义的。gRegJNI数组array[i]的某一项调用mProc(env),就等价于调用其参数名所指向的函数。 例如REG_JNI(register_com_android_internal_os_RuntimeInit).mProc也就是指进入register_com_android_internal_os_RuntimeInit方法,接下来就继续以此为例来说明:

/* * JNI registration. */static const JNINativeMethod gMethods[] = {//java层方法名与jni层的方法的一一映射关系    { "nativeFinishInit", "()V",        (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },    { "nativeZygoteInit", "()V",        (void*) com_android_internal_os_RuntimeInit_nativeZygoteInit },    { "nativeSetExitWithoutCleanup", "(Z)V",        (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },};int register_com_android_internal_os_RuntimeInit(JNIEnv* env){    return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",        gMethods, NELEM(gMethods));}

  好了,已经粗略的看过启动虚拟机和注册jni函数代码了,现在就要分析ZygoteInit.main函数了,做好准备,start。

三、ZygoteInit.main

[===>frameworks\base\core\java\com\android\internal\os\ZygoteInit.java]

public class ZygoteInit {  ......  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();//开启DDMS          // 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());//ro.product.cpu.abilist32              } 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]);              }          }          ......          registerZygoteSocket(socketName);          ......          preload();//预加载类、资源、OpenGL和共享库等          ......          // 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);          // Zygote process unmounts root storage spaces.          Zygote.nativeUnmountStorageOnInit();          ZygoteHooks.stopZygoteNoThreadCreation();          if (startSystemServer) {//条件成立              startSystemServer(abiList, socketName);//启动SystemServer          }          Log.i(TAG, "Accepting command socket connections");          runSelectLoop(abiList);          closeServerSocket();      } catch (MethodAndArgsCaller caller) {          caller.run();      } catch (RuntimeException ex) {          Log.e(TAG, "Zygote died with exception", ex);          closeServerSocket();          throw ex;      }  }  ......}

  ZygoteInit.main主要做了三项工作:

  1. 调用registerZygoteSocket,注册zygote的socket。
  2. 调用startSystemServer,启动SystemServer。
  3. 调用runSelectLoop,zygote无限循环等待创建进程的请求。

1、ZygoteInit.registerZygoteSocket

[===>frameworks\base\core\java\com\android\internal\os\ZygoteInit.java]

public class ZygoteInit {    ......    private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";    ......    /**     * Registers a server socket for zygote command connections     *     * @throws RuntimeException when open fails     */    private static void registerZygoteSocket(String socketName) {//socketName为"zygote"        if (sServerSocket == null) {            int fileDesc;            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;//fullSocketName为"ANDROID_SOCKET_zygote"            try {                String env = System.getenv(fullSocketName);                fileDesc = Integer.parseInt(env);//实际上获得/dev/socket/zygote的文件描述符            } catch (RuntimeException ex) {                ......            }            try {                sServerSocket = new LocalServerSocket(                        createFileDescriptor(fileDesc));//创建Socket的本地服务端            } catch (IOException ex) {                ......            }        }    }    ......}

  这里根据zygote的socket的文件描述符创建了LocalServerSocket对象并保存在zygoteInit的类型LocalServerSocket的静态成员变量sServerSocket中,若又想反过来获得zygote的socket的文件描述符,只要调用LocalServerSocket.getFileDescriptor即可。

  我们知道,在进行经典的socket网络编程时,需要有服务端等待客户端的连接,需要客户端向服务端进行连接请求。

服务端socket 客户端socket
socket() 创建socket socket() 创建socket
bind() 绑定socket ————
listen() 监听socket ————
———— connect() 连接服务端socket
accept() 接受客户端连接请求 ————

  这里,将zygote的socket注册成服务端的过程实际上也是这个过程,是通过构造LocalServerSocket对象时完成注册的。

  来看看LocalServerSocket,代码位于\frameworks\base\core\java\android\net\LocalServerSocket.java文件中。

/** * Non-standard class for creating an inbound UNIX-domain socket * in the Linux abstract namespace. */public class LocalServerSocket {    private final LocalSocketImpl impl;//Framework层socket的实现,JNI调用系统socket的API  private final LocalSocketAddress localAddress;//unix域socket地址及其所处的空间  ......    /**     * Creates a new server socket listening at specified name.     * On the Android platform, the name is created in the Linux     * abstract namespace (instead of on the filesystem).     *     * @param name address for socket     * @throws IOException     */    public LocalServerSocket(String name) throws IOException    {        impl = new LocalSocketImpl();        impl.create(LocalSocket.SOCKET_STREAM);        localAddress = new LocalSocketAddress(name);        impl.bind(localAddress);        impl.listen(LISTEN_BACKLOG);    }  ......}

  LocalSocketImpl类的实现代码位于\frameworks\base\core\java\android\net\LocalSocketImpl.java文件中。
  LocalSocketAddress类的实现代码位于\frameworks\base\core\java\android\net\LocalSocketAddress.java文件中。

  与经典的socket服务端注册过程对比如下表:

经典socket服务端 zygote的socket服务端
socket() 创建socket LocalSocketImpl.create() 创建socket
bind() 绑定socket LocalSocketImpl.bind(LocalSocketAddress) 绑定socket
listen() 监听socket LocalSocketImpl.listen() 监听socket

  至于socket的创建、绑定和监听工作,LocalSocketImpl也是通过jni调用c层的socket API函数完成,这个部分略去了。
  到这里,就将zygote的socket注册成为服务端,ZygoteInit.sServerSocket就是位于服务端的zygote的socket。

然后就会调用startSystemServer来创建SystemServer进程。

2、ZygoteInit.preload

[===>frameworks\base\core\java\com\android\internal\os\ZygoteInit.java]

static void preload() {    preloadClasses();//预加载/system/etc/preloaded-classes文件中的类    preloadResources();//预加载drawable和color资源    preloadOpenGL();//预加载OpenGL    preloadSharedLibraries();//通过System.loadLibrary的方式加载"android"、"compiler_rt"和"jnigraphics"共享库    preloadTextResources();    // Ask the WebViewFactory to do any initialization that must run in the zygote process,    // for memory sharing purposes.    WebViewFactory.prepareWebViewInZygote();//在zygote进程中初始化WebView,用于内存共享}

  这里暂时要知道的有两点:
-1、zygote在启动过程中会通过Class.forName的方式预加载/system/etc/preloaded-classes文件中的类,该文件中指定的类有很多,因此如果需要优化开机时间的话,完全可以暂时不加载一些不必要的类,来达到缩短开机时间的目的;
-2、在preloadResources()预加载com.android.internal.R.array.preloaded_drawables和com.android.internal.R.array.preloaded_color_state_lists或者com.android.internal.R.array.preloaded_freeform_multi_window_drawables中指定的drawable和color资源。

2、ZygoteInit.startSystemServer

[===>frameworks\base\core\java\com\android\internal\os\ZygoteInit.java]

/** * Startup class for the zygote process. * * Pre-initializes some classes, and then waits for commands on a UNIX domain * socket. Based on these commands, forks off child processes that inherit * the initial state of the VM. * * Please see {@link ZygoteConnection.Arguments} for documentation on the * client protocol. * * @hide */public class ZygoteInit {  ......    /**     * 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",//SystemServer进程uid            "--setgid=1000",//SystemServer进程gid            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",            "--capabilities=" + capabilities + "," + capabilities,            "--runtime-init",            "--nice-name=system_server",//SystemServer进程名            "com.android.server.SystemServer",//startClass名称        };        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 */            //对zygote进程进行fork,得到的子进程就是SystemServer进程,返回的子进程pid为0            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) {//此时处于SystemServer进程中            if (hasSecondZygote(abiList)) {                waitForSecondaryZygote(socketName);            }            handleSystemServerProcess(parsedArgs);//完成SystemServer进程的剩余工作        }        return true;    }  ......}

  代码首先通过ZygoteConnection来解析出将来创建SystemServer进程时所需的参数。除了能够解析参数外,ZygoteConnection另外一个功能就是记录zygote的socket套接字连接。
  准备参数并fork新进程,从上面可以看出system server进程参数信息为uid=1000,gid=1000,进程名为sytem_server,从zygote进程fork新进程后,需要关闭zygote原有的socket。另外,对于有两个zygote进程情况,需等待第2个zygote创建完成。

  具体启动SystemServer的流程,打算专门写一篇文章来说明,这里直接看ZygoteInit.runSelectLoop函数。


  在创建好SysteServer进程后,在SystemServer进程中调用handleSystemServerProcess处理。

Step 10. zygoteInit.handleSystemServerProcess
[===>frameworks\base\core\java\com\android\internal\os\ZygoteInit.java]

    /**     * Finish remaining work for the newly forked system server process.     */    private static void handleSystemServerProcess(            ZygoteConnection.Arguments parsedArgs)            throws ZygoteInit.MethodAndArgsCaller {        closeServerSocket();//SystemServer进程不需要接受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);        }        final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");        if (systemServerClasspath != null) {            performSystemServerDexOpt(systemServerClasspath);        }        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,                    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 */    }

Step 11. RuntimeInit.zygoteInit
[===>frameworks\base\core\java\com\android\internal\os\RuntimeInit.java]

/** * Main entry point for runtime initialization.  Not for * public consumption. * @hide */public class RuntimeInit {  ......    /**     * 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.

* @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"); redirectLogStreams(); commonInit();//常规的初始化 nativeZygoteInit();//bind通信机制的准备工作 applicationInit(targetSdkVersion, argv, classLoader); } ......}

Step 11. RuntimeInit.applicationInit
[===>frameworks\base\core\java\com\android\internal\os\RuntimeInit.java]

    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;        }        // Remaining arguments are passed to the start class's static main        invokeStaticMain(args.startClass, args.startArgs, classLoader);//args.startClass为"com.android.server.SystemServer"    }

  最后调用了com.android.server.SystemServer类的main函数。

Step 12. SystemServer.main
  这里就进行了SystemServer的初始化工作,这里不重点分析。


  在启动完成SystemServer后,就又执行了ZygoteInit.runSelectLoop函数。

3、ZygoteInit.runSelectLoop

[===>frameworks\base\core\java\com\android\internal\os\ZygoteInit.java]

    /**     * 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());//fds[0]为sServerSocket,即sServerSocket为位于zygote进程中的socket服务端;        peers.add(null);        while (true) {            StructPollfd[] pollFds = new StructPollfd[fds.size()];            for (int i = 0; i < pollFds.length; ++i) {                pollFds[i] = new StructPollfd();                pollFds[i].fd = fds.get(i);//pollFds[0].fd即为sServerSocket,位于zygote进程中的socket服务端                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) {                    //客户端第一次请求服务端,服务端调用accept与客户端建立连接,客户端在zygote中以ZygoteConnection对象表示。                    ZygoteConnection newPeer = acceptCommandPeer(abiList);                    peers.add(newPeer);                    fds.add(newPeer.getFileDesciptor());                } else {//经过上个if操作后,客户端与服务端已经建立连接,并开始发送数据;peers.get(index)取得发送数据客户端的ZygoteConnection对象,之后调用runOnce函数处理具体的请求。                    boolean done = peers.get(i).runOnce();                    if (done) {//请求处理完成之后,移除与该客户端的连接                        peers.remove(i);                        fds.remove(i);                    }                }            }        }    }

  runSelectLoop函数的逻辑比较简单,主要有两点:
  1. 处理客户端的连接和请求。其中客户端在zygote进程中使用ZygoteConnection对象表示。
  2. 客户的请求经由ZygoteConnection的runOnce来处理。


Zygote总结


  Zygote是在android系统中创建java世界的盘古,它创建了第一个java虚拟机。同时,它又是女娲,它成功的繁殖了framework的核心system_server进程。主要步骤如下:
  1. 创建AppRuntime对象,并调用其start函数。之后zygote的核心初始化都由AppRuntime中。
  2. 调用startVm创建java虚拟机,然后调用startReg来注册JNI函数。
  3. 通过JNI调用com.android.internal.os.ZygoteInit类的main函数,从此进入了java世界。
  4. 调用registerZygoteSocket创建可以响应子孙后代请求的socket。同时,zygote调用preload函数预加载了常用的类、资源等,为java世界添砖加瓦。
  5. 调用startSystemServer函数分裂了一个子进程system_server来为java世界服务。
  6. Zygote完成了java世界的初创工作,便调用runSelectLoop来让自己无限循环等待。之后,如果收到子孙后代的请求,它便会醒来为他们工作。

更多相关文章

  1. 箭头函数的基础使用
  2. Python技巧匿名函数、回调函数和高阶函数
  3. 关于Android调用系统Action录制视频
  4. android视频截图
  5. Android(安卓)MediaPlayer基本知识
  6. Android(安卓)Telephony 分析[PART IV]
  7. java.lang.NullPointerException Attempt to invoke virtual met
  8. Android(安卓)后台线程调用前台线程的几种方法
  9. Android(安卓)P Android.dp添加逻辑判断

随机推荐

  1. Android Studio无法执行Java类的main方法
  2. Android 实现在Java代码中修改UI界面,并修
  3. Android API Differences Report
  4. Android ApiDemos示例解析(100):Views->A
  5. CreateProcess error=2, 系统找不到指定
  6. Android添加单元测试的方法与步骤
  7. Android SDK的docs访问速度很慢
  8. android添加超级管理权限
  9. Android环境变量作用--命令行操作
  10. Android 触摸事件传递流程解析