init进程到Zygote进程

​ init进程到Zygote进程流程图如下:

BA1216B4-DAA5-4dff-A5F5-FCC1D97CB4BB

​ Android启动流程中,当内核启动之后,就会启动init进程。init进程是一个用户级进程,而且它是由内核拉起的。init进程的入口在system/core/init/init.cpp 的main方法。在Android9.0源码中,init.cpp文件没有main方法,在system/core/init文件夹中的main.cpp中找到了main方法:

int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif

    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }

    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();

            return SubcontextMain(argc, argv, &function_map);
        }

        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }

        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }

    return FirstStageMain(argc, argv);
}

​ 在main.cpp文件的main方法中根据条件,调用了init.h声明的SecondStageMain方法,尚不清楚条件是什么,不过最终会走到init.cpp文件中的SecondStageMain方法。为什么会走到这里?因为不走到这里说不通啊,哈哈哈哈

​ 在init.cpp文件的SecondStageMain方法中,调用LoadBootScripts方法,读取解析init.rc文件:

static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser = CreateParser(action_manager, service_list);

    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    if (bootscript.empty()) {
        parser.ParseConfig("/system/etc/init/hw/init.rc");
        if (!parser.ParseConfig("/system/etc/init")) {
            late_import_paths.emplace_back("/system/etc/init");
        }
        // late_import is available only in Q and earlier release. As we don't
        // have system_ext in those versions, skip late_import for system_ext.
        //从上面日志看,应该会走这里,bootscript默认应该是空的
        parser.ParseConfig("/system_ext/etc/init");
        if (!parser.ParseConfig("/product/etc/init")) {
            late_import_paths.emplace_back("/product/etc/init");
        }
        if (!parser.ParseConfig("/odm/etc/init")) {
            late_import_paths.emplace_back("/odm/etc/init");
        }
        if (!parser.ParseConfig("/vendor/etc/init")) {
            late_import_paths.emplace_back("/vendor/etc/init");
        }
    } else {
        parser.ParseConfig(bootscript);
    }
}

​ 从源码log看,bootscript默认是空的,上面的代码应该是初始化各个文件夹

​ 回到init.rc的SecondStageMain方法,继续往ActionManager对象添加信息。

// Run all property triggers based on current state of the properties.
am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");

​ 上面这句,运行所有的触发器(trigger)。

init.rc

import /system/etc/init/hw/init.${ro.zygote}.rc

on late-init
    trigger zygote-start

on zygote-start && property:persist.sys.fuse=true
  # Mount default storage into root namespace
  mount none /mnt/user/0 /storage bind rec
  mount none none /storage slave rec
on zygote-start && property:persist.sys.fuse=false
  # Mount default storage into root namespace
  mount none /mnt/runtime/default /storage bind rec
  mount none none /storage slave rec
on zygote-start && property:persist.sys.fuse=""
  # Mount default storage into root namespace
  mount none /mnt/runtime/default /storage bind rec
  mount none none /storage slave rec
##############
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
##############
on property:vold.decrypt=trigger_post_fs_data
    trigger post-fs-data
    trigger zygote-start
##############
on userspace-reboot-resume
  trigger userspace-reboot-fs-remount
  trigger post-fs-data
  trigger zygote-start
  trigger early-boot
  trigger boot

​ init.rc文件中关于zygote的进程都在上面了,import /system/etc/init/hw/init.${ro.zygote}.rc,根据当前系统的版本import对应的init.zygoteXX.rc文件。接着,好多个start zygote,没看懂到底是哪个在执行,不过最终执行import进来的init.zygoteXX.rc文件。下面是64位的:

init.zygote64.rc:

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    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

service关键字表示这是要启动一个服务,zygote是服务的名字(这里的服务是init进程内部的概念,跟Android的服务不是一个东西)。

/system/bin/app_process64:指明zygote服务对应的二进制文件的路径。init进程会fork一个子进程来运行指定的程序,这个程序就是:frameworks/base/cmds/app_process/app_main.cpp。

-Xzygote /system/bin --zygote --start-system-server:启动zygote的时候传递给frameworks/base/cmds/app_process/app_main.cpp的参数

frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{
    //....
    //1、AppRuntime是内部类
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // Process command line arguments 2、进程命令行参数
    // ignore argv[0]   3、忽略第一个参数,好像是-Xzygote
    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    启动zygote模式
    // --start-system-server : Start the system server. //启动system server
    // --application : Start in application (stand alone, non zygote) mode.application模       // 式,跟zygote模式互斥
    // --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.  
    // 对于非zygote模式启动,这些参数将后跟主类名称。 所有其余的参数都传递给此类的main方法。
    //
    // For zygote starts, all remaining arguments are passed to the zygote.
    // main function.
    // 对于zygote模式启动,所有剩余的参数都传递给zygote。即main方法
    // Note that we must copy argument string values since we will rewrite the
    // entire argument block when we apply the nice name to argv0.
    // 注意,我们必须复制参数字符串值,因为当我们将nice name 应用于argv0时,我们将重写整个参数块。
    // As an exception to the above rule, anything in "spaced commands"
    // goes to the vm even though it has a space in it.
    // 作为上述规则的例外,“spaced commands”中的任何内容都将送至vm,即使其中有空格也是如此。
//**************下面这段代码没看懂*************************
    const char* spaced_commands[] = { "-cp", "-classpath" };
    // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
    // 允许“spaced commands”后接正好1个参数(无论-s如何)。
    bool known_command = false;

    int i;
    for (i = 0; i < argc; i++) {
        if (known_command == true) {
          runtime.addOption(strdup(argv[i]));
          // The static analyzer gets upset that we don't ever free the above
          // string. Since the allocation is from main, leaking it doesn't seem
          // problematic. NOLINTNEXTLINE
          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) {
            known_command = true;
            ALOGV("app_process main found known command '%s'", argv[i]);
          }
        }

        if (argv[i][0] != '-') {//如果参数不是 以“-” 开头就退出?
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {//--(哪个字符对应0?),如果是这种格式就退出? 
            ++i; // Skip --.
            break;
        }

        runtime.addOption(strdup(argv[i]));
        // The static analyzer gets upset that we don't ever free the above
        // string. Since the allocation is from main, leaking it doesn't seem
        // problematic. NOLINTNEXTLINE
        ALOGV("app_process main add option '%s'", argv[i]);
    }
//**************上面这段代码没太看懂*************************

//传进来的参数 : -Xzygote /system/bin --zygote --start-system-server ,后面的不知道传没传
// 根据上面的代码,好像在遇到  /system/bin 的时候,因为不是以“-”开头,所以直接退出循环了

    // Parse runtime arguments.  Stop at first unrecognized option. 
    // 解析运行时参数。 停在第一个无法识别的选项。
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;
//根据前面的分析,到这里 i 指向的argv的内容是 /system/bin
    ++i;  // Skip unused "parent dir" argument. 跳过未使用的“父目录”参数。
// 递增一个之后, i 指向的argv内容就是 --zygote
// 所以下面的循环是可以执行的
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            //第一次会走到这里
            zygote = true;
            //static const char ZYGOTE_NICE_NAME[] = "zygote64";
            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;
        }
    }
//上面的循环只走两次,其他参数不符合了  最终:  zygote = true; niceName = ZYGOTE_NICE_NAME; 
// startSystemServer = true;

    Vector<String8> args;
    //className 没赋值 走else
    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);

        if (!LOG_NDEBUG) {
          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 { 
        // We're in zygote mode. zygote模式
        maybeCreateDalvikCache(); //创建虚拟机缓存?

        if (startSystemServer) {//添加启动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);

        // In zygote mode, pass all remaining arguments to the zygote
        // main() method.  在zygote模式下,将所有剩余的参数传递给main()方法。
        for (; i < argc; ++i) {//把剩余的参数放到args里面
            args.add(String8(argv[i]));
        }
    }

    if (!niceName.isEmpty()) {
        //确实不为空,设置进程名字 zygote64 
        //使用 adb shell ps 命令查看,确实有名为zygote64的进程
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }

    if (zygote) {
        //启动zygote 然后转到Java世界
        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.");
    }
}

上面是对app_main.cpp文件的main方法的分析,基本上每一步都有注释。这个方法的功能主要是对启动zygote进程传递进来的参数进行处理。

AppRuntime

AppRuntime是app_miain.cpp里面的内部类,继承自AndroidRuntime。

void AndroidRuntime::setArgv0(const char* argv0, bool setProcName) {
    // Set the kernel's task name, for as much of the name as we can fit. 设置内核的任务名称,并使用尽可能多的名称。
    // The kernel's TASK_COMM_LEN minus one for the terminating NUL == 15. 内核的TASK_COMM_LEN减1代表终止NUL == 15。
    if (setProcName) { //前面知道这个setProcName == true
        int len = strlen(argv0);
        if (len < 15) {
            pthread_setname_np(pthread_self(), argv0);
        } else {
            pthread_setname_np(pthread_self(), argv0 + len - 15);
        }
    }

    // Directly change the memory pointed to by argv[0].  直接更改argv [0]指向的内存。
    memset(mArgBlockStart, 0, mArgBlockLength);
    strlcpy(mArgBlockStart, argv0, mArgBlockLength);

    // Let bionic know that we just did that, because __progname points
    // into argv[0] (https://issuetracker.google.com/152893281).
    setprogname(mArgBlockStart);
}

setArgv0方法好像是做一些初始化工作。

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
 //对于zygote模式,className = com.android.internal.os.ZygoteInit options是参数列表  zygote = true

    static const String8 startSystemServer("start-system-server");//options中第一个参数也是start-system-server
    // Whether this is the primary zygote, meaning the zygote which will fork system server.
    bool primary_zygote = false;

    /*
     * 'startSystemServer == true' means runtime is obsolete and not run from
     * init.rc anymore, so we print out the boot start event here.
     *'startSystemServer == true'表示runtime已过时,不再从init.rc中运行,因此我们在此处打印启动启动事件。
     */
    for (size_t i = 0; i < options.size(); ++i) {
        if (options[i] == startSystemServer) {//options中第一个参数 是start-system-server
            primary_zygote = true;
           /* 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 /system does not exist.");
            return;
        }
        setenv("ANDROID_ROOT", rootDir, 1);
    }

    const char* artRootDir = getenv("ANDROID_ART_ROOT");
    if (artRootDir == NULL) {
        LOG_FATAL("No ART directory specified with ANDROID_ART_ROOT environment variable.");
        return;
    }

    const char* i18nRootDir = getenv("ANDROID_I18N_ROOT");
    if (i18nRootDir == NULL) {
        LOG_FATAL("No runtime directory specified with ANDROID_I18N_ROOT environment variable.");
        return;
    }

    const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT");
    if (tzdataRootDir == NULL) {
        LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable.");
        return;
    }
//上面的代码是检查文件夹及运行环境是否满足条件

    //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; //JNI 引擎?
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {//如果启动失败,返回的不是0,所以结果不为0,就直接退出
        return;
    }
    onVmCreated(env);//这是个空方法

    /*
     * Register android functions. 注册Android方法,注册的是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.
     * 我们要使用包含参数的String数组调用main()。 目前,我们有两个参数,即类名和选项字符串。 创建一个数组来保存它们。
     *
     * 调用Java类的main方法都需要一个String类型的数组,这里开始创建。用传递过来的类名和参数列表创建
     */
    jclass stringClass; //jclass是JNI的数据类型?
    jobjectArray strArray;//jobjectArray是JNI的数据类型?
    jstring classNameStr;//jstring是JNI的数据类型?

    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) {//把传过来的参数保存到JNI类型数组中
        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 != NULL ? className : "");//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 {
        //找到类走这里
        //找main方法
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            //找不到main方法走这里
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            //找到main方法走这里
            //调用main方法,到这就开始去到Java世界了,运行 com.android.internal.os.ZygoteInit 的main方法
            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");
}

总结

​ init进程是怎么被拉起的,那是内核的事情,太底层了看不到。而init进程被拉起来之后,做了些什么事情呢?如下:

  1. 读取、解析、执行init.rc文件
  2. 解析init.rc到zygote start的时候, 程序运行到app_process.cpp的main方法(app_process.cpp的main方法的参数来源与init.zygote64.rc)
  3. app_process.cpp的main方法,解析参数,将参数一一准备好,放到一个String类型的列表中。
  4. 启动虚拟机、注册Android JNI方法
  5. 通过JNI,调用Java层的com.android.internal.os.ZygoteInit.java的main方法

results matching ""

    No results matching ""