Android(安卓)-- 系统进程Zygote的启动分析
Android -- 系统进程Zygote的启动分析
我们知道,Android系统是基于Linux内核的。Linux中,所有的进程都是由init进程创建出来的,即所有的进程都是直接或间接被init进程fork产生的。Android进程的孵化器Zygote同样如此,它在系统启动过程中,被init进程创建出来。Android系统启动时,会解析init.rc初始化文件,我们先看init.rc中对Zygote配置文件的处理:
import /init.${ro.zygote}.rc
可以看到,此处配置文件的导入,是由ro.zygote属性控制的,由此来引入不同的文件。出现这种情况的原因是,Android 5.0以后,Android开始支持64位编译,Zygote进程也随之引入了32/64位的区别。所以,这里通过ro.zygote属性来控制启动不同版本的Zygote进程。
ro.zygote属性会有四种不同的值:
- zygote32:代表32位模式
- zygote32_64:代表32模式为主,64位模式为辅
- zygote64:代表64位模式
- zygote64_32:代表64模式为主,32位模式为辅
在init.rc同级目录下一共4个和Zygote进程有关的rc配置文件:
双模式下,Zygote的配置文件下会有两个服务声明,这里以init.zygote64_32.rc为例:
service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote class main 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 writepid /dev/cpuset/foreground/tasksservice zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary class main socket zygote_secondary stream 660 root system onrestart restart zygote writepid /dev/cpuset/foreground/tasks
这两个服务声明最大的区别就是对应的可执行文件不一样。我们分析还是以纯32位模式为例,来看Zygote进程的启动过程。
纯32位模式下启动Zygote进程的命令如下:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main 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
关键字service告诉我们要创建一个名为Zygote的进程,并通过应用程序/system/bin/app_process来启动它;之后的内容是此次启动传入的参数:
- -Xzygote:jvm使用的参数
- /system/bin:一个未被使用的父目录
- --zygote、--start--system--server:启动Zygote进程要使用的参数
- class main:将Zygote声明为主要服务,用于后续class_start main启动服务用
- socket xxx:表示需要为此服务创建一个socket
- onrestart xxx:当Zygote服务重启时,需要执行的命令
socket关键字说明该进程需要创建一个套接字资源用于进程间通信,类型是unix domain socket,权限设置为660。onrestart关键字描述的都是该进程重启时需要执行的命令操作。
这里再介绍下app_process启动参数的格式:
- 虚拟机参数:以"-"开头。启动虚拟机时传递给虚拟机使用
- 运行目录:程序的运行目录,通常是/system/bin
- 参数:以"--"开头。"--zygote"表示要启动zygote进程。参数"--application"表示以普通进程的方式执行Java代码
- Java类:将要执行的Java类,它必须有main()方法;使用"--zygote"时,不会执行这个类,而是固定执行ZygoteInit类
在Init进程解析init.rc时,会解析并启动这个服务,最后通过系统调用exec()去执行zygote进程对应的应用程序。
它对应的文件是/frameworks/base/cmds/app_process/app_main.cpp;直接看它的main()函数:
int main(int argc, char* const argv[]){ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { // Older kernels don't understand PR_SET_NO_NEW_PRIVS and return // EINVAL. Don't die on such kernels. if (errno != EINVAL) { LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno)); return 12; } } //AppRuntime是AndroidRuntime的子类,这里初始化runtime对象时Androidruntime中的gCurRuntime变量会被初始化为AppRuntime对象:runtime 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) {//忽略第一个参数:-Xzygote const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) { //由参数列表可知,该项成立 zygote = true; 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; } } Vector args;//启动Zygote进程时使用的参数列表 if (!className.isEmpty()) {//非Zygote模式 // 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);//如果不是zygote模式,则把要启动的Java类的名字保存到mClassName字段中 } else {//Zygote模式 // We're in zygote mode. maybeCreateDalvikCache(); if (startSystemServer) { 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. for (; i < argc; ++i) { args.add(String8(argv[i]));//添加剩余的参数 } } if (!niceName.isEmpty()) {//设置进程名 runtime.setArgv0(niceName.string()); set_process_name(niceName.string()); } if (zygote) {//zygote为TRUE runtime.start("com.android.internal.os.ZygoteInit", args, zygote);//附带参数列表,在Zygote模式下,同过AndroidRuntime::start()启动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."); return 10; }}
首先我们创建了一个AppRuntime实例runtime,它是AndroidRuntime的子类,重写了一些AndroidRuntime的方法。
app_process除了能启动Zygote进程外,还能启动某个系统的Java类(非zygote模式下)。我们经常使用的"am"命令就是通过app_process实现的。
runtime.start()实际是调用父类的同名方法AndroidRuntime::start()函数,分析它是怎么启动ZygoteInit的:
/* * 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& options, bool zygote){ ALOGD(">>>>>> START %s uid %d <<<<<<\n", className != NULL ? className : "(unknown)", getuid()); static const String8 startSystemServer("start-system-server"); /* * 'startSystemServer == true' means runtime is obsolete and not run from * init.rc anymore, so we print out the boot start event here. */ for (size_t i = 0; i < options.size(); ++i) { if (options[i] == startSystemServer) { /* 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))); } } //获取系统根目录,缺省是/system,如果没有/system目录,Zygote进程就会终止。系统目录是在Init进程中创建的 const char* rootDir = getenv("ANDROID_ROOT"); 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); } //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; if (startVm(&mJavaVM, &env, zygote) != 0) {//1、启动虚拟机 return; } onVmCreated(env); /* * Register android functions. */ if (startReg(env) < 0) { //2、注册所需的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);//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 { jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V");//通过JNI获取com.android.internal.os.ZygoteInit类的main()方法的jmethodID值 if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */ } else { env->CallStaticVoidMethod(startClass, startMeth, strArray);//通过JNI调用com.android.internal.os.ZygoteInit类的main()方法,进入Java层代码#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");}
AndroidRuntime是Android底层一个很重要的类,它负责启动JVM和Java类。AndroidRuntime在一个进程中只会有一个实例,在构造时,它的实例会保存在全局变量gCurRuntime中。
在start()函数中首先会获取系统根目录,然后调用startVMm()启动虚拟机。onVmCreated()函数在zygote模式下,并没有实际用处,但我们还是有必要看下它的处理,该函数定义在AppRuntime中:
virtual void onVmCreated(JNIEnv* env) { if (mClassName.isEmpty()) {//zygote模式下,mClassName为空,直接return return; // Zygote. Nothing to do here. } /* * This is a little awkward because the JNI FindClass call uses the * class loader associated with the native method we're executing in. * If called in onStarted (from RuntimeInit.finishInit because we're * launching "am", for example), FindClass would see that we're calling * from a boot class' native method, and so wouldn't look for the class * we're trying to look up in CLASSPATH. Unfortunately it needs to, * because the "am" classes are not boot classes. * * The easiest fix is to call FindClass here, early on before we start * executing boot class Java code and thereby deny ourselves access to * non-boot classes. */ char* slashClassName = toSlashClassName(mClassName.string());//转换Java类的路径字符串 mClass = env->FindClass(slashClassName);//在当前的虚拟机环境下,根据类名查找这个类 if (mClass == NULL) { ALOGE("ERROR: could not find class '%s'\n", mClassName.string()); } free(slashClassName); mClass = reinterpret_cast(env->NewGlobalRef(mClass)); }
如果当前的启动模式不是zygote,那我们在通过app_process启动某个类时会为它指定一个要启动的类。首先,会转换指定的类的路径名,并在当前的虚拟机环境下查找这个类。这表明app_process将要调用的Java类必须是系统类。如果当前的启动模式是zygote,则直接返回。随后调用startReg()注册系统的JNI函数。
最后会将启动类用到的参数封装到strArray数组,并通过JNI的方式在native代码中直接调用ZygoteInit.java的main()函数,处理流程转而进入Java层。
ZygoteInit类是zygote进程的启动类,看它的main()函数:
public static void main(String argv[]) { try { RuntimeInit.enableDdms(); // 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; //该标志为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());//值为zygote } else { throw new RuntimeException("Unknown command line argument: " + argv[i]); } } if (abiList == null) { throw new RuntimeException("No ABI list supplied."); } registerZygoteSocket(socketName); // 1、创建socket,用来与ActivityManagerService进行通信 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); preload(); // 2、预加载资源文件 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); // 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); if (startSystemServer) { startSystemServer(abiList, socketName); // 3、启动system_server进程 } Log.i(TAG, "Accepting command socket connections"); runSelectLoop(abiList); // 4、开启一个循环,处理ActivityManagerService创建应用进程的请求 closeServerSocket(); // 程序退出时,清除socket资源 } catch (MethodAndArgsCaller caller) { caller.run(); // 5、注意 } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; } }
代码中共标记出了5个较为重要的处理过程,下面一一分析。
(1)、registerZygoteSocket(socketName)
registerZygoteSocket()函数会注册Zygote的socket监听端口,用来接收启动应用程序的消息,查看其代码处理:
/** * Registers a server socket for zygote command connections * * @throws RuntimeException when open fails */ private static void registerZygoteSocket(String socketName) { if (sServerSocket == null) { int fileDesc; final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;// fullSocketName:ANDROID_SOCKET_zygote try { String env = System.getenv(fullSocketName);//获取该环境变量的值,即此socket对应的文件描述符 fileDesc = Integer.parseInt(env); } catch (RuntimeException ex) { throw new RuntimeException(fullSocketName + " unset or invalid", ex); } try { FileDescriptor fd = new FileDescriptor(); fd.setInt$(fileDesc);//将该fd保存到descriptor中 sServerSocket = new LocalServerSocket(fd);//用该文件描述符创建一个LocalServerSocket对象,并开始监听该socket } catch (IOException ex) { throw new RuntimeException( "Error binding to local socket '" + fileDesc + "'", ex); } } }
从系统环境变量中获取到“ANDROID_SOCKET_zygote”这个socket对应的文件描述符,创建LocalServerSocket对象并监听该socket;此时名为zygote的socket就可以接收消息了。细心地人可能发现了,在我们的分析过程中并没有看到socket和Zygote进程的创建过程。其实这个过程在init.cpp解析init.rc文件时,已经处理完成了。下面来看这一部分内容。
系统启动解析init.rc时,每当碰到一个由service关键字声明的服务,就会给他创建一个进程、并初始化该服务相关的资源;这些资源就包括socket的创建。
在init.cpp中,void service_start(struct service *svc, const char *dynamic_args)函数负责启动每个声明的service服务,我们提出一段重要的处理过程:
pid_t pid = fork();//创建一个进程 if (pid == 0) { struct socketinfo *si; struct svcenvinfo *ei; char tmp[32]; int fd, sz; umask(077); if (properties_initialized()) { get_property_workspace(&fd, &sz); snprintf(tmp, sizeof(tmp), "%d,%d", dup(fd), sz); add_environment("ANDROID_PROPERTY_WORKSPACE", tmp); } for (ei = svc->envvars; ei; ei = ei->next) add_environment(ei->name, ei->value); for (si = svc->sockets; si; si = si->next) { //socket创建 int socket_type = ( !strcmp(si->type, "stream") ? SOCK_STREAM : (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET)); int s = create_socket(si->name, socket_type, si->perm, si->uid, si->gid, si->socketcon ?: scon); if (s >= 0) { publish_socket(si->name, s);//socket发布 } } ... }
当系统为每个service通过调用fork()创建进程时,如果发现需要创建socket,它就会通过调用create_socket()创建一个socket:
/* * create_socket - creates a Unix domain socket in ANDROID_SOCKET_DIR * ("/dev/socket") as dictated in init.rc. This socket is inherited by the * daemon. We communicate the file descriptor's value via the environment * variable ANDROID_SOCKET_ENV_PREFIX ("ANDROID_SOCKET_foo"). */int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid, const char *socketcon){ struct sockaddr_un addr; int fd, ret; char *filecon; if (socketcon) setsockcreatecon(socketcon); fd = socket(PF_UNIX, type, 0); if (fd < 0) { ERROR("Failed to open socket '%s': %s\n", name, strerror(errno)); return -1; } if (socketcon) setsockcreatecon(NULL); memset(&addr, 0 , sizeof(addr)); addr.sun_family = AF_UNIX; snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s", name);//设置此socket的地址 ret = unlink(addr.sun_path); if (ret != 0 && errno != ENOENT) { ERROR("Failed to unlink old socket '%s': %s\n", name, strerror(errno)); goto out_close; } filecon = NULL; if (sehandle) { ret = selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK); if (ret == 0) setfscreatecon(filecon); } ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));//绑定该socket,启动listen在ZygoteInit::registerZygoteSocket()处理 if (ret) { ERROR("Failed to bind socket '%s': %s\n", name, strerror(errno)); goto out_unlink; } setfscreatecon(NULL); freecon(filecon); chown(addr.sun_path, uid, gid); chmod(addr.sun_path, perm); INFO("Created socket '%s' with mode '%o', user '%d', group '%d'\n", addr.sun_path, perm, uid, gid); return fd;//返回该socket的文件描述符out_unlink: unlink(addr.sun_path);out_close: close(fd); return -1;}
socket创建完成后,要以环境变量键值对的形式把它发布到系统中:
static void publish_socket(const char *name, int fd){ char key[64] = ANDROID_SOCKET_ENV_PREFIX; char val[64]; strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, name, sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); snprintf(val, sizeof(val), "%d", fd); add_environment(key, val);//ANDROID_SOCKET_zygote -- socket的文件描述符 /* make sure we don't close-on-exec */ fcntl(fd, F_SETFD, 0);}
到这里,socket的创建、注册处理流程就联系起来了。
ANDROID_SOCKET_ENV_PREFIX、ANDROID_SOCKET_DIR两个宏定义在/system/core/include/cutils/Socket.h中:
#define ANDROID_SOCKET_ENV_PREFIX"ANDROID_SOCKET_"#define ANDROID_SOCKET_DIR"/dev/socket"
(2)、preload()
preload()函数用于加载系统资源,包括预加载系统类、Framework资源和OpenGL资源等,它的处理如下:
static void preload() { Log.d(TAG, "begin preload"); preloadClasses();//加载/system/etc/preloaded-classes和framework.jar中的类资源 preloadResources(); preloadOpenGL(); preloadSharedLibraries(); preloadTextResources(); // Ask the WebViewFactory to do any initialization that must run in the zygote process, // for memory sharing purposes. WebViewFactory.prepareWebViewInZygote(); Log.d(TAG, "end preload"); }
这里调用了5个函数去加载需要使用的类资源、图片资源、库资源等。这几个函数功能单一,我们可以自己阅读代码;这里就不详述了。但由于这部分内容涉及到很多I/O操作,而且加载的资源较多,会影响Android系统启动的时间。一些开机时间优化就是在这一部分处理的。
(3)、startSystemServer()
startSystemServer()函数用于启动system_server进程,它的具体处理如下:
/** * 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", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007", "--capabilities=" + capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", "com.android.server.SystemServer",/*指明需要启动的进程的主类入口*/ };//创建system_server的参数列表。设置了进程的uid、gid和进程名 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 */ pid = Zygote.forkSystemServer( parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities);//根据参数,为systemserver创建进程 } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } /* For child process */ if (pid == 0) {//子进程,即system_server进程 if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } handleSystemServerProcess(parsedArgs);//进程创建完毕后,调用该函数进一步处理 } return true;//函数返回之后,重新返回到ZygoteInit.main()中,即进入Zygote父进程中 }
首先根据设置的参数列表创建system_server进程,然后在子进程中调用handleSystemServerProcess()做进一步处理:
/** * Finish remaining work for the newly forked system server process. */ private static void handleSystemServerProcess( ZygoteConnection.Arguments parsedArgs) throws ZygoteInit.MethodAndArgsCaller { closeServerSocket();//根据fork()机制,system_server是zygote的子进程,它也拥有zygote这个socket资源;但由于system_server不需要使用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);//system_server } final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH"); if (systemServerClasspath != null) { performSystemServerDexOpt(systemServerClasspath);//com.android.server.SystemServer } 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, VMRuntime.getCurrentInstructionSet(), 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 */ }
直接查看函数末尾调用RuntimeInit.zygoteInit()函数:
/** * 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. * * Current recognized args: *
* -
[--] *
* * @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"); Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit"); redirectLogStreams(); commonInit();//通用的初始化部分,包括设置默认的uncaught exception handler等 nativeZygoteInit();//调用AppRuntime.cpp::onZygoteInit(),开启线程池,用于Binder通信 applicationInit(targetSdkVersion, argv, classLoader);//通过反射调用SystemServer.java的main函数 }
函数主要做了三个个处理:通用初始化部分;native层开启线程池,用于Binder通信;
private static final void commonInit() { if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!"); /* set default handler; this applies to all threads in the VM */ Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler()); /* * Install a TimezoneGetter subclass for ZoneInfo.db */ TimezoneGetter.setInstance(new TimezoneGetter() { @Override public String getId() { return SystemProperties.get("persist.sys.timezone"); } }); TimeZone.setDefault(null); /* * Sets handler for java.util.logging to use Android log facilities. * The odd "new instance-and-then-throw-away" is a mirror of how * the "java.util.logging.config.class" system property works. We * can't use the system property here since the logger has almost * certainly already been initialized. */ LogManager.getLogManager().reset(); new AndroidConfig(); /* * Sets the default HTTP User-Agent used by HttpURLConnection. */ String userAgent = getDefaultUserAgent(); System.setProperty("http.agent", userAgent); /* * Wire socket tagging to traffic stats. */ NetworkManagementSocketTagger.install(); /* * If we're running in an emulator launched with "-trace", put the * VM into emulator trace profiling mode so that the user can hit * F9/F10 at any time to capture traces. This has performance * consequences, so it's not something you want to do always. */ String trace = SystemProperties.get("ro.kernel.android.tracing"); if (trace.equals("1")) { Slog.i(TAG, "NOTE: emulator trace profiling enabled"); Debug.enableEmulatorTraceOutput(); } initialized = true; }
通用部分的初始化,包括设置默认的uncaught exception handler(UncaughtHandler类);设置默认时区;为HttpURLConnection准备默认的Http User-Agent;开启trace模式等。
nativeZygoteInit()是重要的本地初始化函数,根据JNI实现其最终调用:
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz){ gCurRuntime->onZygoteInit();//gCurRuntime实际指向AndroidRuntime的子类AppRuntime实例,即调用AppRuntime::onZygoteInit()}
virtual void AppRuntime::onZygoteInit() { sp proc = ProcessState::self(); ALOGV("App process: starting thread pool.\n"); proc->startThreadPool();//开启Binder线程池以保证其他进程可以正确访问到Zygote所提供的服务 }
启动线程池,用于Binder通信。然后进入applicationInit():
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; } // The end of of the RuntimeInit event (see #zygoteInit). Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); // Remaining arguments are passed to the start class's static main invokeStaticMain(args.startClass, args.startArgs, classLoader);//通过反射调用SystemServer.java的main方法 }
再看invokeStaticMain():
/** * Invokes a static "main(argv[]) method on class "className". * Converts various failing exceptions into RuntimeExceptions, with * the assumption that they will then cause the VM instance to exit. * * @param className Fully-qualified class name * @param argv Argument vector for main() * @param classLoader the classLoader to load {@className} with */ private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { Class<?> cl; try { cl = Class.forName(className, true, classLoader); } catch (ClassNotFoundException ex) { throw new RuntimeException( "Missing class when invoking static main " + className, ex); } Method m; try { m = cl.getMethod("main", new Class[] { String[].class });//获取SystemServer.java的main()函数的域名,但并没有立即调用main函数; } catch (NoSuchMethodException ex) { throw new RuntimeException( "Missing static main on " + className, ex); } catch (SecurityException ex) { throw new RuntimeException( "Problem getting static main on " + className, ex); } int modifiers = m.getModifiers(); if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) { throw new RuntimeException( "Main method is not public and static on " + className); } /* * This throw gets caught in ZygoteInit.main(), which responds * by invoking the exception's run() method. This arrangement * clears up all the stack frames that were required in setting * up the process. */ throw new ZygoteInit.MethodAndArgsCaller(m, argv);//在ZygoteInit.java的main()中第5步处理时,调用SystemServer.java的main()函数 }
通过ZygoteInit.MethodAndArgsCaller异常的处理来调用SystemServer.java的main()函数启动各个系统服务,看MethodAndArgsCaller的定义:
/** * Helper exception class which holds a method and arguments and * can call them. This is used as part of a trampoline to get rid of * the initial process setup stack frames. */ public static class MethodAndArgsCaller extends Exception implements Runnable { /** method to call */ private final Method mMethod; /** argument array */ private final String[] mArgs; public MethodAndArgsCaller(Method method, String[] args) { mMethod = method; mArgs = args; } public void run() { try { mMethod.invoke(null, new Object[] { mArgs }); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { Throwable cause = ex.getCause(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } throw new RuntimeException(ex); } } }
由代码注释可知:这种调用方式会清理堆栈,可以让SystemServer.java的main函数认为自己是system_server进程的入口,虽然这之前已经做了大量的工作。
(4)、 runSelectLoop()
system_server进程处理完毕后,函数调用重新返回到ZygoteInit.main()中。Zygote进程此时会进入一个loop循环,等待处理来自运行在system_server中的AMS的创建应用进程的请求。runSelectLoop()函数会进入监听和接收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. * * @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()); peers.add(null);//添加null,是为了保持fds和peers的一致性(对应Zygote Server Socket);可以看到后面处理中,添加/移除操作都是成对出现的 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[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) { ZygoteConnection newPeer = acceptCommandPeer(abiList); peers.add(newPeer); fds.add(newPeer.getFileDesciptor()); } else { boolean done = peers.get(i).runOnce(); if (done) { peers.remove(i); fds.remove(i); } } } } }
acceptCommandPeer()函数会和客户端建立一个socket连接;而ZygoteConnection对象可以进行请求通信。如果ActivityManagerService发送的创建新应用进程的请求在此处收到后,就会进入ZygoteConnection::runOnce()处理。
/** * Reads one start command from the command socket. If successful, * a child is forked and a {@link ZygoteInit.MethodAndArgsCaller} * exception is thrown in that child while in the parent process, * the method returns normally. On failure, the child is not * spawned and messages are printed to the log and stderr. Returns * a boolean status value indicating whether an end-of-file on the command * socket has been encountered. * * @return false if command socket should continue to be read from, or * true if an end-of-file has been encountered. * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main() * method in child process */ boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { String args[]; Arguments parsedArgs = null; FileDescriptor[] descriptors; try { args = readArgumentList();//读取创建进程时传递的参数 descriptors = mSocket.getAncillaryFileDescriptors(); } catch (IOException ex) { Log.w(TAG, "IOException on command socket " + ex.getMessage()); closeSocket(); return true; } if (args == null) {//参数读取失败时,会关掉当次socket连接 // EOF reached. closeSocket(); return true; } /** the stderr of the most recent request, if avail */ PrintStream newStderr = null; if (descriptors != null && descriptors.length >= 3) { newStderr = new PrintStream( new FileOutputStream(descriptors[2])); } int pid = -1; FileDescriptor childPipeFd = null; FileDescriptor serverPipeFd = null; try { parsedArgs = new Arguments(args);//将读到的参数保存到Arguments对象中 if (parsedArgs.abiListQuery) { return handleAbiListQuery(); } if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) { throw new ZygoteSecurityException("Client may not specify capabilities: " + "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) + ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities)); } applyUidSecurityPolicy(parsedArgs, peer); applyInvokeWithSecurityPolicy(parsedArgs, peer); applyDebuggerSystemProperty(parsedArgs); applyInvokeWithSystemProperty(parsedArgs); int[][] rlimits = null; if (parsedArgs.rlimits != null) { rlimits = parsedArgs.rlimits.toArray(intArray2d); } if (parsedArgs.invokeWith != null) { FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC); childPipeFd = pipeFds[1]; serverPipeFd = pipeFds[0]; Os.fcntlInt(childPipeFd, F_SETFD, 0); } /** * In order to avoid leaking descriptors to the Zygote child, * the native code must close the two Zygote socket descriptors * in the child process before it switches from Zygote-root to * the UID and privileges of the application being launched. * * In order to avoid "bad file descriptor" errors when the * two LocalSocket objects are closed, the Posix file * descriptors are released via a dup2() call which closes * the socket and substitutes an open descriptor to /dev/null. */ int [] fdsToClose = { -1, -1 }; FileDescriptor fd = mSocket.getFileDescriptor(); if (fd != null) { fdsToClose[0] = fd.getInt$(); } fd = ZygoteInit.getServerSocketFileDescriptor(); if (fd != null) { fdsToClose[1] = fd.getInt$(); } fd = null; pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet, parsedArgs.appDataDir);//调用forkAndSpecialize()函数创建新进程 } catch (ErrnoException ex) { logAndPrintError(newStderr, "Exception creating pipe", ex); } catch (IllegalArgumentException ex) { logAndPrintError(newStderr, "Invalid zygote arguments", ex); } catch (ZygoteSecurityException ex) { logAndPrintError(newStderr, "Zygote security policy prevents request: ", ex); } try { if (pid == 0) {//pid = 0,表示在新创建的子进程中 // in child IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);//调用handleChildProc()来启动子进程 // should never get here, the child is expected to either // throw ZygoteInit.MethodAndArgsCaller or exec(). return true; } else { // in parent...pid of < 0 means failure IoUtils.closeQuietly(childPipeFd); childPipeFd = null; return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); } } finally { IoUtils.closeQuietly(childPipeFd); IoUtils.closeQuietly(serverPipeFd); } }
runOnce()的主要工作就是会为这个请求fork一个新的进程,并做一些其他的处理。这一部分的内容会在后续分析Application启动时,再做详细介绍。
(5)、MethodAndArgsCaller异常处理
我们退回到ZygoteInit::main()函数中,看MethodAndArgsCaller异常的捕获处理过程:
catch (MethodAndArgsCaller caller) { caller.run(); // 5、注意 } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; }
/** * Helper exception class which holds a method and arguments and * can call them. This is used as part of a trampoline to get rid of * the initial process setup stack frames. */ public static class MethodAndArgsCaller extends Exception implements Runnable { /** method to call */ private final Method mMethod; /** argument array */ private final String[] mArgs; public MethodAndArgsCaller(Method method, String[] args) { mMethod = method; mArgs = args; } public void run() { try { mMethod.invoke(null, new Object[] { mArgs });//调用mMethod本身代表的方法 } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { Throwable cause = ex.getCause(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } throw new RuntimeException(ex); } } }
run()方法中通过invoke()调用SystemServer.java的main()方法:
/** * The main entry point from zygote. */ public static void main(String[] args) { new SystemServer().run(); }
SystemServer.run()方法中做了大量的工作,其中就包括启动各种重要的Android系统服务,如PackageManagerService、PowerManagerService等,run()函数的实现如下:
private void run() { // If a device's clock is before 1970 (before 0), a lot of // APIs crash dealing with negative numbers, notably // java.io.File#setLastModified, so instead we fake it and // hope that time from cell towers or NTP fixes it shortly. if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {//如果系统时间不正确,则调整系统时间 Slog.w(TAG, "System clock is before 1970; setting to 1970."); SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME); } // If the system has "persist.sys.language" and friends set, replace them with // "persist.sys.locale". Note that the default locale at this point is calculated // using the "-Duser.locale" command line flag. That flag is usually populated by // AndroidRuntime using the same set of system properties, but only the system_server // and system apps are allowed to set them. // // NOTE: Most changes made here will need an equivalent change to // core/jni/AndroidRuntime.cpp if (!SystemProperties.get("persist.sys.language").isEmpty()) { final String languageTag = Locale.getDefault().toLanguageTag(); SystemProperties.set("persist.sys.locale", languageTag); SystemProperties.set("persist.sys.language", ""); SystemProperties.set("persist.sys.country", ""); SystemProperties.set("persist.sys.localevar", ""); } // Here we go! Slog.i(TAG, "Entered the Android system server!"); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis()); // In case the runtime switched since last boot (such as when // the old runtime was removed in an OTA), set the system // property so that it is in sync. We can't do this in // libnativehelper's JniInvocation::Init code where we already // had to fallback to a different runtime because it is // running as root and we need to be the system user to set // the property. http://b/11463182//设置当前的虚拟机的运行库路径 SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary()); // Enable the sampling profiler. if (SamplingProfilerIntegration.isEnabled()) { SamplingProfilerIntegration.start(); mProfilerSnapshotTimer = new Timer(); mProfilerSnapshotTimer.schedule(new TimerTask() { @Override public void run() { SamplingProfilerIntegration.writeSnapshot("system_server", null); } }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL); } // Mmmmmm... more memory! VMRuntime.getRuntime().clearGrowthLimit(); // The system server has to run all of the time, so it needs to be // as efficient as possible with its memory usage. VMRuntime.getRuntime().setTargetHeapUtilization(0.8f); // Some devices rely on runtime fingerprint generation, so make sure // we've defined it before booting further. Build.ensureFingerprintProperty(); // Within the system server, it is an error to access Environment paths without // explicitly specifying a user. Environment.setUserRequired(true); // Ensure binder calls into the system always run at foreground priority. BinderInternal.disableBackgroundScheduling(true); // Prepare the main looper thread (this thread). android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_FOREGROUND); android.os.Process.setCanSelfBackground(false); Looper.prepareMainLooper(); // Initialize native services. System.loadLibrary("android_servers");//装载libandroid_servers.so库 // Check whether we failed to shut down last time we tried. // This call may not return. performPendingShutdown(); // Initialize the system context. createSystemContext();//初始化系统Context对象,这块详细内容会在分析ActivityManagerService时介绍 // Create the system service manager. mSystemServiceManager = new SystemServiceManager(mSystemContext); LocalServices.addService(SystemServiceManager.class, mSystemServiceManager); // Start services. try { startBootstrapServices(); startCoreServices(); startOtherServices(); } catch (Throwable ex) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting system services", ex); throw ex; } // For debug builds, log event loop stalls to dropbox for analysis. if (StrictMode.conditionallyEnableDebugLogging()) { Slog.i(TAG, "Enabled StrictMode for system server main thread."); } // Loop forever. Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
SystemServer::run()函数中,重要的服务启动操作都工作在主线程中,并且最后会开启一个消息循环。
其中:
// Start services. try { startBootstrapServices(); startCoreServices(); startOtherServices(); } catch (Throwable ex) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting system services", ex); throw ex; }
会启动Android系统中各种重要的系统服务。到此,Zygote进程的启动过程就结束了。
更多相关文章
- C语言函数的递归(上)
- AIDL跨进程通信和Service调用
- Android(安卓)GSM驱动模块(rild)详细分析(三)response流程
- Android计算器功能的实现
- 【Java/Android性能优5】 Android(安卓)ImageCache图片缓存,使用
- Android(安卓)JNI知识简介
- Android(安卓)动画框架的基本原理
- Android中SoundPool放声音
- Android(安卓)进程间通信AIDL简单使用