init进程启动zygote的过程分析

23 阅读3分钟

在Android系统的启动过程中,init进程通过解析init.rc文件启动zygote,其过程分析如下。
本文以Android 13代码为例。
1,init进程解析init.rc文件
在init.rc文件中

import /system/etc/init/hw/init.${ro.zygote}.rc	//采用import来引入Zygote启动脚本,通过adb shell getprop | grep ro.zygot获取ro.zygote值
on late-init
    trigger zygote-start
//在zygote-start事情被触发并且在property:ro.crypto.state不同值的情况下start zygoe
on zygote-start && property:ro.crypto.state=unencrypted //zygote-start事件被触发,并且系统属性ro.crypto.state的值为unencrypted
on zygote-start && property:ro.crypto.state=unsupported //设备不支持加密
on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file //设备启用了文件加密
	exec_start update_verifier_nonencrypted
    start statsd
    start netd
    start zygote
    start zygote_secondary

在init.zygote64.rc文件中

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server //--zygote告诉app_process以zygote模式运行,--start-system-server则指示在zygote启动后,它将启动系统服务
   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 exec_background - system system -- /system/bin/vdc volume abort_fuse
   onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart media.tuner
    onrestart restart netd
    onrestart restart wificond
    task_profiles ProcessCapacityHigh
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

在解析完rc文件后,会向init的ActionManager添加内置动作和事件触发器,比如am.QueueEventTrigger("early-init")和am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers")等。上面的代码执行start zygote命令,会走到/system/core/init/builtins.cpp文件中,根据映射表执行do_start函数。
在builtins.cpp文件中

static const Map builtin_functions = {
{"start",                   {1,     1,    {false,  do_start}}}
}
static Result<Success> do_start(const BuiltinArguments& args) {
    Service* svc = ServiceList::GetInstance().FindService(args[1]); //根据解析到的参数,从解析的服务列表中查询对应的服务。
    if (!svc) return Error() << "service " << args[1] << " not found";
    if (auto result = svc->Start(); !result) { //调用查询到的服务的 start函数启动对应的服务
        return Error() << "Could not start service: " << result.error();
    }
    return Success();
}

do_start函数直接从保存的服务列表中,根据服务名称查询对应的服务,然后调用/system/core/init/service.cpp中的Start函数启动服务。
在service.cpp文件中

Result<Success> Service::Start() {
    pid_t pid = -1;
    if (namespaces_.flags) {
        pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr);
    } else {
        pid = fork();
    }
	if (pid == 0) {
	    umask(077);
	    RunService(override_mount_namespace, descriptors, std::move(pipefd));
	    _exit(127);
    }
}

void Service::RunService() {
    if (!ExpandArgsAndExecv(args_, sigstop_)) {
        PLOG(ERROR) << "cannot execv('" << args_[0]
                    << "'). See the 'Debugging init' section of init's README.md for tips";
    }
}

static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigstop) {
    std::vector<char*> c_strings;
	c_strings.push_back(const_cast<char*>(args[0].data()));
	return execv(c_strings[0], c_strings.data()) == 0; //rong 执行c_string[0]对应的文件,比如启动zygote64
}

ExpandArgsAndExecv这个函数获取待执行文件的路径,然后调用execv执行待执行的具体文件,同时将参数传递过去。 从return execv(c_strings[0], c_strings.data()) == 0;起函数的流程就走到了/system/bin/app_process64这个可执行文件的main函数中, app_process64这个可运行文件的源文件是frameworks/base/cmds/app_process/app_main.cpp
2,zygote的启动
c++代码 /frameworks/base/cmds/app_process/app_main.cpp
java代码 /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
在app_main.cpp文件中的main函数中

int main(int argc, char* const argv[]) {
	AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); //创建一个AppRuntime的实例runtime
	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; //zygote进程此时由app_process进程被改名为zygote进程,static const char ZYGOTE_NICE_NAME[] = "zygote";
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        }  else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        }
    }
	if (zygote) { //zygote为true,表示正在启动的进程为zygote进程。
	    runtime.start("com.android.internal.os.ZygoteInit", args, zygote);//执行AndroidRuntime::start函数
    } else if (className) { //启动app
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    }
}

在AndroidRuntime.cpp文件中的main函数中

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) {
	JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) { //创建虚拟机
        return;
    }
    onVmCreated(env);
    if (startReg(env) < 0) { //注册android常用的jni
        ALOGE("Unable to register all android natives\n");
        return;
    }
	
	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);
	}
	//查找zygoteInit.main,将zygote带入java世界
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);  //查找ZygoteInit类
	jmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V"); //获取main函数
	env->CallStaticVoidMethod(startClass, startMeth, strArray);  //调用ZygoteInit.java的main函数
    free(slashClassName);
}

经过上面的代码就可以走到ZygoteInit.java类中的main函数。