精华内容
参与话题
问答
  • zygote

    2019-07-30 01:26:20
    NULL 博文链接:https://yishizhu.iteye.com/blog/843632
  • Zygote

    千次阅读 2016-08-01 17:24:09
    在Android中,zygote是整个系统创建新进程的核心装置。zygote进程在内部会先启动Dalvik虚拟机,继而加载一些必要的系统资源和系统类,最后进入一种监听状态。  在之后的运作中,当其他系统模块(比如AMS)希望创建...

    相关源码:

    /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<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        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 proc
    private 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 main
    invokeStaticMain(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);
        }





    展开全文
  • 认识Zygote

    千次阅读 2016-06-07 22:37:36
    概述zygote “受精卵”,由init进程通过解析init.zygote.rc文件而创建的,zygote所对应的可执行程序app_process,所对应的源文件是App_main.cpp,进程名为zygotezygote孵化的第一个进程是System Server,而这两个...

    概述

    在java中不同的虚拟机实例会为不同的应用分配不同内存,为了使Android系统尽快启动,使用了Zygote来预加载核心类库和一些加载时间长的类(超过1250ms),让Dalvik虚拟机共享代码,降低占用内存和启动时间。
    zygote 中文为“受精卵”,由init进程通过解析init.zygote.rc文件而创建的,zygote所对应的可执行程序app_process,所对应的源文件是App_main.cpp,进程名为zygote。zygote孵化的第一个进程是System Server,而这两个都是java世界的半边天,任何一个进程死亡都会导致Java世界的奔溃。

    4.2 zygote分析

    zygote进程由init进程根据init.rc文件中配置创建,是android系统首个java进程,是所有java进程的父进程,zygote最初名字叫“app_process”,这个名字是在Android.mk文件中指定的,但是在运行过程中Linux下的pctrl系统调用将自己名字换成了“zygote”,因此通过ps命令查看到进程名称为”zygote”.原型app_process所对应的源文件是App_main.cpp

    涉及到的函数调用

    `App_main.main
    AndroidRuntime.start
        startVm
        startReg
        ZygoteInit.main
            registerZygoteSocket
            preload
            startSystemServer
            runSelectLoop`
    

    从AndroidRuntime到ZygoteInit

    主要分为2大过程

    1、创建虚拟机——startVm:调用JNI虚拟机创建函数

    2、注册JNI函数——startReg:前面已经创建虚拟机,这里就需要给这个虚拟机注册一些JNI函数(后续java世界用到的函数是native实现,这里需要提前注册注册这些函数)

    此时就要执行CallStaticViodMethod,通过这个函数将进入android精心打造的java世界,这个函数将调用com.android.internal.os.ZygoteInit的main函数

    进入java世界

    在 ZygoteInit.main函数中进入java世界,但是这个世界啥都没与需要做很多初始化工作,主要有4个关键步骤

    1、建立IPC通信服务——registerZygoteSocket

    zygote及系统中其他程序的通信并没有使用Binder,而是采用基于AF_UNIX类型的Socket,registerZygoteSocket函数的作用正是建立这个Socket

    预加载类和资源

    主要是preloadClasses和preloadResources,其中preloadClasses一般是加载时间超过1250ms的类,因而需要在zygote预加载

    启动system_server——startSystemServer

    这个函数会创建Java世界中系统Service所驻留的进程system_server,该进程是framework的核心,也是zygote孵化出的第一个进程。如果它死了,就会导致zygote自杀。

    等待请求——runSelectLoppMode

    zygote从startSystemServer返回后,将进入第四个关键函数runSelectLoppMode,在第一个函数registerZygoteSocket中注册了一个用于IPC的Socket将在这里使用,这里Zygote采用高效的I/O多路复用机制,保证在没有客户端请求时或者数据处理时休眠,否则响应客户端的请求

    此时zygote完成了java世界的初创工作,调用runSelectLoppMode便开始休眠了,当收到请求或者数据处理便会随时醒来,继续工作

    zygote的分裂

    zygote主要用来孵化system_server进程和应用程序进程。在孵化出第一个进程system_server后通过runSelectLoopMode等待并处理消息,分裂应用程序进程仍由system_server控制,如app启动时创建子进程

    小结:

    宏观把握了zygote的诞生到创建java世界的的过程

    参考《深入理解android卷一》

    展开全文
  • 2.zygote进程有一个监听启动APP的socket。 当有收到启动App请求,fork出来的进程是否也包括这样的一个socket呢? 如果包括,这样两个进程监听同一个端口,不就导致资源冲突了吗? ![图片说明]...
  • Android系统进程Zygote启动过程的源代码分析

    万次阅读 多人点赞 2011-09-19 00:59:08
    在Android系统中,所有的应用程序进程以及系统服务进程SystemServer都是由Zygote进程孕育(fork)出来的,这也许就是为什么要把它称为Zygote(受精卵)的原因吧。由于Zygote进程在Android系统中有着如此重要的地位,...

            在Android系统中,所有的应用程序进程以及系统服务进程SystemServer都是由Zygote进程孕育(fork)出来的,这也许就是为什么要把它称为Zygote(受精卵)的原因吧。由于Zygote进程在Android系统中有着如此重要的地位,本文将详细分析它的启动过程。

    《Android系统源代码情景分析》一书正在进击的程序员网(http://0xcc0xcd.com)中连载,点击进入!

            在前面一篇文章Android应用程序进程启动过程的源代码分析中,我们看到了,当ActivityManagerService启动一个应用程序的时候,就会通过Socket与Zygote进程进行通信,请求它fork一个子进程出来作为这个即将要启动的应用程序的进程;在前面两篇文章Android应用程序安装过程源代码分析Android系统默认Home应用程序(Launcher)的启动过程源代码分析中,我们又看到了,系统中的两个重要服务PackageManagerService和ActivityManagerService,都是由SystemServer进程来负责启动的,而SystemServer进程本身是Zygote进程在启动的过程中fork出来的。

            我们知道,Android系统是基于Linux内核的,而在Linux系统中,所有的进程都是init进程的子孙进程,也就是说,所有的进程都是直接或者间接地由init进程fork出来的。Zygote进程也不例外,它是在系统启动的过程,由init进程创建的。在系统启动脚本system/core/rootdir/init.rc文件中,我们可以看到启动Zygote进程的脚本命令:

    service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
        socket zygote stream 666
        onrestart write /sys/android_power/request_state wake
        onrestart write /sys/power/state on
        onrestart restart media
        onrestart restart netd
    
            前面的关键字service告诉init进程创建一个名为"zygote"的进程,这个zygote进程要执行的程序是/system/bin/app_process,后面是要传给app_process的参数。

            接下来的socket关键字表示这个zygote进程需要一个名称为"zygote"的socket资源,这样,系统启动后,我们就可以在/dev/socket目录下看到有一个名为zygote的文件。这里定义的socket的类型为unix domain socket,它是用来作本地进程间通信用的,具体可以参考前面一篇文章Android学习启动篇提到的一书《Linux内核源代码情景分析》的第七章--基于socket的进程间通信。前面我们说到的ActivityManagerService就是通这个socket来和zygote进程通信请求fork一个应用程序进程的了。

            最后的一系列onrestart关键字表示这个zygote进程重启时需要执行的命令。

            关于init.rc文件的更多信息,请参考system/core/init/readme.txt文件。

            了解了这个信息之后,我们就知道Zygote进程要执行的程序便是system/bin/app_process了,它的源代码位于frameworks/base/cmds/app_process/app_main.cpp文件中,入口函数是main。在继续分析Zygote进程启动的过程之前,我们先来看看它的启动序列图:


            下面我们就详细分析每一个步骤。

            Step 1. app_process.main

            这个函数定义在frameworks/base/cmds/app_process/app_main.cpp文件中:

    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;
    	const char *arg;
    	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)) {
    			bool startSystemServer = (i < argc) ?
    				strcmp(argv[i], "--start-system-server") == 0 : false;
    			setArgv0(argv0, "zygote");
    			set_process_name("zygote");
    			runtime.start("com.android.internal.os.ZygoteInit",
    				startSystemServer);
    		} else {
    			set_process_name(argv0);
    
    			runtime.mClassName = arg;
    
    			// Remainder of args get passed to startup class main()
    			runtime.mArgC = argc-i;
    			runtime.mArgV = argv+i;
    
    			LOGV("App process is starting with pid=%d, class=%s.\n",
    				getpid(), runtime.getClassName());
    			runtime.start();
    		}
    	} else {
    		LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    		fprintf(stderr, "Error: no class name or --zygote supplied.\n");
    		app_usage();
    		return 10;
    	}
    
    }
            这个函数的主要作用就是创建一个AppRuntime变量,然后调用它的start成员函数。AppRuntime这个类我们在Android应用程序进程启动过程的源代码分析一文中已经有过介绍了,它同样是在frameworks/base/cmds/app_process/app_main.cpp文件中定义:

    class AppRuntime : public AndroidRuntime
    {
    	......
    };
            它约继承于AndroidRuntime类, AndroidRuntime类定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中:

    ......
    
    static AndroidRuntime* gCurRuntime = NULL;
    
    ......
    
    AndroidRuntime::AndroidRuntime()
    {
    	......
    
    	assert(gCurRuntime == NULL);        // one per process
    	gCurRuntime = this;
    }
            当AppRuntime对象创建时,会调用其父类AndroidRuntime的构造函数,而在AndroidRuntime类的构造函数里面,会将this指针保存在静态全局变量gCurRuntime中,这样,当其它地方需要使用这个AppRuntime对象时,就可以通过同一个文件中的这个函数来获取这个对象的指针:

    AndroidRuntime* AndroidRuntime::getRuntime()
    {
        return gCurRuntime;
    }
    
            回到上面的main函数中,由于我们在init.rc文件中,设置了app_process启动参数--zygote和--start-system-server,因此,在main函数里面,最终会执行下面语句:

        runtime.start("com.android.internal.os.ZygoteInit",
    	startSystemServer);
            这里的参数startSystemServer为true,表示要启动SystemServer组件。由于AppRuntime没有实现自己的start函数,它继承了父类AndroidRuntime的start函数,因此,下面会执行AndroidRuntime类的start函数。

            Step 2. AndroidRuntime.start

            这个函数定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中:

    /*
    * 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);
    			......
    		}
    	}
    
    	......
    }

            这个函数的作用是启动Android系统运行时库,它主要做了三件事情,一是调用函数startVM启动虚拟机,二是调用函数startReg注册JNI方法,三是调用了com.android.internal.os.ZygoteInit类的main函数。

            Step 3. ZygoteInit.main

            这个函数定义在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) {
    			......
    		}
    	}
    
    	......
    }
             它主要作了三件事情,一个调用registerZygoteSocket函数创建了一个socket接口,用来和ActivityManagerService通讯,二是调用startSystemServer函数来启动SystemServer组件,三是调用runSelectLoopMode函数进入一个无限循环在前面创建的socket接口上等待ActivityManagerService请求创建新的应用程序进程。

             Step 4. ZygoteInit.registerZygoteSocket

             这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:

    public class ZygoteInit {
    	......
    
    	/**
    	* Registers a server socket for zygote command connections
    	*
    	* @throws RuntimeException when open fails
    	*/
    	private static void registerZygoteSocket() {
    		if (sServerSocket == null) {
    			int fileDesc;
    			try {
    				String env = System.getenv(ANDROID_SOCKET_ENV);
    				fileDesc = Integer.parseInt(env);
    			} catch (RuntimeException ex) {
    				......
    			}
    
    			try {
    				sServerSocket = new LocalServerSocket(
    					createFileDescriptor(fileDesc));
    			} catch (IOException ex) {
    				.......
    			}
    		}
    	}
    		
    	......
    }
             这个socket接口是通过文件描述符来创建的,这个文件描符代表的就是我们前面说的/dev/socket/zygote文件了。这个文件描述符是通过环境变量ANDROID_SOCKET_ENV得到的,它定义为:

    public class ZygoteInit {
    	......
    
    	private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";
    		
    	......
    }
            那么,这个环境变量的值又是由谁来设置的呢?我们知道,系统启动脚本文件system/core/rootdir/init.rc是由init进程来解释执行的,而init进程的源代码位于system/core/init目录中,在init.c文件中,是由service_start函数来解释init.rc文件中的service命令的:

    void service_start(struct service *svc, const char *dynamic_args)
    {
    	......
    
    	pid_t pid;
    
    	......
    
    	pid = fork();
    
    	if (pid == 0) {
    		struct socketinfo *si;
    
    		......
    
    		for (si = svc->sockets; si; si = si->next) {
    			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);
    			if (s >= 0) {
    				publish_socket(si->name, s);
    			}
    		}
    
    		......
    	}
    
    	......
    }
            每一个service命令都会促使init进程调用fork函数来创建一个新的进程,在新的进程里面,会分析里面的socket选项,对于每一个socket选项,都会通过create_socket函数来在/dev/socket目录下创建一个文件,在这个场景中,这个文件便是zygote了,然后得到的文件描述符通过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));
        snprintf(val, sizeof(val), "%d", fd);
        add_environment(key, val);
    
        /* make sure we don't close-on-exec */
        fcntl(fd, F_SETFD, 0);
    }
    
           这里传进来的参数name值为"zygote",而ANDROID_SOCKET_ENV_PREFIX在system/core/include/cutils/sockets.h定义为:

    #define ANDROID_SOCKET_ENV_PREFIX	"ANDROID_SOCKET_"
    
            因此,这里就把上面得到的文件描述符写入到以"ANDROID_SOCKET_zygote"为key值的环境变量中。又因为上面的ZygoteInit.registerZygoteSocket函数与这里创建socket文件的create_socket函数是运行在同一个进程中,因此,上面的ZygoteInit.registerZygoteSocket函数可以直接使用这个文件描述符来创建一个Java层的LocalServerSocket对象。如果其它进程也需要打开这个/dev/socket/zygote文件来和Zygote进程进行通信,那就必须要通过文件名来连接这个LocalServerSocket了,参考Android应用程序进程启动过程的源代码分析一文中的Step 4,ActivityManagerService是通过Process.start函数来创建一个新的进程的,而Process.start函数会首先通过Socket连接到Zygote进程中,最终由Zygote进程来完成创建新的应用程序进程,而Process类是通过openZygoteSocketIfNeeded函数来连接到Zygote进程中的Socket的:

    public class Process {  
    	......  
     
    	private static void openZygoteSocketIfNeeded()  
    			throws ZygoteStartFailedEx {  
    
    		......
    
    		for (int retry = 0  
    			; (sZygoteSocket == null) && (retry < (retryCount + 1))  
    			; retry++ ) {  
    
    				......
    
    				try {  
    					sZygoteSocket = new LocalSocket();  
    					sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,  
    						LocalSocketAddress.Namespace.RESERVED));  
    
    					sZygoteInputStream  
    						= new DataInputStream(sZygoteSocket.getInputStream());  
    
    					sZygoteWriter =  
    						new BufferedWriter(  
    						new OutputStreamWriter(  
    						sZygoteSocket.getOutputStream()),  
    						256);  
    
    					......  
    				} catch (IOException ex) {  
    					......  
    				}  
    		}  
    
    		......  
    	}  
    
    	......  
    }
            这里的ZYGOTE_SOCKET定义为:

    public class Process {  
    	......  
     
    	private static final String ZYGOTE_SOCKET = "zygote";  
    
    	......  
    } 
            它刚好就是对应/dev/socket目录下的zygote文件了。

            Android系统中的socket机制和binder机制一样,都是可以用来进行进程间通信,读者可以自己对比一下这两者的不同之处,Binder进程间通信机制可以参考Android进程间通信(IPC)机制Binder简要介绍和学习计划一文。

           Socket对象创建完成之后,回到Step 3中的ZygoteInit.main函数中,startSystemServer函数来启动SystemServer组件。

           Step 5. ZygoteInit.startSystemServer
           这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:

    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);
    		} catch (IllegalArgumentException ex) {
    			......
    		}
    
    		/* For child process */
    		if (pid == 0) {
    			handleSystemServerProcess(parsedArgs);
    		}
    
    		return true;
    	}
    	
    	......
    }
            这里我们可以看到,Zygote进程通过Zygote.forkSystemServer函数来创建一个新的进程来启动SystemServer组件,返回值pid等0的地方就是新的进程要执行的路径,即新创建的进程会执行handleSystemServerProcess函数。

            Step 6. ZygoteInit.handleSystemServerProcess
            这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:

    public class ZygoteInit {
    	......
    
    	private static void handleSystemServerProcess(
    			ZygoteConnection.Arguments parsedArgs)
    			throws ZygoteInit.MethodAndArgsCaller {
    		closeServerSocket();
    
    		/*
    		* Pass the remaining arguments to SystemServer.
    		* "--nice-name=system_server com.android.server.SystemServer"
    		*/
    		RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
    		/* should never reach here */
    	}
    
    	......
    } 
            由于由Zygote进程创建的子进程会继承Zygote进程在前面Step 4中创建的Socket文件描述符,而这里的子进程又不会用到它,因此,这里就调用closeServerSocket函数来关闭它。这个函数接着调用RuntimeInit.zygoteInit函数来进一步执行启动SystemServer组件的操作。

            Step 7. RuntimeInit.zygoteInit

            这个函数定义在frameworks/base/core/java/com/android/internal/os/RuntimeInit.java文件中:

    public class RuntimeInit {  
    	......  
    
    	public static final void zygoteInit(String[] argv)  
    			throws ZygoteInit.MethodAndArgsCaller {  
    		......  
      
    		zygoteInitNative();  
    
    		......  
    
    
    		// Remaining arguments are passed to the start class's static main  
    
    		String startClass = argv[curArg++];  
    		String[] startArgs = new String[argv.length - curArg];  
    
    		System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);  
    		invokeStaticMain(startClass, startArgs);  
    	}  
    
    	......  
    }
             这个函数会执行两个操作,一个是调用zygoteInitNative函数来执行一个Binder进程间通信机制的初始化工作,这个工作完成之后,这个进程中的Binder对象就可以方便地进行进程间通信了,另一个是调用上面Step 5传进来的com.android.server.SystemServer类的main函数。

             Step 8. RuntimeInit.zygoteInitNative

             这个函数定义在frameworks/base/core/java/com/android/internal/os/RuntimeInit.java文件中:

    public class RuntimeInit {  
    	......  
    
    	public static final native void zygoteInitNative();  
    
    	......  
    }
            这里可以看出,函数zygoteInitNative是一个Native函数,实现在frameworks/base/core/jni/AndroidRuntime.cpp文件中,这里我们就不再细看了,具体可以参考Android应用程序进程启动过程的源代码分析一文的Step 9,完成这一步后,这个进程的Binder进程间通信机制基础设施就准备好了。

            回到Step 7中的RuntimeInit.zygoteInitNative函数,下一步它就要执行com.android.server.SystemServer类的main函数了。

            Step 9. SystemServer.main

            这个函数定义在frameworks/base/services/java/com/android/server/SystemServer.java文件中:

    public class SystemServer  
    {  
    	......  
    
    	native public static void init1(String[] args);  
    
    	......  
    
    	public static void main(String[] args) {  
    		......  
    
    		init1(args);  
    
    		......  
    	} 
    
    	public static final void init2() {  
    		Slog.i(TAG, "Entered the Android system server!");  
    		Thread thr = new ServerThread();  
    		thr.setName("android.server.ServerThread");  
    		thr.start();  
    	}  
    
    	......  
    }
            这里的main函数首先会执行JNI方法init1,然后init1会调用这里的init2函数,在init2函数里面,会创建一个ServerThread线程对象来执行一些系统关键服务的启动操作,例如我们在前面两篇文章Android应用程序安装过程源代码分析Android系统默认Home应用程序(Launcher)的启动过程源代码分析中提到的PackageManagerService和ActivityManagerService。
            这一步的具体执行过程可以参考Android应用程序安装过程源代码分析一文,这里就不再详述了。

            这里执行完成后,层层返回,最后回到上面的Step 3中的ZygoteInit.main函数中,接下来它就要调用runSelectLoopMode函数进入一个无限循环在前面Step 4中创建的socket接口上等待ActivityManagerService请求创建新的应用程序进程了。

            Step 10. ZygoteInit.runSelectLoopMode

            这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:

    public class ZygoteInit {
    	......
    
    	private static void runSelectLoopMode() throws MethodAndArgsCaller {
    		ArrayList<FileDescriptor> fds = new ArrayList();
    		ArrayList<ZygoteConnection> peers = new ArrayList();
    		FileDescriptor[] fdArray = new FileDescriptor[4];
    
    		fds.add(sServerSocket.getFileDescriptor());
    		peers.add(null);
    
    		int loopCount = GC_LOOP_COUNT;
    		while (true) {
    			int index;
    
    			......
    
    
    			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);
    				}
    			}
    		}
    	}
    
    	......
    }      
            这个函数我们已经在Android应用程序进程启动过程的源代码分析一文的Step 5中分析过了,这就是在等待ActivityManagerService来连接这个Socket,然后调用ZygoteConnection.runOnce函数来创建新的应用程序,有兴趣的读者可以参考Android应用程序进程启动过程的源代码分析这篇文章,这里就不再详述了。

            这样,Zygote进程就启动完成了,学习到这里,我们终于都对Android系统中的进程有了一个深刻的认识了,这里总结一下:

            1. 系统启动时init进程会创建Zygote进程,Zygote进程负责后续Android应用程序框架层的其它进程的创建和启动工作。

            2. Zygote进程会首先创建一个SystemServer进程,SystemServer进程负责启动系统的关键服务,如包管理服务PackageManagerService和应用程序组件管理服务ActivityManagerService。

            3. 当我们需要启动一个Android应用程序时,ActivityManagerService会通过Socket进程间通信机制,通知Zygote进程为这个应用程序创建一个新的进程。

    老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注!

    展开全文
  • Android6.0 Zygote进程

    千次阅读 2016-08-20 13:16:45
    Android Zygote进程

    背景
    从字面上看,zygote是受精卵的意思,它的主要工作就是进行细胞分裂。

    在Android中,zygote的行为就如同受精卵一样,在系统发出请求时,负责分裂出其它的进程。

    Android为什么要这么设计呢?

    要知道从受精卵分裂出来的细胞,将继承受精卵的DNA。这些细胞只需要按照规则复制DNA就行了,而不需要重新思考DNA应该怎么排序。

    大概也可以按照这个思路来理解zygote进程吧。

    zygote进程启动时,将在内部启动Dalvik虚拟机,注册JNI函数,继而加载一些必要的系统资源和必要类等,然后进入到监听状态。

    在后续的运作中,当其它系统模块希望创建新进程时,只需向zygote进程发出请求。zygote进程监听到该请求后,会相应地“分裂”出新的进程。

    于是新创建出的进程,从一开始就具有了自己的Dalvik虚拟机以及一些必要的系统资源。这将减少每个进程启动消耗的时间。进一步来说,由于fork的copy-on-write策略,zygote的这种分裂方式还有可能减少系统整体内存的占用。

    版本
    android 6.0

    主要流程分析
    在分析init进程时,我们知道init进程会解析init.rc文件,然后加载对应的进程。zygote就是以这种方式,被init进程加载的。

    在system/core/rootdir/init.rc中,可以看到:

    import /init.${ro.zygote}.rc
    

    从import的文件命名方式,我们可以看出在不同的平台(32、64及64_32)上,init.rc将包含不同的zygote.rc文件。不同的zygote.rc内容大致相同,主要区别体现在启动的是32位,还是64位的进程。

    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
        writepid /dev/cpuset/foreground/tasks
    

    以上是init.zygote32.rc中的内容。

    从init.zygote32.rc可以看出,zygote实际上对应于app_process进程,对应源文件为frameworks/base/cmds/app_process/app_main.cpp,其main函数对应的传入参数为:–zygote, --start-system-server 。

    这里需要补充说明的是:
    1、在init.zygote64.rc中,启动的进程为app_process64;在init.zyote64_32.rc中,会启动两个进程,分别为app_process64和app_process32(目前,不太清楚这种设置的实际含义)。
    2、从zyote的rc文件,我们可以看到zygote启动的时候,创建了一个socket(后文将介绍这个socket)。

    接下来我们按照zygote进程启动涉及文件的先后顺序,一起来看看zygote的主要工作情况。

    1、app_main.cpp
    首先从入口文件app_main.cpp的main函数开始分析。

    int main(int argc, char* const argv[])
    {
    	//AppRuntime定义于app_main.cpp中,继承自AndroidRuntime
    	//个人感觉该对象就是对Android运行时环境的一种抽象
    	AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    	..........
    	//开始解析输入参数
    	while (i < argc) {
            const char* arg = argv[i++];
            if (strcmp(arg, "--zygote") == 0) {
                //init.zygote.rc中定义了该字段
                zygote = true;
                //记录app_process进程名的nice name,即zygote
                niceName = ZYGOTE_NICE_NAME;
            } else if (strcmp(arg, "--start-system-server") == 0) {
    	        //init.zygote.rc中定义了该字段
                startSystemServer = true;
            } else if (strcmp(arg, "--application") == 0) {
                application = true;
            } else if (strncmp(arg, "--nice-name=", 12) == 0) {
                niceName.setTo(arg + 12);
            } else if (strncmp(arg, "--", 2) != 0) {
                className.setTo(arg);
                break;
            } else {
                --i;
                break;
            }
        }
        ..........
        //准备下一个函数调用所需的参数
        Vector<String8> args;
    	if (!className.isEmpty()) {
    		//启动zygote时,class name is empty,不进入该分支
    		........
    	} else {
    		//创建dalvikCache所需的目录,并定义权限
    		maybeCreateDalvikCache();
    		
    		if (startSystemServer) {
    			//增加参数
                args.add(String8("start-system-server"));
            }
    		.........
    		for (; i < argc; ++i) {
    			//将main函数未处理的参数都递交给下个调用函数处理
                args.add(String8(argv[i]));
            }
    	}
    	
    	if (!niceName.isEmpty()) {
    		//将app_process的进程名,替换为zygote
            runtime.setArgv0(niceName.string());
            set_process_name(niceName.string());
        }
    	
    	if (zygote) {
    		//调用Runtime的start函数
            runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
        } else if (className) {
    	    //启动zygote没有进入这个分支,但这个分支说明,通过配置init.rc文件,其实是可以不通过zygote来启动一个进程
            runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
        } else {
            ...............
        }
    }
    

    由于AppRuntime继承自AndroidRuntime,且没有重写start方法,因此zygote的流程进入到了AndroidRuntime.cpp。

    2、AndroidRuntime.cpp
    我们一起来看看在AndroidRuntime的start函数中,进行了哪些重要操作:

    void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) {
    	.........
        JniInvocation jni_invocation;
        jni_invocation.Init(NULL);
        JNIEnv* env;
        //创建虚拟机,其中大多数参数由系统属性决定
        //最终,startVm利用JNI_CreateVM创建出虚拟机
        if (startVm(&mJavaVM, &env, zygote) != 0) {
            return;
        }
    	...........
    	//注册JNI函数
    	if (startReg(env) < 0) {
            ALOGE("Unable to register all android natives\n");
            return;
        }
        ......
    

    ==以下非主干部分

    我们先来看看startReg具体是在干什么。

    int AndroidRuntime::startReg(JNIEnv* env) {
    	..........
    	if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
            env->PopLocalFrame(NULL);
            return -1;
        }
    	........
    }
    

    从上述代码可以看出,startReg函数中主要是通过register_jni_procs来注册JNI函数。

    其中,gRegJNI是一个全局数组,该数组的定义类似于:

    static const RegJNIRec gRegJNI[] = {
        REG_JNI(register_android_util_SeempLog),
        REG_JNI(register_com_android_internal_os_RuntimeInit),
        REG_JNI(register_android_os_SystemClock),
        REG_JNI(register_android_util_EventLog),
        ............
    

    其中,REG_JNI的宏定义及RegJNIRec结构体的定义为:

    #ifdef NDEBUG
        #define REG_JNI(name)      { name }
        struct RegJNIRec {
            int (*mProc)(JNIEnv*);
        };
    #else
        #define REG_JNI(name)      { name, #name }
        struct RegJNIRec {
            int (*mProc)(JNIEnv*);
            const char* mName;
        };
    #endif
    

    根据宏定义可以看出,宏REG_JNI将得到函数名;定义RegJNIRec数组时,函数名被赋值给RegJNIRec结构体,于是每个函数名被强行转换为函数指针。

    明白宏及数组的定义后,我们再回头来看register_jni_procs的定义:

    static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
    {
        for (size_t i = 0; i < count; i++) {
            if (array[i].mProc(env) < 0) {
    #ifndef NDEBUG
                ALOGD("----------!!! %s failed to load\n", array[i].mName);
    #endif
                return -1;
            }
        }
        return 0;
    }
    

    结合前面的分析,容易知道register_jni_procs函数,实际上就是调用函数指针对应的函数,以进行实际的JNI函数注册。

    我们随意举个例子,看看register_android_util_SeempLog被调用时的情况:

    /*
     * JNI registration.
     */
    static JNINativeMethod gMethods[] = {
        /* name, signature, funcPtr */
        { "seemp_println_native",  "(ILjava/lang/String;)I",
                (void*) android_util_SeempLog_println_native },
    };
    
    int register_android_util_SeempLog(JNIEnv* env)
    {
        jclass clazz = env->FindClass("android/util/SeempLog");
        if (clazz == NULL) {
            return -1;
        }
    
        return AndroidRuntime::registerNativeMethods(env, "android/util/SeempLog", gMethods, NELEM(gMethods));
    }
    

    可以看到,这实际上是自己定义JNI函数并进行动态注册的标准写法。

    int AndroidRuntime::registerNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods)
    {
        return jniRegisterNativeMethods(env, className, gMethods, numMethods);
    }
    

    最后,还是利用jniRegisterNativeMethods进行实际的注册工作。

    ==以上非主干部分

    在介绍完AndroidRuntime.cpp中注册JNI的工作后,我们将思路拉回到它的start函数。

    	........
    	//将"com.android.internal.os.ZygoteInit"替换为"com/android/internal/os/ZygoteInit"
    	char* slashClassName = toSlashClassName(className);
        jclass startClass = env->FindClass(slashClassName);
        if (startClass == NULL) {
            ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
            /* keep going */
        } else {
    	    //通过反射找到ZygoteInit的main函数
            jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V");
            if (startMeth == NULL) {
                ALOGE("JavaVM unable to find main() in '%s'\n", className);
                /* keep going */
            } else {
    	        //调用ZygoteInit的main函数
                env->CallStaticVoidMethod(startClass, startMeth, strArray);
    		........
    

    当调用ZygoteInit.java的main函数后,zygote进程进入了java世界。

    其实我们仔细想一想,就会觉得zygote的整个流程实际上是非常符合实际情况的。

    在Android中,每个进程都运行在对应的虚拟机上,因此zygote首先就负责创建出虚拟机。

    然后,为了反射调用java代码,必须有对应的JNI函数,于是zygote进行了JNI函数的注册。

    当一切准备妥当后,zygote进程才进入到了java世界。

    3、ZygoteInit.java

     public static void main(String argv[]) {
    	try {
    		.........
    		String socketName = "zygote";
    		.........
    		//注册server socket
    		registerZygoteSocket(socketName);
    		.........
    		//预加载
    		preload();
    		.........
    		if (startSystemServer) {
    			//启动system server
    			startSystemServer(abiList, socketName);
    		}
    
    		//zygote进程进入无限循环,处理请求
    		runSelectLoop(abiList);
    
    		closeServerSocket();
    	} catch (MethodAndArgsCaller caller) {
    		//通过反射调用新进程函数的地方
    		//后续介绍新进程启动时,再介绍
    		caller.run();
        } catch (RuntimeException ex) {
    		closeServerSocket();
    		throw ex;
    	}
    }
    

    上面是ZygoteInit的main函数的主干部分,接下来我们进一步分析它们的主要工作。

    3.1 创建server socket

    private static void registerZygoteSocket(String socketName) {
    	if (sServerSocket == null) {
    		int fileDesc;
    		//此处的socket name,就是zygote
    		final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
    		try {
    			//记得么?在init.zygote.rc被加载时,就会创建一个名为zygote的socket
    			String env = System.getenv(fullSocketName);
    			fileDesc = Integer.parseInt(env);
    		} catch (RuntimeException ex) {
    			throw new RuntimeException(fullSocketName + " unset or invalid", ex);
    		}
    
    		try {
    			FileDescriptor fd = new FileDescriptor();
    			//获取zygote socket的文件描述符
    			fd.setInt$(fileDesc);
    			//将zygote socket包装成一个server socket
    			sServerSocket = new LocalServerSocket(fd);
    		} catch (IOException ex) {
    			throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex);
    		}
    	}
    }
    

    zygote进程与系统中其它进程的通信没有使用Binder,而是采用了基于AF_UNIX类型的socket。(实际上,在这个时候Binder根本无法使用)。

    3.2 预加载

    static void preload() {
    	Log.d(TAG, "begin preload");
    	//读取文件framework/base/preloaded-classes,然后通过反射加载对应的类
    	//需要加载数千个类,启动慢的原因之一
    	preloadClasses();
    	//负载加载一些常用的系统资源
    	preloadResources();
    	//图形相关的
    	preloadOpenGL();
    	//一些必要库
    	preloadSharedLibraries();
    	//好像是语言相关的字符信息
    	preloadTextResources();
    	// 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");
    }
    

    为了让系统实际运行时更加流畅,在zygote启动时候,调用preload函数进行了一些预加载操作。

    Android 通过zygote fork的方式创建子进程。zygote进程预加载这些类和资源,在fork子进程时,仅需要做一个复制即可。

    这样可以节约子进程的启动时间。同时,根据fork的copy-on-write机制可知,有些类如果不做改变,甚至都不用复制,子进程可以和父进程共享这部分数据,从而省去不少内存的占用。

    3.3 启动SystemServer进程

    private static boolean startSystemServer(String abiList, String socketName) {
    	//准备capabilities参数
    	........
    	String args[] = {
    		"--setuid=1000",
    		"--setgid=1000",
            "--setgroups=.........",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;
    
    	int pid;
    
    	try {
    		//将上面准备的参数,按照ZygoteConnection的风格进行封装
    		parsedArgs = new ZygoteConnection.Arguments(args);
    		...........
    
    		//通过fork"分裂"出system server,具体的过程在介绍system server时再分析
    		/* 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);
    	}
    	
    	if (pid == 0) {
    		............
    		//pid = 0, 在进程system server中
    		//system server进程处理自己的工作
    		handleSystemServerProcess(parsedArgs);
    	}
    
        return true;
    }
    

    3.4 处理请求信息

    创建出SystemServer进程后,zygote进程利用函数runSelectLoop,处理server socket收到的命令。

    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
    	ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    
    	//首先将server socket加入到fds
        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);
    
    	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);
    		}
    		//注意这里是倒序的
    		for (int i = pollFds.length - 1; i >= 0; --i) {
    			if ((pollFds[i].revents & POLLIN) == 0) {
    				continue;
    			}
    			//server socket最先加入fds, 因此这里是server socket收到数据
    			if (i == 0) {
    			    //收到新的建立通信的请求,建立通信连接
    				ZygoteConnection newPeer = acceptCommandPeer(abiList);
    				//加入到peers和fds
    				peers.add(newPeer);
    				fds.add(newPeer.getFileDesciptor());
    			 } else {
    				//其它通信连接收到数据,runOnce执行对应命令
    				boolean done = peers.get(i).runOnce();
    				if (done) {
    					//对应通信连接不再需要执行其它命令,关闭并移除
    					peers.remove(i);
                        fds.remove(i);
                    }
    			}
    		}
    	}
    }
    

    从上面代码可知,初始时,fds中仅有server socket,因此当有数据到来时,将执行i等于0的分支。
    此时,显然是需要创建新的通信连接,因此acceptCommandPeer将被调用。

    private static ZygoteConnection acceptCommandPeer(String abiList) {
    	try {
    		return new ZygoteConnection(sServerSocket.accept(), abiList);
    	} catch (IOException ex) {
    		throw new RuntimeException("IOException during accept()", ex);
        }
    }
    

    acceptCommandPeer封装了socket的accpet函数。于是我们知道,对应的新的连接,zygote将会创建出一个新的socket与其通信,并将该socket加入到fds中。因此,一旦通信连接建立后,fds中将会包含有多个socket。

    当poll监听到这一组sockets上有数据到来时,就会从阻塞中恢复。于是,我们需要判断到底是哪个socket收到了数据。

    在runSelectLoop中采用倒序的方式轮询,由于server socket第一个被加入到fds,因此最后轮询到的socket才需要处理新建连接的操作;其它socket收到数据时,仅需要调用zygoteConnection的runonce函数执行数据对应的操作。

    若一个连接处理完所有对应消息后,该连接对应的socket和连接等将被移除。

    socket编程中,accept()调用主要用在基于连接的套接字类型,比如SOCK_STREAM和SOCK_SEQPACKET。
    它提取出所监听套接字的等待连接队列中第一个连接请求,创建一个新的套接字,并返回指向该套接字的文件描述符。
    新建立的套接字不在监听状态,原来所监听的套接字的状态也不受accept()调用的影响。

    结束语
    以上是自己对zygote进程的一些初步分析,我们知道了zygote如何由init进程加载后,一步一步地进入到java世界。由于经验原因,自己的分析难免存在纰漏和不够详细的地方,欢迎大家指正。

    展开全文
  • 作者说这是一个系列的...Zygote 的中文意思是受精卵、合子,可以理解为孵化器——Android 中大多数应用进程和系统进程都是通过 Zygote 来生成的。 PS:源码基于 Android API 27。 Zygote 是怎么启动的? init ...
  • Android Zygote源码分析

    千次阅读 2015-04-29 20:33:32
    zygote分析 AppRuntime分析 创建虚拟机startVm 注册JNI函数startReg 进入JAVA世界 建立IPC通信服务端registerZygoteSocket 预加载类和资源preload 启动system_server 有求必应之等待请求runSelectLoop 概述在Android...
  • Zygote进程

    2019-01-22 15:11:26
    Zygote简介 zygote是Android一个非常重要的进程,和init、systemServer进程这三个进程是Android系统非常重要的进程。 Linux的进程是通过fork产生,fork出来的进程除了一些核心数据结构和父进程不一样,其余的内存...
  • Zygote分析

    千次阅读 2017-03-19 17:53:11
    Zygote进程是通过可执行文件app_process创建的,但是app_process除了能创建Zygote进程之外,还可以创建出普通进程。 今天就来说说,Zygote都做了那些事情,这个进程创建出了那些进程。Zygote是Android系统核心进程...
  • 启动zygote

    2016-12-23 16:18:17
    在init.rc中配置zygote启动参数,使用adb pull /init.rc ,文件和zygote相关配置信息如下。 service zygote /system/bin/app_process -Xzygote 5.2 启动Socket服务端口  当zygote服务从app_process启动后,会启动...
  • zygote详解

    2017-11-30 11:29:53
    在init进程详解的一章中,我们知道init.rc文件中的zygote启动脚本命令是service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main socket zygote stream 660 root...
  • Android Zygote

    2016-12-14 14:52:36
    Zygote 是android系统应用中一个相当重要的进程,其主要功能是执行Android应用程序。在android系统中运行新的应用,需要跟Zygote进程结合后才能执行。  Zygote进程运行时,会初始化Dalvik虚拟机,并启动它。android...
  • android zygote

    2019-05-19 16:41:53
    所有应用进程虚拟机,都是继承zygote,共享资源,加速应用启动。 启动sevice抛出异常,在异常信号中重启zygote 和systemServer 预加载资源: 预加载作用 查看加载时间: 优化方法, 多线程 ...
  • Android zygote

    2016-07-19 23:25:01
    zygote的作用: Android应用的神:每个应用对应一个进程,那么它们都是由zygote进程创建出来的。具体如下图: 1,linux内核启动的用户级进程 init 启动一个Zygote进程 2,Zygote创建出一个监听的进程为之...
  • zygote笔记

    2016-07-15 00:59:01
    新的android应用程序A并非通过fork来重新装载已有进程的代码区,而是被动的加载到复制出的Dalvik虚拟机上,Zygote进程将执行流程交给应用程序A类的方法. Zygote子进程动态加载并运行Android应用程序A 通过已加载至内存...
  • Zygote总结

    2018-12-19 17:17:00
    Zygote是由init进程通过解析init.zygote.rc文件而创建的,zygote所对应的可执行程序 app_process,所对应的源文件是App_main.cpp,进程名为zygoteZygote重启的情况(四种) servicemanager进程被杀; ...
  • Zygote详解

    2014-01-26 17:26:13
    class AppRuntime : public AndroidRuntime { public: AppRuntime() : mParentDir(NULL) , mClassName(NULL) , mClass(NULL) , mArgC(0) , mArgV(NULL) { }
  • Zygote Service

    2013-11-01 17:17:43
    在本章我们会接触到这两个单词: Zygote [生物] 受精卵, 接合子, 接合体 Spawn:产卵 通过这两个单词,我们就...其他进程作为一个客服端向Zygote发出”孵化”请求,Zygote接收到命令就“孵化”出一个Acti
  • Zygote简析

    2013-07-30 14:15:05
    Zygote是什么? Zygote 【n.合子,受精卵】 在Android系统中,它是一个非常重要的进程,所有的APP都是由Zygote来启动的。可以认为Zygote是所有APP的始祖。 通过ps命令可以看到以下信息:  root 255...

空空如也

1 2 3 4 5 ... 20
收藏数 3,641
精华内容 1,456
关键字:

zygote