在Android中,zygote是整个系统建立新进程的核心进程。zygote进程在内部会先启动Dalvik虚拟机,继而加载一些必要的系统资源和系统类,最后进入一种监听状态。在以后的运做中,当其余系统模块(好比 AMS)但愿建立新进程时,只需向zygote进程发出请求,zygote进程监听到该请求后,会相应地fork出新的进程,因而这个新进程在初生之时,就先天具备了本身的Dalvik虚拟机以及系统资源。java
关键类 | 路径 |
---|---|
init.rc | system/core/rootdir/init.rc |
init.cpp | system/core/init/init.cpp |
init.zygote64.rc | system/core/rootdir/init.zygote64.rc |
builtins.cpp | system/core/init/builtins.cpp |
service.cpp | system/core/init/service.cpp |
app_main.cpp | frameworks/base/cmds/app_process/app_main.cpp |
AndroidRuntime.cpp | frameworks/base/core/jni/AndroidRuntime.cpp |
JniInvocation.cpp | libnativehelper/JniInvocation.cpp |
ZygoteInit.java | frameworks/base/core/java/com/android/internal/os/ZygoteInit.java |
ZygoteServer.java | frameworks/base/core/java/com/android/internal/os/ZygoteServer.java |
在Android系统中,JavaVM(Java虚拟机)、应用程序进程以及运行系统的关键服务的SystemServer进程都是由Zygote进程来建立的,咱们也将它称为孵化器。它经过fock(复制进程)的形式来建立应用程序进程和SystemServer进程,因为Zygote进程在启动时会建立JavaVM,所以经过fock而建立的应用程序进程和SystemServer进程能够在内部获取一个JavaVM的实例拷贝。android
在分析init进程时,咱们知道init进程启动后,会解析init.rc文件,而后建立和加载service字段指定的进程。zygote进程就是以这种方式,被init进程加载的。ios
在system/core/rootdir/init.rc的开始部分,能够看到:编程
import /init.environ.rc import /init.usb.rc import /init.${ro.hardware}.rc import /vendor/etc/init/hw/init.${ro.hardware}.rc import /init.usb.configfs.rc import /init.${ro.zygote}.rc // ${ro.zygote}由厂商定义,与平台相关 on early-init # Set init and its forked children's oom_adj. write /proc/1/oom_score_adj -1000
从以前分析的init篇中咱们知道,在不一样的平台(3二、64及64_32)上,init.rc将包含不一样的zygote.rc文件。在system/core/rootdir目录下,有init.zygote32_64.rc、init.zyote64.rc、 init.zyote32.rc、init.zygote64_32.rc。 数组
✨ <font color=#87CEFA>init.zygote32.rc</font>:zygote 进程对应的执行程序是 app_process (纯 32bit 模式)
✨ <font color=#87CEFA>init.zygote64.rc</font>:zygote 进程对应的执行程序是 app_process64 (纯 64bit 模式)
✨ <font color=#87CEFA>init.zygote32_64.rc</font>:启动两个 zygote 进程 (名为 zygote 和 zygote_secondary),对应的执行程序分别是 app_process32 (主模式)、app_process64
✨ <font color=#87CEFA>init.zygote64_32.rc</font>:启动两个 zygote 进程 (名为 zygote 和 zygote_secondary),对应的执行程序分别是 app_process64 (主模式)、app_process32缓存
为何要定义这么多种状况呢?直接定义一个不就行了,这主要是由于Android 5.0之后开始支持64位程序,为了兼容32位和64位才这样定义。不一样的zygote.rc内容大体相同,主要区别体如今启动的是32位,仍是64位的进程。init.zygote32_64.rc和init.zygote64_32.rc会启动两个进程,且存在主次之分。安全
这里拿64位处理器为例,init.zygote64_32.rc的代码以下所示:app
// 进程名称是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 指当进程重启时执行后面的命令 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 // 建立子进程时,向 /dev/cpuset/foreground/tasks 写入pid writepid /dev/cpuset/foreground/tasks // 另外一个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
定义了service,确定有地方调用 start zygote。在以前init解析的博客中,咱们分析过init进程的启动。init进程启动的最后,会产生”late-init”事件。框架
// Don't mount filesystems or start core system services in charger mode. std::string bootmode = GetProperty("ro.bootmode", ""); if (bootmode == "charger") { am.QueueEventTrigger("charger"); } else { am.QueueEventTrigger("late-init"); }
对应于init.rc配置文件中,咱们找到以下代码:less
# Mount filesystems and start core system services. on late-init trigger early-fs ... ... # Now we can start zygote for devices with file based encryption trigger zygote-start // 触发了zygote-start事件后,就会启动zygote进程 ... ...
对应于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对应的映射关系定义于system/core/init/builtins.cpp中 start netd // 调用start对应的处理函数,启动名为zygote的服务(传入前文init.zygote.rc中定义的参数) 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
start命令有一个对应的执行函数do_start,定义在platform/system/core/init/builtins.cpp中
const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max(); // clang-format off static const Map builtin_functions = { ... ... {"start", {1, 1, do_start}}, ... ... }; // clang-format on return builtin_functions; }
咱们来看下do_start():
static int do_start(const std::vector<std::string>& args) { // 找到zygote service对应信息 Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]); if (!svc) { LOG(ERROR) << "do_start: Service " << args[1] << " not found"; return -1; } if (!svc->Start()) // 启动对应的进程 return -1; return 0; }
do_start首先是经过FindServiceByName去service数组中遍历,根据名字匹配出对应的service,而后调用service的Start函数。
最后,咱们来看看service.cpp中定义Start函数:
bool Service::Start() { ... ... pid_t pid = -1; if (namespace_flags_) { pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr); } else { pid = fork(); // 从init进程中,fork出zygote进程 } ... ... }
Start函数主要是fork出一个新进程,而后执行service对应的二进制文件,并将参数传递进去。那么下面咱们以init.zygote64.rc为例进行分析。
从上面咱们分析的init.zygote64.rc能够看出,zygote64启动文件的地址为app_process64。app_process64对应的代码定义在frameworks/base/cmds/app_process中,
咱们来看看对应的Android.mk: frameworks/base/cmds/app_process
LOCAL_PATH:= $(call my-dir) ... ... app_process_src_files := \ app_main.cpp \ ... ... LOCAL_MODULE:= app_process LOCAL_MULTILIB := both LOCAL_MODULE_STEM_32 := app_process32 LOCAL_MODULE_STEM_64 := app_process64
其实无论是app_process、app_process32仍是app_process64,对应的源文件都是app_main.cpp。
接下来咱们就看看app_process对应的main函数,该函数定义于app_main.cpp中。
在app_main.cpp的main函数中,主要作的事情就是参数解析. 这个函数有两种启动模式:
✨ 一种是zygote模式,也就是初始化zygote进程,传递的参数有--start-system-server --socket-name=zygote,前者表示启动SystemServer,后者指定socket的名称(Zygote64_32)。
✨ 一种是application模式,也就是启动普通应用程序,传递的参数有class名字以及class带的参数。
二者最终都是调用AppRuntime对象的start函数,加载ZygoteInit或RuntimeInit两个Java类,并将以前整理的参数传入进去。
咱们这里暂时只讲解ZygoteInit的加载流程。
int main(int argc, char* const argv[]) { // 将参数argv放到argv_String字符串中,而后打印出来 // 以前start zygote传入的参数是 -Xzygote /system/bin --zygote --start-system-server 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定义于app_main.cpp中,继承自AndroidRuntime // 就是对Android运行环境的一种抽象,相似于java虚拟机对Java程序的做用 AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); // Process command line arguments // ignore argv[0] argc--; argv++; // 这两个参数是Java程序须要依赖的Jar包,至关于import const char* spaced_commands[] = { "-cp", "-classpath" }; // 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++) { // 将spaced_commands中的参数额外加入VM 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) { // 比较参数是不是spaced_commands中的参数 if (strcmp(argv[i], spaced_commands[j]) == 0) { known_command = true; ALOGV("app_process main found known command '%s'", argv[i]); } } // 若是参数第一个字符是'-',直接跳出循环,以前传入的第一个参数是 -Xzygote,因此执行到这儿就跳出了 if (argv[i][0] != '-') { break; } if (argv[i][1] == '-' && argv[i][2] == 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]); } // Parse runtime arguments. Stop at first unrecognized option. // 从这里其实能够看出,经过app_main能够启动zygote、system-server及普通apk进程 // 这个能够经过init.rc来配置 bool zygote = false; bool startSystemServer = false; bool application = false; String8 niceName; // app_process的名称改成zygote String8 className; // 启动apk进程时,对应的类名 ++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) { startSystemServer = true; // init.zygote.rc中定义了该字段,启动zygote后会启动system-server } else if (strcmp(arg, "--application") == 0) { application = true; // 表示是application启动模式,也就是普通应用程序 } else if (strncmp(arg, "--nice-name=", 12) == 0) { niceName.setTo(arg + 12); // 进程别名,能够本身指定进程名 } else if (strncmp(arg, "--", 2) != 0) { className.setTo(arg); // 与--application配置,启动指定的类,application启动的class 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 ... ... } else { // zygote启动模式 // We're in zygote mode. maybeCreateDalvikCache(); // 建立Dalvik的缓存目录并定义权限 if (startSystemServer) { // 增长start-system-server参数,默认启动zygote后,就会启动system_server args.add(String8("start-system-server")); } char prop[PROP_VALUE_MAX]; // 获取平台对应的abi信息 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="); // 参数须要制定abi 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.add(String8(argv[i])); // 将剩下的参数加入args } } if (!niceName.isEmpty()) { // 将app_process的进程名,替换为niceName runtime.setArgv0(niceName.string(), true /* setProcName */); } if (zygote) { // 调用Runtime的start函数, 启动ZygoteInit runtime.start("com.android.internal.os.ZygoteInit", args, zygote); } else if (className) { // 启动zygote没有进入这个分支 // 但这个分支说明,经过配置init.rc文件,实际上是能够不经过zygote来启动一个进程 // 若是是application启动模式,则加载RuntimeInit runtime.start("com.android.internal.os.RuntimeInit", args, zygote); } else { // error状况 fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); } }
因为AppRuntime继承自AndroidRuntime,且没有重写start方法,所以zygote的流程进入到了AndroidRuntime.cpp。
接下来,咱们来看看AndroidRuntime的start函数的流程。
/* * 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) { ... ... // 打印一些日志,获取ANDROID_ROOT环境变量 /* start the virtual machine */ JniInvocation jni_invocation; jni_invocation.Init(NULL); // 初始化JNI,加载libart.so JNIEnv* env; // 建立虚拟机,其中大多数参数由系统属性决定 // 最终,startVm利用JNI_CreateJavaVM建立出虚拟机 if (startVm(&mJavaVM, &env, zygote) != 0) { return; } // 回调AppRuntime的onVmCreated函数 // 对于zygote进程的启动流程而言,无实际操做,表示虚拟建立完成,可是里面是空实现 onVmCreated(env); ... ... }
这边咱们跟一下jni_invocation.Init():libnativehelper/JniInvocation.cpp
Init函数主要做用是初始化JNI,具体工做是首先经过dlopen加载libart.so得到其句柄,而后调用dlsym从libart.so中找到JNI_GetDefaultJavaVMInitArgs、JNI_CreateJavaVM、JNI_GetCreatedJavaVMs三个函数地址,赋值给对应成员属性,这三个函数会在后续虚拟机建立中调用。
bool JniInvocation::Init(const char* library) { #ifdef __ANDROID__ char buffer[PROP_VALUE_MAX]; #else char* buffer = NULL; #endif library = GetLibrary(library, buffer); // 默认返回 libart.so // Load with RTLD_NODELETE in order to ensure that libart.so is not unmapped when it is closed. // This is due to the fact that it is possible that some threads might have yet to finish // exiting even after JNI_DeleteJavaVM returns, which can lead to segfaults if the library is // unloaded. const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE; /* * 1.dlopen功能是以指定模式打开指定的动态连接库文件,并返回一个句柄 * 2.RTLD_NOW表示须要在dlopen返回前,解析出全部未定义符号,若是解析不出来,在dlopen会返回NULL * 3.RTLD_NODELETE表示在dlclose()期间不卸载库,而且在之后使用dlopen()从新加载库时不初始化库中的静态变量 */ handle_ = dlopen(library, kDlopenFlags); // 获取libart.so的句柄 if (handle_ == NULL) { // 获取失败打印错误日志并尝试再次打开libart.so if (strcmp(library, kLibraryFallback) == 0) { // Nothing else to try. ALOGE("Failed to dlopen %s: %s", library, dlerror()); return false; } // Note that this is enough to get something like the zygote // running, we can't property_set here to fix this for the future // because we are root and not the system user. See // RuntimeInit.commonInit for where we fix up the property to // avoid future fallbacks. http://b/11463182 ALOGW("Falling back from %s to %s after dlopen error: %s", library, kLibraryFallback, dlerror()); library = kLibraryFallback; handle_ = dlopen(library, kDlopenFlags); if (handle_ == NULL) { ALOGE("Failed to dlopen %s: %s", library, dlerror()); return false; } } /* * 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; }
其次,咱们再跟一下startVm():
这个函数特别长,可是里面作的事情很单一,其实就是从各类系统属性中读取一些参数,而后经过addOption设置到AndroidRuntime的mOptions数组中存起来,另外就是调用以前从libart.so中找到JNI_CreateJavaVM函数,并将这些参数传入,因为本篇主要讲zygote启动流程,所以关于虚拟机的实现就不深刻探究了。
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote) { JavaVMInitArgs initArgs; char propBuf[PROPERTY_VALUE_MAX]; char stackTraceFileBuf[sizeof("-Xstacktracefile:")-1 + PROPERTY_VALUE_MAX]; char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX]; ... ... /* route exit() to our handler */ 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; /* * Initialize the VM. * * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread. * If this call succeeds, the VM is ready, and we can start issuing * JNI calls. */ if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) { // 调用libart.so的JNI_CreateJavaVM函数 ALOGE("JNI_CreateJavaVM failed\n"); return -1; } return 0; }
咱们回到AndroidRuntime的start函数。初始化JVM后,接下来就会调用startReg函数。
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { ... ... /* 01. 建立Java虚拟机*/ /* * Register android functions. */ if (startReg(env) < 0) { // 注册JNI函数 ALOGE("Unable to register all android natives\n"); return; } ... ... }
startReg首先是设置了Android建立线程的处理函数,而后建立了一个200容量的局部引用做用域,用于确保不会出现OutOfMemoryException,最后就是调用register_jni_procs进行JNI注册。
咱们跟进startReg():
/* * 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.) */ // 定义Android建立线程的func:javaCreateThreadEtc,这个函数内部是经过Linux的clone来建立线程的 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); // 建立一个200容量的局部引用做用域,这个局部引用其实就是局部变量 if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) { // 注册JNI函数 env->PopLocalFrame(NULL); return -1; } env->PopLocalFrame(NULL); // 释放局部引用做用域 //createJavaThread("fubar", quickTest, (void*) "hello"); return 0; }
从上述代码能够看出,startReg函数中主要是经过register_jni_procs来注册JNI函数。其中,gRegJNI是一个全局数组,该数组的定义以下:
static const RegJNIRec gRegJNI[] = { // 里面就是一堆的函数指针 REG_JNI(register_com_android_internal_os_RuntimeInit), REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit), REG_JNI(register_android_os_SystemClock), REG_JNI(register_android_util_EventLog), REG_JNI(register_android_util_Log), ... ... };
咱们挑一个register_com_android_internal_os_ZygoteInit_nativeZygoteInit,这其实是自定义JNI函数并进行动态注册的标准写法,
内部是调用JNI的RegisterNatives,这样注册后,Java类ZygoteInit的native方法nativeZygoteInit就会调用com_android_internal_os_ZygoteInit_nativeZygoteInit函数。
int register_com_android_internal_os_ZygoteInit_nativeZygoteInit(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)); }
REG_JNI对应的宏定义及RegJNIRec结构体的定义为:
#ifdef NDEBUG #define REG_JNI(name) { name } struct RegJNIRec { int (*mProc)(JNIEnv*); }; #else #define REG_JNI(name) { name, #name } struct RegJNIRec { int (*mProc)(JNIEnv*); const char* mName; }; #endif
根据宏定义能够看出,宏REG_JNI将获得函数名;定义RegJNIRec数组时,函数名被赋值给RegJNIRec结构体,因而每一个函数名被强行转换为函数指针。
所以,register_jni_procs的参数就是一个函数指针数组,数组的大小和JNIEnv。
咱们来跟进一下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) { // 调用mProc #ifndef NDEBUG ALOGD("----------!!! %s failed to load\n", array[i].mName); #endif return -1; } } return 0; }
结合前面的分析,容易知道register_jni_procs函数,实际上就是调用函数指针(mProc)对应的函数,以进行实际的JNI函数注册。
继续分析AndroidRuntime.cpp的start函数:
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { ... ... /* 01. 建立Java虚拟机*/ /* 02. 注册JNI函数 */ /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */ // 替换string为实际路径 // 例如:将 "com.android.internal.os.ZygoteInit" 替换为 "com/android/internal/os/ZygoteInit" char* slashClassName = toSlashClassName(className != NULL ? 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"); // 经过反射找到ZygoteInit的main函数 if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */ } else { env->CallStaticVoidMethod(startClass, startMeth, strArray); // 调用ZygoteInit的main函数 ... ... } } 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"); }
能够看到,在AndroidRuntime的最后,将经过反射调用ZygoteInit的main函数。至此,zygote进程进入了java世界。
其实咱们仔细想想,就会以为zygote的整个流程其实是很是符合实际状况的。
✨✨ 在Android中,每一个进程都运行在对应的虚拟机上,所以zygote首先就负责建立出虚拟机。
✨✨ 而后,为了反射调用java代码,必须有对应的JNI函数,因而zygote进行了JNI函数的注册。
✨✨ 当一切准备稳当后,zygote进程才进入到了java世界。
如今咱们跟进ZygoteInit.java的main函数。
public static void main(String argv[]) { //建立ZygoteServer对象 ZygoteServer zygoteServer = new ZygoteServer(); // Mark zygote start. This ensures that thread creation will throw // an error. // 调用native函数,确保当前没有其它线程在运行 // 主要仍是处于安全的考虑 ZygoteHooks.startZygoteNoThreadCreation(); // Zygote goes into its own process group. try { Os.setpgid(0, 0); } catch (ErrnoException ex) { throw new RuntimeException("Failed to setpgid(0,0)", ex); } final Runnable caller; try { ... ... RuntimeInit.enableDdms(); boolean startSystemServer = false; String socketName = "zygote"; String abiList = null; boolean enableLazyPreload = false; // 解析参数,获得上述变量的值 for (int i = 1; i < argv.length; i++) { if ("start-system-server".equals(argv[i])) { startSystemServer = true; } else if ("--enable-lazy-preload".equals(argv[i])) { enableLazyPreload = 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."); } zygoteServer.registerServerSocket(socketName); // 注册server socket // In some configurations, we avoid preloading resources and classes eagerly. // In such cases, we will preload things prior to our first fork. if (!enableLazyPreload) { ... ... preload(bootTimingsTraceLog); // 默认状况,预加载信息 ... ... } else { // 如注释,延迟预加载 // 变动Zygote进程优先级为NORMAL级别 // 第一次fork时才会preload Zygote.resetNicePriority(); } // Do an initial gc to clean up after startup bootTimingsTraceLog.traceBegin("PostZygoteInitGC"); gcAndFinalize(); // 若是预加载了,颇有必要GC一波 bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC ... ... // Zygote process unmounts root storage spaces. Zygote.nativeUnmountStorageOnInit(); // Set seccomp policy // 加载seccomp的过滤规则 // 全部 Android 软件都使用系统调用(简称为 syscall)与 Linux 内核进行通讯 // 内核提供许多特定于设备和SOC的系统调用,让用户空间进程(包括应用)能够直接与内核进行交互 // 不过,其中许多系统调用Android未予使用或未予正式支持 // 经过seccomp,Android可以使应用软件没法访问未使用的内核系统调用 // 因为应用没法访问这些系统调用,所以,它们不会被潜在的有害应用利用 // 该过滤器安装到zygote进程中,因为全部Android应用均衍生自该进程 // 于是会影响到全部应用 Seccomp.setPolicy(); /// M: Added for BOOTPROF addBootEvent("Zygote:Preload End"); /// @} ZygoteHooks.stopZygoteNoThreadCreation(); // 容许有其它线程了 if (startSystemServer) { Runnable r = forkSystemServer(abiList, socketName, zygoteServer); // fork出system server // {@code r == null} in the parent (zygote) process, and {@code r != null} in the // child (system_server) process. if (r != null) { r.run(); return; } } Log.i(TAG, "Accepting command socket connections"); // The select loop returns early in the child process after a fork and // loops forever in the zygote. caller = zygoteServer.runSelectLoop(abiList); // zygote进程进入无限循环,处理请求 } catch (Throwable ex) { ... ... } finally { zygoteServer.closeServerSocket(); } // We're in the child process and have exited the select loop. Proceed to execute the // command. if (caller != null) { caller.run(); } }
上面是ZygoteInit的main函数的主干部分,除了安全相关的内容外,最主要的工做就是注册server socket、预加载、启动system server及进入无限循环处理请求消息。
接下来咱们分四部分分别讨论!
Android O将server socket相关的工做抽象到ZygoteServer.java中了。咱们来看看其中的registerZygoteSocket函数:
/** * Registers a server socket for zygote command connections * * @throws RuntimeException when open fails */ void registerServerSocket(String socketName) { if (mServerSocket == null) { int fileDesc; // ANDROID_SOCKET_PREFIX为"ANDROID_SOCKET_" // 此处的socket name,就是zygote final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; try { // 还记得么?在init.zygote.rc被加载时,指定了名为zygote的socket // 在进程被建立时,就会建立对应的文件描述符,并加入到环境变量中 // 所以,此时能够取出对应的环境变量 String env = System.getenv(fullSocketName); fileDesc = Integer.parseInt(env); } catch (RuntimeException ex) { throw new RuntimeException(fullSocketName + " unset or invalid", ex); } try { FileDescriptor fd = new FileDescriptor(); fd.setInt$(fileDesc); // 获取zygote socket的文件描述符 mServerSocket = new LocalServerSocket(fd); // 将socket包装成一个server socket } catch (IOException ex) { throw new RuntimeException( "Error binding to local socket '" + fileDesc + "'", ex); } } }
咱们跟踪LocalServerSocket():
public LocalServerSocket(String name) throws IOException { impl = new LocalSocketImpl(); impl.create(LocalSocket.SOCKET_STREAM); // 建立SOCKET_STREAM类型的AF_UNIX socket localAddress = new LocalSocketAddress(name); impl.bind(localAddress); // 绑定到指定地址 impl.listen(LISTEN_BACKLOG); // 开始监听 }
咱们看看预加载的内容:
static void preload(TimingsTraceLog bootTimingsTraceLog) { ... ... beginIcuCachePinning(); // Pin ICU Data, 获取字符集转换资源等 ... ... preloadClasses(); // 读取文件system/etc/preloaded-classes,而后经过反射加载对应的类 // 通常由厂商来定义,有时须要加载数千个类,启动慢的缘由之一 ... ... preloadResources(); // 负责加载一些经常使用的系统资源 ... ... nativePreloadAppProcessHALs(); ... ... preloadOpenGL(); // 图形相关 ... ... preloadSharedLibraries(); // 一些必要库 preloadTextResources(); // 语言相关的字符信息 // Ask the WebViewFactory to do any initialization that must run in the zygote process, // for memory sharing purposes. WebViewFactory.prepareWebViewInZygote(); endIcuCachePinning(); warmUpJcaProviders(); // 安全相关的 Log.d(TAG, "end preload"); sPreloadComplete = true; }
为了让系统实际运行时更加流畅,在zygote启动时候,调用preload函数进行了一些预加载操做。Android 经过zygote fork的方式建立子进程。zygote进程预加载这些类和资源,在fork子进程时,仅须要作一个复制便可。
这样能够节约子进程的启动时间。同时,根据fork的copy-on-write机制可知,有些类若是不作改变,甚至都不用复制,子进程能够和父进程共享这部分数据,从而省去很多内存的占用。
再来看看启动System Server的流程:
/** * Prepare the arguments and forks for the system server process. * * Returns an {@code Runnable} that provides an entrypoint into system_server code in the * child process, and {@code null} in the parent. */ private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) { 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, OsConstants.CAP_WAKE_ALARM ); /* 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 */ String args[] = { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,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 { // 将上面准备的参数,按照ZygoteConnection的风格进行封装 parsedArgs = new ZygoteConnection.Arguments(args); ZygoteConnection.applyDebuggerSystemProperty(parsedArgs); ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs); /* Request to fork the system server process */ pid = Zygote.forkSystemServer( // 经过fork"分裂"出system_server 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) { // 处理32_64和64_32的状况 if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } // fork时会copy socket,system server须要主动关闭 zygoteServer.closeServerSocket(); // system server进程处理本身的工做 return handleSystemServerProcess(parsedArgs); } return null; }
建立出SystemServer进程后,zygote进程调用ZygoteServer中的函数runSelectLoop,处理server socket收到的命令。
/** * 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. */ Runnable runSelectLoop(String abiList) { ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>(); ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); // 首先将server socket加入到fds fds.add(mServerSocket.getFileDescriptor()); peers.add(null); while (true) { // 每次循环,都从新建立须要监听的pollFds 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[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; } // server socket最早加入fds, 所以这里是server socket收到数据 if (i == 0) { // 收到新的创建通讯的请求,创建通讯链接 ZygoteConnection newPeer = acceptCommandPeer(abiList); // 加入到peers和fds, 即下一次也开始监听 peers.add(newPeer); fds.add(newPeer.getFileDesciptor()); } else { //其它通讯链接收到数据 ... ... } } } }
从上面代码可知,初始时fds中仅有server socket,所以当有数据到来时,将执行i等于0的分支。此时,显然是须要建立新的通讯链接,所以acceptCommandPeer将被调用。
咱们看看acceptCommandPeer函数:
/** * Waits for and accepts a single command connection. Throws * RuntimeException on failure. */ private ZygoteConnection acceptCommandPeer(String abiList) { try { // socket编程中,accept()调用主要用在基于链接的套接字类型,好比SOCK_STREAM和SOCK_SEQPACKET // 它提取出所监听套接字的等待链接队列中第一个链接请求,建立一个新的套接字,并返回指向该套接字的文件描述符 // 新创建的套接字不在监听状态,原来所监听的套接字的状态也不受accept()调用的影响 return createNewConnection(mServerSocket.accept(), abiList); } catch (IOException ex) { throw new RuntimeException( "IOException during accept()", ex); } } protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList) throws IOException { return new ZygoteConnection(socket, abiList); }
从上面的代码,能够看出acceptCommandPeer调用了server socket的accpet函数。因而当新的链接创建时,zygote将会建立出一个新的socket与其通讯,并将该socket加入到fds中。所以,一旦通讯链接创建后,fds中将会包含有多个socket。
当poll监听到这一组sockets上有数据到来时,就会从阻塞中恢复。因而,咱们须要判断究竟是哪一个socket收到了数据。
在runSelectLoop中采用倒序的方式轮询。因为server socket第一个被加入到fds,所以最后轮询到的socket才须要处理新建链接的操做;其它socket收到数据时,仅须要调用zygoteConnection的runonce函数执行数据对应的操做。若一个链接处理完全部对应消息后,该链接对应的socket和链接等将被移除。
Zygote启动流程到此结束,Zygote进程共作了以下几件事
🔨 1. 建立AppRuntime并调用其start方法,启动Zygote进程。
🔨 2. 建立JavaVM并为JavaVM注册JNI.
🔨 3. 经过JNI调用ZygoteInit的main函数进入Zygote的Java框架层。
🔨 4. 经过registerZygoteSocket函数建立服务端Socket,预加载类和资源,并经过runSelectLoop函数等待如ActivityManagerService等的请求。
🔨 5. 启动SystemServer进程。