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虚拟机进程和线程的创建过程分析。