以下源码分析均基于MTK3710
zygote进程流程图
zygote进程是由init进程fork出来,主要负责后续Android应用程序框架层(Frameworks)的其它进程的创建和启动工作。
在系统启动脚本system/core/rootdir/init.rc文件中,它是根据属性ro.zygote的内容来引入不同的文件。
注:从android5.0开始,android开始支持64位的编译,zygote本身也就有了32位和64位的区别,用ro.zygote属性来控制启动不同版本的zygote进程。因此,在/system/core/rootdir下包括四个关于zygote的rc文件。分别是init.zygote32.rc、init.zygote32_64.rc、init.zygote64.rc、init.zygote64_32.rc。由硬件决定调用哪个文件。
下面开始分析源码:
1、init.zygote32.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 audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
说明:class:指定zygote进程的服务类型为main;socket:创建一个权限为660的socket( 660 -rw-rw---- 拥有者和组用户都可读和写,其他人不能进行任何操作);onrestart:说明zygote在重启的时候需要执行的一些命令
app_process:由关键字service告诉init进程创建一个名为“zygote”的进程,进程要执行的程序是/system/bin/app_process。
最后,它会将四个参数: -Xzygote、/system/bin、--zygote 、--start-system-server传给进程。
2、app_main.cpp
由上述1可知,zygote进程要执行的程序是app_process,它的入口函数是main。源码path:/frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
class AppRuntime : public AndroidRuntime
{
public:
AppRuntime(char* argBlockStart, const size_t argBlockLength)
: AndroidRuntime(argBlockStart, argBlockLength)
, mClass(NULL)
{
}
void setClassNameAndArgs(const String8& className, int argc, char * const *argv) {
...
}
......................
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} 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;
}
}
说明:a、AppRuntime 是支撑程序运行的基础库,例如包含虚拟机、java类库、JNI等。在这个main函数中最主要的作用也是创建AppRuntime,它是AndroidRuntime的一个子类。因此它还会去调用AndroidRuntime的start()函数。
b、AndroidRuntime的源码位置为:frameworks/base/core/jni/AndroidRuntime.cpp,这里就不贴出源码了。它的start函数主要做了三件事情:一是调用函数startVM启动虚拟机,二是调用函数startReg注册JNI方法,三是调用了com.android.internal.os.ZygoteInit类的main函数。(为了反射调用java代码,必须有对应的JNI函数,于是zygote进行了JNI函数的注册。)
c、由上述1传递的四个参数,最后会执行runtime.start("com.android.internal.os.ZygoteInit", args, zygote)。
3、ZygoteInit.java
当VM准备就绪,就可以运行Java代码了。ZygoteInit这个类定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:
public static void main(String argv[]) {
try {
or (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
}
registerZygoteSocket(socketName);
if (!sZygoteOnDemandEnabled) {
preloadMPlugin = true;
} else {
if ("zygote".equals(socketName)) {
preloadMPlugin = true;
}
}
if (startSystemServer) {
startSystemServer(abiList, socketName);
}
...........
runSelectLoop(abiList);
/// M: GMO Zygote64 on demand @{
zygoteStopping("ZygoteOnDemand: End of runSelectLoop", socketName);
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
}
zygoteStopping("ZygoteOnDemand: End of main function", socketName);
}
说明:这个main函数主要作了三件事情:一个调用registerZygoteSocket函数创建了一个socket接口,用来和ActivityManagerService通讯;二是调用startSystemServer函数来启动SystemServer组件;三是调用runSelectLoopMode函数进入一个无限循环在前面创建的socket接口上等待ActivityManagerService请求创建新的应用程序进程。
4、registerZygoteSocket()
// Registers a server socket for zygote command connections
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);
}
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
//响应客户端的连接请求
sServerSocket = new LocalServerSocket(fd);
}
}
说明:通过名为ANDROID_SOCKET_zygote的环境获取到zygote启动时创建的socket的fd,然后以此来创建server socket。注意这里用到的socket类型是LocalServerSocket。它是Android对Linux 的 Local Socket的一个封装。Local Socket 是Linux提供的一种基于Socket的进程间通信方式,对Server端来讲,唯一的区别就是bind到一个本地的文件描述符(fd)而不是某个IP地址和端口号。
举个例子,当init.rc中解析到上述1中有这么一行代码“ socket zygote stream 660 root system”,它会做这两件事:
a、 调用 create_socket() (system/core/init/util.c), 创建一个Socket fd, 将这个fd 与某个文件(/dev/socket/xxx, xxx 就是名字,比如,zygote) 绑定(bind), 根据init.rc 里面定义来设定相关的用户,组和权限。最后返回这个fd。
b、将socket 名字(带‘ANDROID_SOCKET_'前缀)(比如 zygote) 和 fd 注册到init 进程的环境变量里,这样所有的其他进程(所有进程都是init的子进程)都可以通过 getenv(name)获取到这个fd.
5、startSystemServer()
//Prepare the arguments and fork for the system server process.
private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, RuntimeException {
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
......
"--runtime-args",
"com.android.server.SystemServer",
};
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} ....
/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
handleSystemServerProcess(parsedArgs);
}
return true;
}
说明:从注释中也可以看出此函数准备fork出SystemServer进程;在startSystemServer方法中,通过Zygote.forkSystemServer方法创建了一个子进程,并将其用户和用户组的ID设置为1000。
注意这里fork出来的子进程在handleSystemServerProcess 里开始初始化工作,初始化分两步,一部在native 完成,另外一部分(大部分)在Java端完成。 native端的工作在AppRuntime(AndroidRuntime的子类)::onZygoteInit()完成,做的一件事情就是启动了一个Thread, 这个Thread是SystemServer的主线程, 负责接收来至其他进程的Binder调用请求。
6、runSelectLoop()
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>()
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
//内部发生错误
throw new RuntimeException("poll failed", ex);
}
//返回值大于等于0
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
//接收新的连接
if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done = peers.get(i).runOnce();
if (done) {
peers.remove(i);
fds.remove(i);.......
}
说明 :第一次连接到服务端 ;返回值 > 0:与服务端已经建立连接,并开始发送数据。
客户端的请求由 ZygoteConnection.runOnce 来处理,这个方法也抛出 MethodAndArgsCaller 异常,从而进入 MethodAndArgsCaller.run 中调用根据客户请求数据反射出的类的 main 方法。
这里从peers.get(i)得到的是一个ZygoteConnection对象,表示一个Socket连接,因此,接下来就是调用ZygoteConnection.runOnce函数进一步处理了。
6.1、ZygoteConnection.runOnce()
Path:/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
................//创建进程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,parsedArgs.appDataDir);
}
//两次返回return
try {
if (pid == 0) {
// in child 子进程
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
// should never get here, the child is expected to either
// throw ZygoteInit.MethodAndArgsCaller or exec().
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); //子进程
return true;
} else {
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); //父进程
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
说明:这个函数会创建一个进程,而且有两个返回值,一个是在当前进程中返回的,一个是在新创建的进程中返回,即在当前进程的子进程中返回。在当前进程中的返回值就是新创建的子进程的pid值,而在子进程中的返回值是0。
其中子进程又调用handleChildProc()方法。
6.2、handleChildProc()
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
..................
if (parsedArgs.invokeWith != null) {
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
} else {
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
说明:为新创建的进程初始化运行时库,继续执行RuntimeInit.zygoteInit进一步处理。
#######至此这里的zygote进程就已经分析完成,例如当一个应用要启动的时候,AMS与Zygote进程的socket连接,请求fork出一个新的子进程。那么流程又会从6.1、ZygoteConnection.runOnce()处顺势往下调用,那么后续代码流程又是怎样呢?下次再专门写一篇关于Android应用程序启动的文章吧~~~~######
总结:
zygote 进程在初始化时会启动虚拟机,并加载一些系统资源。这样当 zygote fork 出子进程后,子进程也继承了能正常工作的虚拟机和各种系统资源,接下来只需装载 apk 文件的字节码就可以运行应用程序了,可以大大缩短应用的启动时间,这就是 zygote 进程的主要作用。