安卓Zygote详解
Posted Leonban
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓Zygote详解相关的知识,希望对你有一定的参考价值。
一、Zygote, 意为“受精卵”,android系统中几乎所有的应用进程都是由Zygote进程孵化出来的,Java环境也是由Zygote创建起来的,它建立了我们app运行所需要的环境,是app的祖先,因此,分析它的启动以及内部逻辑显得非常有必要。*Android系统是基于Linux内核的,而在Linux系统中,所有的进程都是init进程的子孙进程,也就是说,所有的进程都是直接或者间接地由init进程fork出来的。Zygote进程也不例外,它是在系统启动的过程,由init进程创建的。在系统启动脚本system/core/rootdir/init.rc文件中,我们可以看到启动Zygote进程的脚本命令:
<span style="font-size:14px;">service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main socket zygote stream 660 root system # zygote需要一个套接字 onrestart write /sys/android_power/request_state wake # zygote重启的话,需要执行这个操作 onrestart write /sys/power/state on onrestart restart media onrestart restart netd</span>*上述脚本表示要启动一个进程,名称为zygote, 可执行文件为/system/bin/app_process, --Xzygote /system/bin --zygote --start-system-server这些是传给zygote的参数,其余部分的作用见注释。
二、app_process对应的源码在frameworks/base/cmds/app_process目录下,其入口函数main在文件app_main.cpp中,接下来我们就从这个main函数入手来分析zygote的内部逻辑。
<span style="font-size:14px;">int main(int argc, char* const argv[]) { // These are global variables in ProcessState.cpp mArgC = argc; mArgV = argv; mArgLen = 0; for (int i=0; i<argc; i++) { mArgLen += strlen(argv[i]) + 1; } mArgLen--; AppRuntime runtime; const char* argv0 = argv[0]; // Process command line arguments // ignore argv[0] argc--; argv++; // Everything up to '--' or first non '-' arg goes to the vm int i = runtime.addVmArguments(argc, argv); // Parse runtime arguments. Stop at first unrecognized option. bool zygote = false; bool startSystemServer = false; bool application = false; const char* parentDir = NULL; const char* niceName = NULL; const char* className = NULL; while (i < argc) { const char* arg = argv[i++]; if (!parentDir) { parentDir = arg; } else if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = "zygote"; } 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 = arg + 12; } else { className = arg; break; } } if (niceName && *niceName) { setArgv0(argv0, niceName); set_process_name(niceName); } runtime.mParentDir = parentDir; if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : ""); } else if (className) { // Remainder of args get passed to startup class main() runtime.mClassName = className; runtime.mArgC = argc - i; runtime.mArgV = argv + i; runtime.start("com.android.internal.os.RuntimeInit", application ? "application" : "tool"); } 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; } }</span>三、main函数主要就是创建了runtime实例,并且解析参数,然后调用runtime的start函数,接着我们分析AppRuntime的start函数
这个函数定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中:
<span style="font-size:14px;">// 首先明确下传进来的参数 className == "com.android.internal.os.ZygoteInit" options == "start-system-server" void AndroidRuntime::start(const char* className, const char* options) { ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n", className != NULL ? className : "(unknown)"); /* * 'startSystemServer == true' means runtime is obsolete and not run from * init.rc anymore, so we print out the boot start event here. */ if (strcmp(options, "start-system-server") == 0) { /* 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 /android does not exist."); return; } setenv("ANDROID_ROOT", rootDir, 1); //配置ANDROID_ROOT环境变量 } //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) != 0) { // 创建虚拟机 return; } onVmCreated(env); /* * Register android functions. */ 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. */ jclass stringClass; jobjectArray strArray; jstring classNameStr; jstring optionsStr; stringClass = env->FindClass("java/lang/String"); assert(stringClass != NULL); strArray = env->NewObjectArray(2, stringClass, NULL); assert(strArray != NULL); classNameStr = env->NewStringUTF(className); assert(classNameStr != NULL); env->SetObjectArrayElement(strArray, 0, classNameStr); optionsStr = env->NewStringUTF(options); env->SetObjectArrayElement(strArray, 1, optionsStr); /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */ char* slashClassName = toSlashClassName(className); jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); /* keep going */ } else { jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */ } else { /* 调用com.android.internal.os.ZygoteInit的main函数,strArray是参数,数组里面有两个元素, className == "com.android.internal.os.ZygoteInit" options == "start-system-server" */ 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"); }</span>四、start函数主要做了以下几件事情:
调用startVm函数创建虚拟机;
调用startReg函数注册Android Natvie函数;
让虚拟机去执行com.android.internal.os.ZygoteInit的main函数。
接下来分析下com.android.internal.os.ZygoteInit的main函数,frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
<span style="font-size:14px;">public static void main(String argv[]) { try { // Start profiling the zygote initialization. SamplingProfilerIntegration.start(); registerZygoteSocket(); // 1、创建一个套接字,用于监听ams发过来的fork请求 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); preload(); // 2、加载classes 和resources, 后面会详细分析 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 gc(); // If requested, start system server directly from Zygote if (argv.length != 2) { throw new RuntimeException(argv[0] + USAGE_STRING); } if (argv[1].equals("start-system-server")) { startSystemServer(); //3、 创建system server进程,ams wms pms等常见service都在该进程里面 } else if (!argv[1].equals("")) { throw new RuntimeException(argv[0] + USAGE_STRING); } Log.i(TAG, "Accepting command socket connections"); if (ZYGOTE_FORK_MODE) { runForkMode(); } else { runSelectLoopMode(); // 4、进入循环监听模式,监听外来请求 } closeServerSocket(); } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; } }</span>五、com.android.internal.os.ZygoteInit的main函数主要做了四件事情:
调用 registerZygoteSocket()创建一个套接字,用于监听ams发过来的fork请求;
调用preload()预加载classes 和resources;
调用startSystemServer()创建system server进程,ams wms pms等常见service都在该进程里面;
调用runSelectLoopMode()进入循环监听模式,监听外来请求。
1、 registerZygoteSocket
fork()创建子进程,父进程返回true。子进程执行RuntimeInit.zygoteInit。
@frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
<span style="font-size:14px;">public class ZygoteInit { ... private static LocalServerSocket sServerSocket; private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote"; private static void registerZygoteSocket() { if(sServerSocket == NULL) { int fileDesc; String env = System.getenv(ANDROID_SOCKET_ENV); // 获取环境变量 fileDesc = Integer.parseInt(env); sServerSocket = new LocalServerSocket(createFileDescriptor(fileDesc)); } } } </span>*这里通过System.getenv()获取环境变量ANDROID_SOCKET_ENV的值,通过这个文件描述符表示/dev/socket/zygote。那么这个环境变量又是谁设置的呢?执行系统启动脚本init.rc的init.c文件里面有个service_start()函数就是用来分析zygote并创建和设置相应socket的。
<span style="font-size:14px;">void service_start(struct service *svc, const char* dynamic_args) { ... pid = fork(); if ( pid == 0) { struct socketinfo *si; ... for (si = svc->sockets; si; si = si->next) { 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); publish_socket(si->name, s); } } ... } #define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_" #define ANDROID_SOCKET_DIR "/dev/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 = val fcntl(fd, F_SETFD, 0); }</span>*这里每一个service命令都会使init进程调用fork函数创建一个新的进程来分析里面的socket选项,然后调用create_socket()函数在/dev/socket目录下创建一个设备文件,然后获得一个文件描述符并通过publish_socket()写入到环境变量中去。这样就把zygote这个socket的文件描述符写到ANDROID_SOCKET_zygote里面去了,这里创建socket文件描述符的create_socket()函数,最后通过调用execve(svc->args[0], (char**)arg_ptrs, (char**)ENV)去执行zygote的可执行程序,并将环境变量ENV参数传递过去了。所以ZygoteInit.registerZygoteSocket()函数就可以直接从环境变量中取出这个文件描述符来使用。如果其他进程需要打开这个/dev/socket/zygote 文件来和Zygote进程通信就需要通过文件名字连接LocalServerSocket。
2、startSystemServer
@frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
<span style="font-size:14px;">private static boolean startSystemServer() { String args[] = { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006...", "--capabilities=13010432,130104352", "--runtime-init", "--nice-name=system_server", "com.android.server.SystemServer", }; ZygoteConnection.Arguments parsedArgs = null; parsedArgs = new ZygoteConnection.Arguments(args); ZygoteConnection.applyDebuggerSystemProperty(parsedArgs); ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs); int pid = Zygote.forkSystemServer( parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities)); if (pid == 0) { // 子进程 handleSystemServerProcess(parsedArgs); } return true; // 父进程直接返回true }</span>*这里Zygote进程通过调用Zygote.forkSystemServer()函数创建一个新的进程来启动SystemServer组件。
<span style="font-size:14px;">public class ZygoteInit { .... private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) { closeServerSocket(); // 子进程不需要zygote套接字,直接关闭 FileUtils.setUMask(FileUtils.S_IRWXG | FileUtils.S_IRWXO); ... RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs); } } public class RuntimeInit { ... public static final void zygoteInit(int targetSdkVersion, String[] argv) { redirectLogStreams(); commonInit(); zygoteInitNative(); // 是一个native函数,主要完成Binder通信机制的初始化 applicationInit(targetSdkVersion, argv); } public static final native void zygoteInitNative(); private static void applicationInit(int targetSdkVersion, String[] argv) { VMRuntime.getRuntime().setTargetHeapUtilizatoin(0.75f); VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); final Arguments args; args = new Arguments(argv); invokeStaticMain(args.startClass, args.startArgs); } // 这个 className = "com.android.server.SystemServer" private static void invokeStaticMain(String className, String[] argv) { Class<?> cl; cl = Class.forName(className); Method m; m = cl.getMethod("main", new Class[] {String[].class}); ... throw new ZygoteInit.MethodAndArgsCaller(m, argv); } }</span>*这个RuntimeInit.ZygoteInit()函数主要执行两个操作:一是调用zygoteInitNative来执行一个Binder进程间通信机制的初始化工作;二是调用com.android.server.SystemServer类的main函数。
*zygoteInitNative:
@frameworks/base/core/jni/AndroidRuntime.cpp
<span style="font-size:14px;">static JNINativeMethod gMethods[] = { .... { "zygoteInitNative", "()V", (void*) com_android_internal_os_RuntimeInit_zygoteInit }, .... }; static void com_android_internal_os_RuntimeInit_zygoteInit(JNIEnv* env, jobject clazz) { gCurRuntime->onZygoteInit(); // 就是启动Binder通信 } virtual void onZygoteInit() { sp<ProcessState> proc = ProcessState::self(); // 每个进程一份ProcessState对象,打开Binder驱动 if(proc->supportsProcess()){ proc->startThreadPool(); // 启动一个线程用于Binder通信 } }</span>*SystemServer.main :
@frameworks/base/services/java/com/android/server/SystemServer.java
<span style="font-size:14px;">public class SystemServer { native public static void init1(Strig[] args); public static void main(String[] args) { .... VMRuntime.getRuntime().setTargetHeapUtilization(0.8f); System.loadLibrary("android_servers"); init1(args); } public static final void init2() { Thread thr = new ServerThread(); thr.setName("android.server.ServerThread"); thr.start(); } }</span>*@frameworks/base/services/jni/com_android_server_SystemServer.cpp
<span style="font-size:14px;">static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz) { system_init(); } status_t system_init() { sp<ProcessState> proc(ProcessState::self()); sp<IServiceManager> sm = defaultServiceManager(); ... AndroidRuntime* runtime = AndroidRuntime::getRuntime(); JNIEnv* env = rungime->getJNIEnv(); jclass clazz = env->FindClass("com/android/server/SystemServer"); jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V"); env->CallStaticVoidMethod(clazz, methodId); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); return NO_ERROR; }</span>*这个SystemServer的main()函数首先会调用JNI方法init1,init1()会调用SystemServer的init2,在init2里面创建一个ServerThread线程执行一些系统关键服务的启动操作。
<span style="font-size:14px;">class ServerThread extends Thread { ... public void run() { Looper.prepare(); // Critical services ... ServiceManager.addService(Context.POWER_SERVICE, new PoperManagerService()); ActivityManagerService.main(); PackageManagerService.main(context); ... } }</span>*到现在为止,zygote已经fork()子进程完成了SystemServer组件的初始化启动操作,回到zygote.main()里面调用runSelectLoopMode()进入一个循环再前面创建的socket接口上等待ActivityManagerService请求创建新的应用程序。
3、runSelectLoopMode
<span style="font-size:14px;">public class ZygoteInit { .... private static void runSelectLoopMode() throws MethodAndArgsCaller { ArrayList<FileDescriptor> fds = new ArrayList(); ArrayList<ZygoteConnection> peers = new ArrayList(); FileDescriptor[] fdArray = new FileDescriptor[4]; fds.add(sServerSocket.getFileDescriptor()); peers.add(NULL); int loopCount = GC_LOOP_COUNT; // 10 while(true) { fdArray = fds.toArray(fdArray); index = selectReadble(fdArray); // 类似Linux下的select轮询,native 函数 if(index < 0) { ... } else if(index == 0) { // 表示有客户端连接上 ZygoteConnection newPeer = acceptCommandPeer(); peers.add(newPeer); fds.add(newPeer.getFileDescriptor()); } else { // 客户端发送了请求过来,交给ZygoteConnection的runOnce()函数完成 boolean done = peers.get(index).runOnce(); if(done) { peers.remove(index); fds.remove(index); } } } } private static ZygoteConnection acceptCommandPeer() { ... return new ZygoteConnection(sServerSocket.accept()); } }</span>*这里while(true)循环里面调用selectReadble(),这是一个native函数,类似select使用多路复用I/O模型。当返回0的时候表示有客户端连接上,ZygoteConnection表示Zygote的一个客户端,每当客户端连接上的时候acceptCommandPeer()返回一个ZygoteConnection对象,ZygoteConnection里面保存着accpet()返回的LocalSocket对象。然后将相应的文件描述符添加到fds里面,下次再对其调用selelct轮询。当返回值大于0的时候表示有客户端发过来的数据请求,交给ZygoteConnection对象的runOnce()函数处理。
*selectReadable()函数对应native函数为:com_android_internal_os_ZygoteInit_SelectReadable()
<span style="font-size:14px;">static jint com_android_internal_os_ZygoteInit_selectReadable ( JNIEnv *env, jobject clazz, jobjectArray fds) { if (fds == NULL) { jniThrowNullPointerException(env, "fds == null"); return -1; } jsize length = env->GetArrayLength(fds); fd_set fdset; if (env->ExceptionOccurred() != NULL) { return -1; } FD_ZERO(&fdset); int nfds = 0; for (jsize i = 0; i < length; i++) { jobject fdObj = env->GetObjectArrayElement(fds, i); if (env->ExceptionOccurred() != NULL) { return -1; } if (fdObj == NULL) { continue; } int fd = jniGetFDFromFileDescriptor(env, fdObj); if (env->ExceptionOccurred() != NULL) { return -1; } FD_SET(fd, &fdset); if (fd >= nfds) { nfds = fd + 1; } } int err; do { err = select (nfds, &fdset, NULL, NULL, NULL); } while (err < 0 && errno == EINTR); if (err < 0) { jniThrowIOException(env, errno); return -1; } for (jsize i = 0; i < length; i++) { jobject fdObj = env->GetObjectArrayElement(fds, i); if (env->ExceptionOccurred() != NULL) { return -1; } if (fdObj == NULL) { continue; } int fd = jniGetFDFromFileDescriptor(env, fdObj); if (env->ExceptionOccurred() != NULL) { return -1; } if (FD_ISSET(fd, &fdset)) { return (jint)i; } } return -1; }</span>总结:
*在android中SystemService的启动是在Zygote进程创建好后进行的,并且由Zygote进程建立好DVM运行环境,加载ZygoteInit的main函数,最终调用Zygote的本地方法forkSystemServer,并执行linux的fork方法创建SystemServer进程。
*应用程序的进程也是由Zygote创建的,在ActivityManagerService中的startProcessLocked中调用了Process.start()方法。并通过连接调用Zygote的native方法forkAndSpecialize,执行fork任务。
*应用进程和服务进程位于不同的进程中,他们之间是通过IPC进行数据传递的。
以上是关于安卓Zygote详解的主要内容,如果未能解决你的问题,请参考以下文章