Zygote
相关源码:
/frameworks/base/cmds/app_process/App_main.cpp (内含AppRuntime类)/frameworks/base/core/jni/AndroidRuntime.cpp/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java/frameworks/base/core/java/com/android/internal/os/Zygote.java/frameworks/base/core/java/android/net/LocalServerSocket.java
在Android中,zygote是整个系统创建新进程的核心进程。zygote进程在内部会先启动Dalvik虚拟机,继而加载一些必要的系统资源和系统类,最后进入一种监听状态。
在之后的运作中,当其他系统模块(比如AMS)希望创建新进程时,只需向zygote进程发出请求,zygote进程监听到该请求后,会相应地fork出新的进程,于是这个新进程在初生之时,就先天具有了自己的Dalvik虚拟机以及系统资源。zygote进程是由init进程启动起来,由init.rc 脚本中关于zygote的描述可知:zygote对应的可执行文件就是/system/bin/app_process,也就是说系统启动时会执行到这个可执行文件的main()函数里。
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
【解析】
zygote作为一个名字标识了这个service(可执行程序);
/system/bin/app_process表示可执行文件的位置;
class、user、group、onrestart这些关键字所对应的行都被称为options, options是用来描述的service一些特点,不同的service有着不同的options。
第三行表示在Zygote启动过程中,要在其内部创建一个名为zygote的socket,它在Linux下的权限是666,即所有用户多可以对它进行读写。
下面看一个Zygote的启动流程图:
一、Zygote启动函数调用类的栈关系:
App_main.main
AndroidRuntime.start
startVm
startReg
ZygoteInit.main
registerZygoteSocket
preload
startSystemServer
runSelectLoop
zygote服务的main()函数位于frameworks\base\cmds\app_process\App_main.cpp。关键代码如下:
int main(int argc, char* const argv[]){ . . . . . . AppRuntime runtime; const char* argv0 = argv[0]; // -Xzygote argc--; argv++; . . . . . . int i = runtime.addVmArguments(argc, argv); . . . . . . while (i < argc) { const char* arg = argv[i++];// 应该是/system/bin目录 if (!parentDir) { parentDir = arg; } else if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = "zygote"; } else if (strcmp(arg, "--start-system-server") == 0) { startSystemServer = true; } . . . . . . } if (niceName && *niceName) { setArgv0(argv0, niceName); set_process_name(niceName); // 一般改名为“zygote” } runtime.mParentDir = parentDir; if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", args); } else if (className) { runtime.start("com.android.internal.os.RuntimeInit", args); } 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; }}
main()函数里先构造了一个AppRuntime对象,即AppRuntime runtime;而后把进程名改成“zygote”,并利用runtime对象,把工作转交给java层的相应的***Init类处理。
根据传入参数的不同可以有两种启动方式,一个是 "com.android.internal.os.RuntimeInit", 另一个是 ”com.android.internal.os.ZygoteInit", 对应RuntimeInit 和 ZygoteInit 两个类, 这两个类的主要区别在于Java端,可以明显看出,ZygoteInit 相比 RuntimeInit 多做了很多事情,比如说 “preload", "gc" 等等。但是在Native端,他们都做了相同的事, startVM() 和 startReg()
简单地说就是:Zygote进程的main()函数在启动Dalvik虚拟机后,会调用另一个ZygoteInit类的main()静态函数。
1、 zygote在native层的调用示意图如下:
2、 zygote在java层的调用主要是由ZygoteInit.java完成的,调用示意图如下:
ZygoteInit.java关键代码如下(frameworks/base/core/java/com/android/internal/os/ZygoteInit.java)
public class ZygoteInit {......public static void main(String argv[]) {try {......registerZygoteSocket();............if (argv[1].equals("true")) {startSystemServer();} else if (!argv[1].equals("false")) {......}......if (ZYGOTE_FORK_MODE) {......} else {runSelectLoopMode();}......} catch (MethodAndArgsCaller caller) {......} catch (RuntimeException ex) {......}}......}
主要做了四件事情:
(1)调用registerZygoteSocket函数创建了一个socket接口,用来和ActivityManagerService等通讯;
(2)预加载一些类与资源;
(3)调用startSystemServer函数来启动SystemServer组件;
startSystemServer()并不是在函数体内直接调用Java类的main()函数的,而是通过抛异常的方式,在startSystemServer()之外加以处理的。
【为什么要以异常方式启动】
(a)首先、我们要先清楚,抛异常这一操作会引发什么?
我们知道,当一个函数抛出异常后,这个异常会依次传递给调用它的函数,知道这个异常被捕获,如果这个异常一直没有被处理,最终就会引起程序的崩溃。
(b)其次、在传递异常的时候,应用程序的栈发生了什么变化?
这就要牵涉到函数的执行模型了,我们知道,程序都是有一个个函数组成的(除了汇编程序),c/c++/java/..等高级语言编写的应用程序,在执行的时候,他们都拥有自己的栈空间(是一种先进后出的内存区域),用于存放函数的返回地址和函数的临时数据,每调用一个函数时,就会把函数的返回地址和相关数据压入栈中,当一个函数执行完后,就会从栈中弹出,cpu会根据函数的返回地址,执行上一个调用函数的下一条指令。
所以,在抛出异常后,如果异常没有在当前的函数中捕获,那么当前的函数执行就会异常的退出,从应用程序的栈弹出,并将这个异常传递给上一个函数,直到异常被捕获处理,否则,就会引起程序的崩溃。
因此,这里通过抛异常的方式启动主要是清理应用程序栈中ZygoteInit.main以上的函数栈帧,以实现当相应的main函数退出时,能直接退出整个应用程序。 当当前的main退出后,就会退回到MethodAndArgsCaller.run而这个函数直接就退回到ZygoteInit.main函数,而ZygoteInit.main也无其他的操作,直接退出了函数,这样整个应用程序将会完全退出。
(4)调用runSelectLoopMode函数进入一个无限循环在前面创建的socket接口上等待ActivityManagerService等的请求。
2.1 startSystemServer()
其并不是在函数体内直接调用Java类的main()函数的,而是通过抛异常的方式,在startSystemServer()之外加以处理的。
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,1021,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); // fork出系统服务对应的进程 pid = Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } // 对新fork出的系统进程,执行handleSystemServerProcess() if (pid == 0) { handleSystemServerProcess(parsedArgs); } return true;}
其中: (1)Zygote.forkSystemServer()会通过jni调用linux的fork函数;
(2)startSystemServer()会在新fork出的子进程中调用handleSystemServerProgress(),进而抛出异常MethodAndArgsCaller,通过caller.run()启动com.android.server.SystemServer的main 方法。
可参考:Systemserver
2.2、runSelectLoop()
private static void runSelectLoop() throws MethodAndArgsCaller { ArrayList fds = new ArrayList(); ArrayList peers = new ArrayList(); FileDescriptor[] fdArray = new FileDescriptor[4]; fds.add(sServerSocket.getFileDescriptor()); peers.add(null); int loopCount = GC_LOOP_COUNT; while (true) { int index; if (loopCount <= 0) { gc(); loopCount = GC_LOOP_COUNT; } else { loopCount--; } try { fdArray = fds.toArray(fdArray); index = selectReadable(fdArray); } 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 { boolean done; done = peers.get(index).runOnce(); if (done) { peers.remove(index); fds.remove(index); } } }}
2.2.1、在一个while循环中,不断调用selectReadable()。
selectReadable函数是个native函数,主要就是调用select()而已。在Linux的socket编程中,select()负责监视若干文件描述符的变化情况。内部调用select等待客户端 的连接,客户端连接上之后就会返回。
返回值:
<0: 内部发生错误
=0: 该客户端第一次连接到服务端。服务端调用accept与客户 端建立连接。客户端在zygote中以ZygoteConnection对象表示。
>0: 客户端与服务端已经建立连接,并开始发送数据。表明发送数据的客户端的index,peers.get(index)取得 发送数据客户端的ZygoteConnection对象,之后调用runOnce 函数处理具体的请求。
2.2.2、runOnce()
boolean runOnce( ) { Arguments parsedArgs = null; FileDescriptor[] descriptors; //Reads one start command from the command socket. args = readArgumentList(); descriptors = mSocket.getAncillaryFileDescriptors(); //创建/Forks a new VM instance /process. //使用Jni 调用nativeFork pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits); //返回两次 if (pid == 0) { // in child serverPipeFd = null; handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); // should never get here, the child is expected to either return true; } else { // in parent...pid of < 0 means failure childPipeFd = null; return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); }}
从上面的代码中可以看到创建进程之后返回: 子进程:handleChildProc
父进程:handleParentProc
我们关心的是子进程的执行,继续到handleChildProc中。
// Handles post-fork setup of child procprivate void handleChildProc(Arguments parsedArgs,...){ …… if (parsedArgs.runtimeInit) { if (parsedArgs.invokeWith != null) { //通过系统调用执行进程 WrapperInit.execApplication(parsedArgs.invokeWith, parsedArgs.niceName, parsedArgs.targetSdkVersion, pipeFd, parsedArgs.remainingArgs); } else { //通过寻找到相应目标类的main()函数并执行 RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs); } } ……}
看到子进程的执行有两种方式: WrapperInit.execApplication和RuntimeInit.zygoteInit
1)通过系统调用的方式执行进程 WrapperInit.execApplication:
public static void execApplication(……) { …… Zygote.execShell(command.toString());}public static void execShell(String command) { // using the exec() system call nativeExecShell(command);}
2)通过寻找到相应目标类的main()函数并执行 RuntimeInit.zygoteInit: // The main function called when started through the zygote process.public static final void zygoteInit( ){zygoteInitNative();applicationInit(targetSdkVersion, argv);}private static void applicationInit( ) {// Remaining arguments are passed to the start class's static maininvokeStaticMain(args.startClass, args.startArgs);}
通过RuntimeInit调用startClass的main函数,进而以异常的方式启动新的进程。
static void invokeStaticMain(ClassLoader loader, String className, String[] argv) throws ZygoteInit.MethodAndArgsCaller { .... /* * This throw gets caught in ZygoteInit.main(), which responds * by invoking the exception's run() method. This arrangement * clears up all the stack frames that were required in setting * up the process. */ throw new ZygoteInit.MethodAndArgsCaller(m, argv); }
更多相关文章
- 跑马灯效果实现方式三种
- android获取CPU参数(命令行方式)
- Android使用okHttp(get方式)登录
- Android分享到腾讯微博,信息,新浪微博等等,的实现方式
- 第四例:Intent启动Activity的几种方式(一)
- Android Studio 中module需要单独引用jdk的方式
- android 栈方式退出
- 绑定方式开始服务&调用服务的方法