文章出处:http://blog.csdn.net/shift_wwx
前言:之前一篇博文(Android 的init过程详解)中记录了init启动过程,后来另一篇(Android init.rc详解 )中记录了init.rc的解析过程,android详细的启动过程,就需要将所有的init rc文件解剖之后,从action到service挨个分析。这里记录一下zygote的启动过程。
启动命令
init.rc中:
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
通过app_process引导启动zygote,/system/bin/app_process 之后的都是命令参数。
接下来的socket关键字表示这个zygote进程需要一个名称为"zygote"的socket资源,这样,系统启动后,我们就可以在/dev/socket目录下看到有一个名为zygote的文件。ActivityManagerService就是通这个socket来和zygote进程通信请求fork一个应用程序进程的了。
最后的一系列onrestart关键字表示这个zygote进程重启时需要执行的命令。
详细的可以参考Android init.rc详解
下面来分析一下source code:
int main(int argc, char* const argv[]) { #ifdef __arm__ /* * b/7188322 - Temporarily revert to the compat memory layout * to avoid breaking third party apps. * * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE. * * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466 * changes the kernel mapping from bottom up to top-down. * This breaks some programs which improperly embed * an out of date copy of Android's linker. */ char value[PROPERTY_VALUE_MAX]; property_get("ro.kernel.qemu", value, ""); bool is_qemu = (strcmp(value, "1") == 0); if ((getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) && !is_qemu) { int current = personality(0xFFFFFFFF); if ((current & ADDR_COMPAT_LAYOUT) == 0) { personality(current | ADDR_COMPAT_LAYOUT); setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1); execv("/system/bin/app_process", argv); return -1; } } unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP"); #endif // 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);//进程名为zygote } runtime.mParentDir = parentDir;//没看懂是干嘛的,应该只是做个路径保存吧,/system/bin if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : "");//启动zygote } else if (className) {//除了zygote,RuntimeInit也在这里启动 // 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; } }
刚开始的时候直接忽略了argv[0],直接从命令的路径开始,通过while循环逐个解析命令参数,parentDir、niceName、startSystemServer、zygote等等。
if (niceName && *niceName) { setArgv0(argv0, niceName); set_process_name(niceName); }niceName是”zygote“,保存到了argv0,没看懂这个函数内部变量是干什么的?
设置了进程名为zygote。
@/syste/core/libcutils/process_name.c
void set_process_name(const char* new_name) { #ifdef HAVE_ANDROID_OS char propBuf[PROPERTY_VALUE_MAX]; #endif if (new_name == NULL) { return; } // We never free the old name. Someone else could be using it. int len = strlen(new_name); char* copy = (char*) malloc(len + 1); strcpy(copy, new_name); process_name = (const char*) copy; #if defined(HAVE_PRCTL) if (len < 16) { prctl(PR_SET_NAME, (unsigned long) new_name, 0, 0, 0); } else { prctl(PR_SET_NAME, (unsigned long) new_name + len - 15, 0, 0, 0); } #endif #ifdef HAVE_ANDROID_OS // If we know we are not running in the emulator, then return. if (running_in_emulator == 0) { return; } // If the "running_in_emulator" variable has not been initialized, // then do it now. if (running_in_emulator == -1) { property_get("ro.kernel.qemu", propBuf, ""); if (propBuf[0] == '1') { running_in_emulator = 1; } else { running_in_emulator = 0; return; } } // If the emulator was started with the "-trace file" command line option // then we want to record the process name in the trace even if we are // not currently tracing instructions (so that we will know the process // name when we do start tracing instructions). We do not need to execute // this code if we are just running in the emulator without the "-trace" // command line option, but we don't know that here and this function // isn't called frequently enough to bother optimizing that case. int fd = open(PROCESS_NAME_DEVICE, O_RDWR); if (fd < 0) return; write(fd, process_name, strlen(process_name) + 1); close(fd); #endif }后来通过
runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : "");来启动zygote,具体start做了什么可以参考 Dalvik虚拟机的启动过程
public static void main(String argv[]) { try { // Start profiling the zygote initialization. SamplingProfilerIntegration.start(); registerZygoteSocket(); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); if(!SystemProperties.getBoolean("config.enable_quickboot", false)) { preload(); } 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(); // Disable tracing so that forked processes do not inherit stale tracing tags from // Zygote. Trace.setTracingEnabled(false); // 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(); } else if (!argv[1].equals("")) { throw new RuntimeException(argv[0] + USAGE_STRING); } Log.i(TAG, "Accepting command socket connections"); runSelectLoop(); closeServerSocket(); } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; } }最主要的就是做了三件事情:
1)创建zygote socket,用来和ActivityManagerService通讯
2)startSystemServer启动system_server
3)调用runSelectLoopMode函数进入一个无限循环在前面创建的socket接口上等待ActivityManagerService请求创建新的应用程序进程。
接下来对main函数做简单的分析:
1、数据统计
// Start profiling the zygote initialization. SamplingProfilerIntegration.start(); ...... // Finish profiling the zygote initialization. SamplingProfilerIntegration.writeZygoteSnapshot();
2、registerZygoteSocket
private static void registerZygoteSocket() { if (sServerSocket == null) { int fileDesc; try { String env = System.getenv(ANDROID_SOCKET_ENV); fileDesc = Integer.parseInt(env); } catch (RuntimeException ex) { throw new RuntimeException( ANDROID_SOCKET_ENV + " unset or invalid", ex); } try { sServerSocket = new LocalServerSocket( createFileDescriptor(fileDesc)); } catch (IOException ex) { throw new RuntimeException( "Error binding to local socket '" + fileDesc + "'", ex); } } }这个socket接口是通过文件描述符来创建的,这个文件描符代表的就是我们前面说的/dev/socket/zygote文件了。这个文件描述符是通过环境变量ANDROID_SOCKET_ENV得到的,它定义为:
private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";那么,这个环境变量的值又是由谁来设置的呢?我们知道,系统启动脚本文件system/core/rootdir/init.rc是由init进程来解释执行的,而init进程的源代码位于system/core/init目录中,在init.c文件中,是由service_start函数来解释init.rc文件中的service命令的:
void service_start(struct service *svc, const char *dynamic_args) { ...... pid_t pid; ...... 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); if (s >= 0) { publish_socket(si->name, s); } } ...... } ...... }每一个service命令都会促使init进程调用fork函数来创建一个新的进程,在新的进程里面,会分析里面的socket选项,对于每一个socket选项,都会通过create_socket函数来在/dev/socket目录下创建一个文件,在这个场景中,这个文件便是zygote了,然后得到的文件描述符通过publish_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); /* make sure we don't close-on-exec */ fcntl(fd, F_SETFD, 0); }这里就将init.rc中的zygote传了进来,而ANDROID_SOCKET_ENV_PREFIX在system/core/include/cutils/sockets.h定义为:
#define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_" #define ANDROID_SOCKET_DIR "/dev/socket"因此,这里就把上面得到的文件描述符写入到以"ANDROID_SOCKET_zygote"为key值的环境变量中。又因为上面的ZygoteInit.registerZygoteSocket函数与这里创建socket文件的create_socket函数是运行在同一个进程中,因此,上面的ZygoteInit.registerZygoteSocket函数可以直接使用这个文件描述符来创建一个Java层的LocalServerSocket对象。如果其它进程也需要打开这个/dev/socket/zygote文件来和Zygote进程进行通信,那就必须要通过文件名来连接这个LocalServerSocket了。
if(!SystemProperties.getBoolean("config.enable_quickboot", false)) { preload(); }对于preload这里不做过多的介绍,可以参考 android 系统资源的加载和获取
4、startSystemServer
private static boolean startSystemServer() throws MethodAndArgsCaller, RuntimeException { long capabilities = posixCapabilitiesAsBits( 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,1032,3001,3002,3003,3006,3007", "--capabilities=" + capabilities + "," + capabilities, "--runtime-init", "--nice-name=system_server", "com.android.server.SystemServer", }; 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); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } /* For child process */ if (pid == 0) { handleSystemServerProcess(parsedArgs); } return true; }对于system_server进程,可以参考 android systemserver启动详解
private static void handleSystemServerProcess( ZygoteConnection.Arguments parsedArgs) throws ZygoteInit.MethodAndArgsCaller { closeServerSocket(); // set umask to 0077 so new files and directories will default to owner-only permissions. Libcore.os.umask(S_IRWXG | S_IRWXO); if (parsedArgs.niceName != null) { Process.setArgV0(parsedArgs.niceName); } if (parsedArgs.invokeWith != null) { WrapperInit.execApplication(parsedArgs.invokeWith, parsedArgs.niceName, parsedArgs.targetSdkVersion, null, parsedArgs.remainingArgs); } else { /* * Pass the remaining arguments to SystemServer. */ RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs); } /* should never reach here */ }
由于由Zygote进程创建的子进程会继承Zygote进程在前面Step 2中创建的Socket文件描述符,而这里的子进程又不会用到它,因此,这里就调用closeServerSocket函数来关闭它。这个函数接着调用RuntimeInit.zygoteInit函数来进一步执行启动SystemServer组件的操作。详细的可以参考android systemserver启动详解
5、runSelectLoop
/** * 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() throws MethodAndArgsCaller { ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>(); ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); FileDescriptor[] fdArray = new FileDescriptor[4]; fds.add(sServerSocket.getFileDescriptor()); peers.add(null); int loopCount = GC_LOOP_COUNT; while (true) { int index; /* * Call gc() before we block in select(). * It's work that has to be done anyway, and it's better * to avoid making every child do it. It will also * madvise() any free memory as a side-effect. * * Don't call it every time, because walking the entire * heap is a lot of overhead to free a few hundred bytes. */ if (loopCount <= 0) {//Zygote每循环GC_LOOP_COUNT(这里的值是10)次就会进行一次内存回收</span></span> gc(); loopCount = GC_LOOP_COUNT; } else { loopCount--; } try { fdArray = fds.toArray(fdArray); index = selectReadable(fdArray);//内部由select()实现,在没有客户端事件时会堵塞 } catch (IOException ex) { throw new RuntimeException("Error in select()", ex); } if (index < 0) { throw new RuntimeException("Error in select()"); } else if (index == 0) {//index==0表示selcet接收到的是Zygote的socket的事件 ZygoteConnection newPeer = acceptCommandPeer(); peers.add(newPeer); fds.add(newPeer.getFileDesciptor()); } else {//调用ZygoteConnection对象的runOnce方法,ZygoteConnection是在index == 0时被添加到peers的 boolean done; done = peers.get(index).runOnce(); if (done) { peers.remove(index); fds.remove(index); } } } }这就是在等待ActivityManagerService来连接这个Socket,然后调用ZygoteConnection.runOnce函数来创建新的应用程序
这样,Zygote进程就启动完成了,学习到这里,我们终于都对Android系统中的进程有了一个深刻的认识了,这里总结一下:
1. 系统启动时init进程会创建Zygote进程,Zygote进程负责后续Android应用程序框架层的其它进程的创建和启动工作。
2. Zygote进程会首先创建一个SystemServer进程,SystemServer进程负责启动系统的关键服务,如包管理服务PackageManagerService和应用程序组件管理服务ActivityManagerService。
3. 当我们需要启动一个Android应用程序时,ActivityManagerService会通过Socket进程间通信机制,通知Zygote进程为这个应用程序创建一个新的进程。