zygote本身是一个Linux的Native应用程序,当init进程启动完毕之后,通过init.rc文件启动zygote并修改进程名字为zygote(frameworks/base/cmds/app_process/app_main.cpp文件)。它是一个deamon进程,启动VM,加载class和resource等。之后唯一的任务就是监听socket(/dev/socket/zygote这个是用来监听的socket)并启动application,所有APP的父进程皆为zygote进程。
zygote从”/dev/socket/zygote”监听到APP启动的请求之后,最终会fork()一个子进程。我们知道fork()会完全复制父进程(clone)到另外的一个用户空间。当zygote进行fork之后,还需要创建新的Dalvik VM,还需要preload那些APP需要的class和resource。看起来像是zygote每次启动一个APP的时候都要重新复制整块的内存并重新加载class和resouce,但其实不然,这是因为Linux内核实现的Copy-On-Write(COW)。有Copy-On-Write,意味着在fork复制内存操作中,没有内存是会被马上拷贝的。而是在进程在改写这段内存的时候,kernel会中断这种写操作并先做之前没有做的复制操作。在zygote进行preload的class和resource都是只读的文件,所以在启动APP和运行APP的过程中,没有class和resource是会被复制到另外的内存的,而是所有的APP都在用同一份class和resource,也就是zygote启动的时候加载的那些。
1.设置init.xx.rc启动运行相关service
//system/core/rootdir/init.zygotexx.rc //xx是64或者32,看平台
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
//设置zygote相关的socket名字,权限等。会生成/dev/socket/zygote节点,权限如下:
//srw-rw---- root system 2012-01-28 13:39 zygote
onrestart write /sys/android_power/request_state wake //??
onrestart write /sys/power/state on //??
onrestart restart media
onrestart restart netd
onrestart restart loc_launcher
2.init进程读到上面的service之后,会跑到/frameworks/base/cmds/app_process/app_main.cpp文件的main函数,并传入参数。main函数主要做以下几件事情
1)修改当前进程名字为zygote
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string());
set_process_name(niceName.string());
}
//通过这个最终用prctl()系统调用修改当前进程的名字为zygo
2)调用AppRuntime.start函数!! 下面会继续分析AppRuntime.start函数
AppRuntime.start函数做如下一些事情
1) startVm()初始化DVM
2) startReg()注册JNI函数
3)
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
env->CallStaticVoidMethod(startClass, startMeth, strArray)
//加载"com.android.internal.os.ZygoteInit"类并调用其main函数。
//第一个java函数调用开始了~~
ZygoteInit.main函数主要做以下几件事情
1.调用registerZygoteSocket函数创建了一个socket接口,用来和ActivityManagerService通讯
boolean startSystemServer = false;
String socketName = "zygote";
registerZygoteSocket(socketName);
registerZygoteSocket()函数如下:
private static void registerZygoteSocket(String socketName) {
if (sServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
sServerSocket = new LocalServerSocket(
createFileDescriptor(fileDesc));
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
可以看到registerZygoteSocket()函数通过叫fullSocketName的环境变量得到env并转换为文件描述符。
这个环境变量的名字可以从上面的函数中知道是”ANDROID_SOCKET_zygote”。这个环境变量是在哪里设置的呢?
我们知道,系统启动脚本文件system/core/rootdir/init.rc是由init进程来解释执行的,而init进程的源代码位于system/core/init目录中,在init.c文件中,是由service_start函数来解释init.rc文件中的service命令的。每一个service命令都会促使init进程调用fork函数来创建一个新的进程,在新的进程里面,会分析里面的socket选项,对于每一个socket选项,都会通过create_socket函数来在/dev/socket目录下创建一个文件,在这个场景中,这个文件便是zygote了,然后得到的文件描述符通过publish_socket函数写入到环境变量中去。publish_socke()函数中可以看到是如何设置环境变量的。
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);
}
因此,这里就把上面得到的文件描述符写入到以”ANDROID_SOCKET_zygote”为key值的环境变量中。又因为上面的ZygoteInit.registerZygoteSocket函数与这里创建socket文件的create_socket函数是运行在同一个进程中,因此,上面的ZygoteInit.registerZygoteSocket函数可以直接使用这个文件描述符来创建一个Java层的LocalServerSocket对象。如果其它进程也需要打开这个/dev/socket/zygote文件来和Zygote进程进行通信,那就必须要通过文件名来连接这个LocalServerSocket了
2.预加载
static void preload() {
Log.d(TAG, "begin preload");
preloadClasses();
preloadResources();
preloadOpenGL();
preloadSharedLibraries();
// 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");
}
3.调用startSystemServer函数来启动SystemServer组件
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[] = {//SystemServer进程的uid,gid等等,,很多参数设置,需要仔细看看
"--setuid=1000",
"--setgid=1000",
//WTL_EDM_START
// "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
//Adds system to net_raw and net_admin (3004, 3005)
//groups, so that system can use iptables.
"-- setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3004,3005,3006,3007",
//WTL_EDM_END
"--capabilities=" + capabilities + "," + capabilities,
"--runtime-init",
"--nice-name=system_server",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
//按照上面的参数赋值给parsedArgs
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
//fork出来一个SystemServer进程
/* 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) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
//SystemServer进程跑到这里,开始跑handleSystemServerProcess()。
handleSystemServerProcess(parsedArgs);
}
return true;
}
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.
Os.umask(S_IRWXG | S_IRWXO);
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}
final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
if (systemServerClasspath != null) {
performSystemServerDexOpt(systemServerClasspath);
}
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,
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()函数
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader
classLoader) throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
redirectLogStreams();
commonInit();
nativeZygoteInit();
applicationInit(targetSdkVersion, argv, classLoader);
}
这个函数都是做一些初始化工作,其中nativeZygoteInit最终会调用到app_main.cpp中的onZygoteInit。
virtual void onZygoteInit()
{
// Re-enable tracing now that we're no longer in Zygote.
atrace_set_tracing_enabled(true);
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}
applicationInit函数中的invokeStaticMain(args.startClass, args.startArgs, classLoader)最终会调用SystemServer.java中的main函数。ZygoteInit.java的startSystemServer()函数中,args参数的最后一个就是 “com.android.server.SystemServer”,所以最后调用的就是这个库的main函数。
/** * The main entry point from zygote. * */
public static void main(String[] args) {
new SystemServer().run();
}
这里看到SystemServer启动,但具体内容很多,需要后面再进行分析。
4.调用runSelectLoopMode函数进入一个无限循环在前面创建的socket接口上等待ActivityManagerService请求创建新的应用程序进程。
runSelectLoop()->ZygoteConnection.runOnce()函数负责接收command并启动APP
/*runSelectLoop()函数中,GC_LOOP_COUNT表示跑起来几个APP之后调用一次gc()清理内存。 如果内存较小,可以适当调整这个值?*/
从这里可以再进一步看看ActivityManagerService是怎么组织参数发给zygote来启动一个参数的。
这里也涉及到安全等,需要仔细检查一下。
//安全相关的
applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);
//需要设置的uid,gid等,,
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal,
parsedArgs.seInfo,parsedArgs.category, parsedArgs.accessInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir);
至此,zygote进程的启动分析就结束了,它会一直循环在这里,等待其他进程请求它孵化出新的进程。