Zygote进程时由Android系统的第一个进程init启动起来的。init进程时在内核加载完成之后就启动起来的,它在启动的过程中,会读取根目录下的一个脚本文件init.rc,以便可以将其他需要开机启动的进程也一起启动起来。
Zygote进程在脚本文件init.rc中的启动脚本如下:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server socket zygote stream 666第一行表示Zygote进程是以服务的形式启动的,并且它对应的应用程序文件为/system/bin/app_process。接下来的四个选项是Zygote进程的启动参数。其中最后一个参数"--start-system-server"表示Zygote进程在启动完成之后,需要马上将System进程也启动起来。
第二行表示Zygote进程在启动的过程中,需要在内部创建一个名称为"zygote"的Socket。这个Socket是用来执行进程间通信的,它的访问权限被设置为666,即所有用户都可以对它进行读和写。
我们先分析Zygote是如何在启动的过程中创建一个名称为"zygote"的Socket。
由于Zygote进程在脚本init.rc中配置了以服务的形式来启动,因此,init进程在启动时,就会调用函数service_start来启动它,如下:
void service_start(struct service *svc, const char *dynamic_args)//svc用来描述一个即将要启动的服务,dynamic_args为NULL { ...... pid_t pid; ...... pid = fork();//init进程fork出Zygote进程 if (pid == 0) {//Zygote进程 struct socketinfo *si; ...... for (si = svc->sockets; si; si = si->next) {//svc->sockets描述即将要启动的服务的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);//name为socket,socket_type为stream,创建一个Socket,返回一个描述符 if (s >= 0) { publish_socket(si->name, s);//create_socket返回的描述符最后会通过函数publish_socket发布到系统中 } } ...... setpgid(0, getpid()); /* as requested, set our gid, supplemental gids, and uid */ if (svc->gid) { setgid(svc->gid); } if (svc->nr_supp_gids) { setgroups(svc->nr_supp_gids, svc->supp_gids); } if (svc->uid) {//由于svc->uid为空,所有Zygote进程的uid还为0,依然是root权限 setuid(svc->uid); } if (!dynamic_args) { if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {//svc->args[0]为/system/bin/app_process,svc->args静态启动参数,注意这个数组里面有"--start-system-server" ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno)); } } else { ...... } _exit(127); } ...... }接着我们分析函数create_socket和public_socket的实现,以便可以了解它们是如何为Zygote进程创建一个名称为"zygote"的Socket。
函数create_socket的实现如下所示。
int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid) { struct sockaddr_un addr; int fd, ret; fd = socket(PF_UNIX, type, 0);//创建一个socket,这个Socket使用文件描述符fd描述 ...... memset(&addr, 0 , sizeof(addr)); addr.sun_family = AF_UNIX;//创建了一个类型为AF_UNIX的Socket地址addr,这个Socket地址有一个对应的设备文件,即ANDROID_SOCKET_DIR/name,如下一行代码所示 snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",//name为zygote,ANDROID_SOCKET_DIR为/dev/socket name); ...... ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));//bind将文件描述符fd所描述的Socket与Socket地址addr绑定起来之后,我们就可以得到一个设备文件/dev/socket/zygote ...... chown(addr.sun_path, uid, gid);//chown设置设备文件/dev/socket/zygote的用户ID,用户组ID chmod(addr.sun_path, perm);//chmod设置设备文件/dev/socket/zygote的访问权限,参数perm为666,因为设备文件/dev/socket/zygote是可以被任意用户访问的。 ...... return fd;//返回描述符 }函数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));//key值为ANDROID_SOCKET_zygote snprintf(val, sizeof(val), "%d", fd);//fd是一个文件描述符,指向了前面所创建的一个Socket,把fd格式化为一个字符串,并且保存在变量val中 add_environment(key, val);//在系统中增加了一个名称为key的环境变量,并且将它的值设置为val。这就相当于将前面所创建的一个Socket的文件描述符保存在名称为"ANDROID_SOCKET_zygote"的环境变量中 /* make sure we don't close-on-exec */ fcntl(fd, F_SETFD, 0); }在下面,我们就会看到,Zygote进程在启动的过程中,会根据这个环境变量的值来创建一个Server端Socket,等到启动完成之后,再在这个Server端Socket上等待Activtiy管理服务ActivityMangerService请求它创建新的应用程序进程。
回到service_start中,继续执行如下代码:
if (!dynamic_args) { if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {//svc->args[0]为/system/bin/app_process,svc->args静态启动参数,注意这个数组里面有"--start-system-server" ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno)); } }在Zygote进程中加载的应用程序文件为system/bin/app_process,因此,接下来我们就从这个应用程序文件的入口函数main开始分析Zygote进程的启动流程。
int main(int argc, const 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;//创建了一个AppRuntime对象runtime const char *arg; const char *argv0; 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); // Next arg is parent directory if (i < argc) { runtime.mParentDir = argv[i++]; } // Next arg is startup classname or "--zygote" if (i < argc) { arg = argv[i++]; if (0 == strcmp("--zygote", arg)) {//启动参数中有"--zygote" bool startSystemServer = (i < argc) ? strcmp(argv[i], "--start-system-server") == 0 : false;//startSystemServer的值等于true,表示Zygote进程在启动完成之后,需要将System进程启动起来 setArgv0(argv0, "zygote"); set_process_name("zygote");//设置进程名为zygote runtime.start("com.android.internal.os.ZygoteInit", startSystemServer); } else { ...... } } else { ...... } }AppRuntime类的成员函数start是从其父类AndroidRuntime继承下来的,因此,接下来我们就继续分析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". */ void AndroidRuntime::start(const char* className, const bool startSystemServer) { ...... char* slashClassName = NULL; char* cp; JNIEnv* env; ...... /* start the virtual machine */ if (startVm(&mJavaVM, &env) != 0) goto bail; /* * Register android functions. */ if (startReg(env) < 0) { LOGE("Unable to register all android natives\n"); goto bail; } /* * We want to call main() with a String array with arguments in it. * At present we only have one argument, the class name. Create an * array to hold it. */ jclass stringClass; jobjectArray strArray; jstring classNameStr; jstring startSystemServerStr; 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); startSystemServerStr = env->NewStringUTF(startSystemServer ? "true" : "false"); env->SetObjectArrayElement(strArray, 1, startSystemServerStr); /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */ jclass startClass; jmethodID startMeth; slashClassName = strdup(className); for (cp = slashClassName; *cp != '\0'; cp++) if (*cp == '.') *cp = '/'; startClass = env->FindClass(slashClassName); if (startClass == NULL) { ...... } else { startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); if (startMeth == NULL) { ...... } else { env->CallStaticVoidMethod(startClass, startMeth, strArray); ...... } } ...... }startVm在Zygote进程中创建了一个虚拟机实例,然后startReg在这个虚拟机实例中注册了一系列JNI方法,这两步的执行流程可参考Dalvik虚拟机的启动过程分析和Dalvik虚拟机总结。
最后调用com.android.internal.os.ZygoteInit类的静态成员函数main来进一步启动Zygote进程。env->CallStaticVoidMethod(startClass, startMeth, strArray)实际上通过Dalvik虚拟机去解释执行相关java代码,具体请参考Dalvik虚拟机的运行过程分析。
接着我们继续来分析com.android.internal.os.ZygoteInit类的静态成员函数main的实现。
public class ZygoteInit {
......
public static void main(String argv[]) {
try {
......
registerZygoteSocket();//创建一个Server端Socket,这个Server端Socket是用来等待Activity管理服务ActivityManagerService请求Zygote进程创建新的应用程序进程的
......
......
if (argv[1].equals("true")) {
startSystemServer();//启动System进程,以便它可以将系统的关键服务启动起来
} else if (!argv[1].equals("false")) {
......
}
......
if (ZYGOTE_FORK_MODE) {//false
......
} else {
runSelectLoopMode();
}
......
} catch (MethodAndArgsCaller caller) {
......
} catch (RuntimeException ex) {
......
}
}
......
}
我们先来分析registerZygoteSocket,如下:
private static void registerZygoteSocket() { if (sServerSocket == null) { int fileDesc; try { String env = System.getenv(ANDROID_SOCKET_ENV);//获得一个名称为"ANDROID_SOCKET_zygote"的环境变量的值 fileDesc = Integer.parseInt(env);//将它转换位一个文件描述符,我们知道这个文件描述符是用来描述一个类型为AF_UNIX的Socket。 } catch (RuntimeException ex) { throw new RuntimeException( ANDROID_SOCKET_ENV + " unset or invalid", ex); } try { sServerSocket = new LocalServerSocket( createFileDescriptor(fileDesc));//创建了一个Server端Socket,并且保存在ZygoteInit的静态成员变量sServerSocket中 } catch (IOException ex) { throw new RuntimeException( "Error binding to local socket '" + fileDesc + "'", ex); } } }然后我们来分析startSystemServer,如下:
public class ZygoteInit { ...... private static boolean startSystemServer() throws MethodAndArgsCaller, RuntimeException { /* 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,3001,3002,3003", "--capabilities=130104352,130104352", "--runtime-init", "--nice-name=system_server", "com.android.server.SystemServer", }; ZygoteConnection.Arguments parsedArgs = null; int pid; try { parsedArgs = new ZygoteConnection.Arguments(args); ...... /* Request to fork the system server process */ pid = Zygote.forkSystemServer( parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, debugFlags, null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities);//System进程uid为1000 } catch (IllegalArgumentException ex) { ...... } /* For child process */ if (pid == 0) {//子进程,System进程 handleSystemServerProcess(parsedArgs);//System进程,后续再分析 } return true; } ...... }首先创建了字符串数组args,用来保存System进程的启动参数。接着调用forkSystemServer来创建一个子进程,这个子进程就是Android系统的System进程。这里可以看出,Android系统的System进程的用户id和用户组id都被设置为1000,shell中显示的就是system。
返回到com.android.internal.os.ZygoteInit类的静态成员函数main,继续分析runSelectLoopMode,如下:
public class ZygoteInit {
......
private static void runSelectLoopMode() throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList();
ArrayList<ZygoteConnection> peers = new ArrayList();
FileDescriptor[] fdArray = new FileDescriptor[4];//首先创建了一个大小为4的Socket文件描述符数组fdArray,表示Zygote进程做多能同时处理4个Socket连接
fds.add(sServerSocket.getFileDescriptor());//将ZygoteInit类的静态成员变量sServerSocket所描述的一个Socket的文件描述符添加到Socket文件描述符列表fds中
peers.add(null);
int loopCount = GC_LOOP_COUNT;
while (true) {
int index;
......
try {
fdArray = fds.toArray(fdArray);//将保存在Socket文件描述符列表fds中的Socket文件描述符转移到Socket文件描述符数组fdArray中
index = selectReadable(fdArray);//来监控保存在这个数组中的Socket是否有数据可读。
} catch (IOException ex) {
throw new RuntimeException("Error in select()", ex);
}
if (index < 0) {
throw new RuntimeException("Error in select()");
} else if (index == 0) {//接收到连接,
ZygoteConnection newPeer = acceptCommandPeer();
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {//接收到Activity管理服务ActivityManangerService发送过来的创建应用程序进程请求
boolean done;
done = peers.get(index).runOnce();//来创建一个应用程序进程
if (done) {
peers.remove(index);
fds.remove(index);
}
}
}
}
......
}
selectReadable来监控保存在这个数组中的Socket是否有数据可读,一个数据可读就意味着它接收到了一个连接或者一个请求。如果index为0,说明它接收到了一个连接。index大于0,说明接收到请求。
ZygoteInit中静态函数startSystemServer中调用了Zygote.forkSystemServer,ZygoteInit中静态函数runSelectLoopMode中调用了selectReadable,都是native方法,如下:
native public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits);
static native int selectReadable(FileDescriptor[] fds) throws IOException;我们刚刚说过了 com.android.internal.os.ZygoteInit类的静态成员函数main,是Dalvik虚拟机解释执行的;那么执行到这些native方法,实际上JNI方法是直接在本地操作系统上执行的,而不是由Dalvik虚拟机解释器执行。具体请参考Dalvik虚拟机JNI方法的注册过程分析和Dalvik虚拟机总结。相关直接在本地操作系统执行代码如下:
void dvmCallMethodV(Thread* self, const Method* method, Object* obj, bool fromJni, JValue* pResult, va_list args) { ...... if (dvmIsNativeMethod(method)) { TRACE_METHOD_ENTER(self, method); /* * Because we leave no space for local variables, "curFrame" points * directly at the method arguments. */ (*method->nativeFunc)(self->curFrame, pResult, method, self);//直接去执行 TRACE_METHOD_EXIT(self, method); } else { dvmInterpret(self, method, pResult);//解释执行 } ...... }
Zygote.forkSystemServer创建了一个进程,具体请参考Dalvik虚拟机进程和线程的创建过程分析。