android 系统启动–Zygote

Zygote的触发过程

Zygote是init启动的第一个进程

所有的system server 都是从Zygote fork来的。

// 进程名称是zygote,运行的二进制文件在/system/bin/app_process64
// 启动参数是 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    priority -20
    user root
    group root readproc
    socket zygote stream 660 root system //创建一个socket,名字叫zygote,以tcp形式
    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
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks //创建子进程时,向/dev/cpuset/foreground/tasks 写入pid

// 另一个service ,名字 zygote_secondary
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
    class main
    priority -20
    user root
    group root readproc
    socket zygote_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks

Zygote start

定义在 platform/system/core/rootdir/init.rc

# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device s init.rc to unblock zygote start.
on zygote-start && property:ro.crypto.state=unencrypted
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

on zygote-start && property:ro.crypto.state=unsupported
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

zygote在哪里触发

on late-init
    ...

    trigger zygote-start

late-init 在哪里启动

在init进程进入循环的最后一个地方

if (bootmode == "charger") {
        am.QueueEventTrigger("charger");
    } else {
        am.QueueEventTrigger("late-init");
    }

这个就是init进程启动Zygote的由来。

为什么要有Zygote,虽然init是android系统启动的第一个进程,但是init来管理的事情太多了,如果都是有init来触发启动其他android进程,这个init事情就太多了。所以通过Zygote来启动其他进程,就把android其他进程由Zygote来负责了。

Zygote启动参数解析

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote

在app_main.cpp种定义了Zygote的解析过程。

int main(int argc, char* const argv[])
{
    //将参数argv放到argv_String字符串中,然后打印出来
    //之前start zygote传入的参数是 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    if (!LOG_NDEBUG) {
      String8 argv_String;
      for (int i = 0; i < argc; ++i) {
        argv_String.append("/"");
        argv_String.append(argv[i]);
        argv_String.append("/" ");
      }
      ALOGV("app_process main with argv: %s", argv_String.string());
    }

    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));//构建AppRuntime对象,并将参数传入
    // 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.
    //
    // As an exception to the above rule, anything in "spaced commands"
    // goes to the vm even though it has a space in it.

    //上面这段英文大概讲的是,所有在 "--" 后面的非 "-"开头的参数都将传入vm, 但是有个例外是spaced commands数组中的参数

    const char* spaced_commands[] = { "-cp", "-classpath" };//这两个参数是Java程序需要依赖的Jar包,相当于import
    // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
    bool known_command = false;
    int i;
    for (i = 0; i < argc; i++) {
        if (known_command == true) { //将spaced_commands中的参数额外加入VM
          runtime.addOption(strdup(argv[i]));
          ALOGV("app_process main add known option  %s ", argv[i]);
          known_command = false;
          continue;
        }

        for (int j = 0;
             j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
             ++j) {
          if (strcmp(argv[i], spaced_commands[j]) == 0) {//比较参数是否是spaced_commands中的参数
            known_command = true;
            ALOGV("app_process main found known command  %s ", argv[i]);
          }
        }

        if (argv[i][0] !=  - ) { //如果参数第一个字符是 - ,直接跳出循环,之前传入的第一个参数是 -Xzygote,所以执行到这儿就跳出了,i=0
            break;
        }
        if (argv[i][1] ==  -  && argv[i][2] == 0) {
            ++i; // Skip --.
            break;
        }

        runtime.addOption(strdup(argv[i]));
        ALOGV("app_process main add option  %s ", 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.
    //跳过一个参数,之前跳过了-Xzygote,这里继续跳过 /system/bin ,也就是所谓的 "parent dir"
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {//表示是zygote启动模式
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;//这个值根据平台可能是zygote64或zygote
        } else if (strcmp(arg, "--start-system-server") == 0) {//需要启动SystemServer
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {//表示是application启动模式,也就是普通应用程序
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {//进程别名
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {//application启动的class
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }

    Vector<String8> args;
    if (!className.isEmpty()) {//className不为空,说明是application启动模式
        // 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);//将className和参数设置给runtime

        if (!LOG_NDEBUG) {//打印class带的参数
          String8 restOfArgs;
          char* const* argv_new = argv + i;
          int argc_new = argc - i;
          for (int k = 0; k < argc_new; ++k) {
            restOfArgs.append("/"");
            restOfArgs.append(argv_new[k]);
            restOfArgs.append("/" ");
          }
          ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
        }
    } else { //zygote启动模式
        // We re in zygote mode.
        maybeCreateDalvikCache(); //新建Dalvik的缓存目录

        if (startSystemServer) {//加入start-system-server参数
            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); //加入--abi-list=参数

        // In zygote mode, pass all remaining arguments to the zygote
        // main() method.
        for (; i < argc; ++i) {//将剩下的参数加入args
            args.add(String8(argv[i]));
        }
    }

    if (!niceName.isEmpty()) {//设置进程别名
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }

    if (zygote) { //如果是zygote启动模式,则加载ZygoteInit
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {//如果是application启动模式,则加载RuntimeInit
        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.");
    }
}

参数描述:

// –zygote : Start in zygote mode

// –start-system-server : Start the system server.

// –application : Start in application (stand alone, non zygote) mode.

这段描述以及解释清楚。

整个过程其实是2个部分

start-system-server

AppRuntime,虚拟机的启动,是在这个类里面执行的。

如上面的注解,如果传入的是start-system-server就

startSystemServer = true;

然后在后面的位置

if (startSystemServer) {//加入start-system-server参数
            args.add(String8("start-system-server"));
        }

        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);

zygote启动模式,也就是start-system-server模式,就启动com.android.internal.os.ZygoteInit进程的虚拟机。

因为android是一个进程,一个虚拟机进程。

application启动

如果是启动application,就会走到

application = true;

后面就启动

} else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);

这里就是通过jvm启动一个application的进程

创建虚拟机

platform/frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{

    ... //打印一些日志,获取ANDROID_ROOT环境变量

    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);//初始化JNI,加载libart.so
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {//创建虚拟机
        return;
    }
    onVmCreated(env);//表示虚拟创建完成,但是里面是空实现

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

    ... //JNI方式调用ZygoteInit类的main函数
}

startVm启动虚拟机

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{

    ... //打印一些日志,获取ANDROID_ROOT环境变量

    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);//初始化JNI,加载libart.so
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {//创建虚拟机
        return;
    }
    onVmCreated(env);//表示虚拟创建完成,但是里面是空实现

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

    ... //JNI方式调用ZygoteInit类的main函数
}

Jni初始化

/*
   * 1.FindSymbol函数内部实际调用的是dlsym
   * 2.dlsym作用是根据 动态链接库 操作句柄(handle)与符号(symbol),返回符号对应的地址
   * 3.这里实际就是从libart.so中将JNI_GetDefaultJavaVMInitArgs等对应的地址存入&JNI_GetDefaultJavaVMInitArgs_中
   */
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
                  "JNI_GetDefaultJavaVMInitArgs")) {
    return false;
  }
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
                  "JNI_CreateJavaVM")) {
    return false;
  }
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
                  "JNI_GetCreatedJavaVMs")) {
    return false;
  }
  return true;

Init函数主要作用是初始化JNI,具体工作是首先通过dlopen加载libart.so获得其句柄,然后调用dlsym从libart.so中找到

JNI_GetDefaultJavaVMInitArgs、JNI_CreateJavaVM、JNI_GetCreatedJavaVMs三个函数地址,赋值给对应成员属性,

这三个函数会在后续虚拟机创建中调用.

startVm

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
    JavaVMInitArgs initArgs;
    ...
    addOption("exit", (void*) runtime_exit);各//将参数放入mOptions数组中
    ...
    initArgs.version = JNI_VERSION_1_4;
    initArgs.options = mOptions.editArray();//将mOptions赋值给initArgs
    initArgs.nOptions = mOptions.size();
    initArgs.ignoreUnrecognized = JNI_FALSE;
    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {//调用libart.so的JNI_CreateJavaVM函数
            ALOGE("JNI_CreateJavaVM failed/n");
            return -1;
    }
    return 0;
}

extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
  return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
}

jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
  return JNI_CreateJavaVM_(p_vm, p_env, vm_args);//调用之前初始化的JNI_CreateJavaVM_
}

主要就是存储一些参数到mOptions 里面,另外就是调用JNI_CreateJavaVM方法调起VM

startReg

startReg首先是设置了Android创建线程的处理函数,然后创建了一个200容量的局部引用作用域,用于确保不会出现OutOfMemoryException, 最后就是调用register_jni_procs进行JNI注册

register_jni_procs

我们看看register_jni_procs传入的RegJNIRec数组gRegJNI,里面就是一堆的函数指针

static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_com_android_internal_os_RuntimeInit),
    REG_JNI(register_com_android_internal_os_ZygoteInit),
    REG_JNI(register_android_os_SystemClock),
    REG_JNI(register_android_util_EventLog),
    REG_JNI(register_android_util_Log),
    REG_JNI(register_android_util_MemoryIntArray)
    ...
}

我们随便看一个register_com_android_internal_os_ZygoteInit,这实际上是自定义JNI函数并进行动态注册的标准写法,

内部是调用JNI的RegisterNatives,这样注册后,Java类ZygoteInit的native方法nativeZygoteInit就会调用com_android_internal_os_ZygoteInit_nativeZygoteInit函数

int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
{
    const JNINativeMethod methods[] = {
        { "nativeZygoteInit", "()V",
            (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
    };
    return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
        methods, NELEM(methods));
}

反射调用ZygoteInit类的main函数

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    /*
     * 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.
     */

    //接下来的这些语法大家应该比较熟悉了,都是JNI里的语法,主要作用就是调用ZygoteInit类的main函数 
    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);//找到class
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class  %s /n", slashClassName);
        /* keep going */
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in  %s /n", className);
            /* keep going */
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);//调用main函数

#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");
}

原文 

http://www.demanmath.com/index.php/2020/06/22/android-xitongqidong-zygote/

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » android 系统启动–Zygote

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址