Zygote进程的分析



以下源码分析均基于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下包括四个关于zygoterc文件。分别是init.zygote32.rcinit.zygote32_64.rcinit.zygote64.rcinit.zygote64_32.rc。由硬件决定调用哪个文件。

 

下面开始分析源码:

1init.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:创建一个权限为660socket( 660 -rw-rw---- 拥有者和组用户都可读和写,其他人不能进行任何操作);onrestart:说明zygote在重启的时候需要执行的一些命令

app_process由关键字service告诉init进程创建一个名为“zygote”的进程,进程要执行的程序是/system/bin/app_process

最后,它会将四个参数: -Xzygote/system/bin--zygote --start-system-server传给进程。

 

2app_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;

}

}

说明:aAppRuntime 是支撑程序运行的基础库,例如包含虚拟机、java类库、JNI等。在这个main函数中最主要的作用也是创建AppRuntime,它是AndroidRuntime的一个子类。因此它还会去调用AndroidRuntimestart()函数。

 bAndroidRuntime的源码位置为: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)

 

3ZygoteInit.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请求创建新的应用程序进程。

4registerZygoteSocket()

 //  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启动时创建的socketfd,然后以此来创建server socket。注意这里用到的socket类型是LocalServerSocket它是AndroidLinux 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

bsocket 名字(带‘ANDROID_SOCKET_'前缀)(比如 zygote) fd 注册到init 进程的环境变量里,这样所有的其他进程(所有进程都是init的子进程)都可以通过 getenv(name)获取到这个fd.

5startSystemServer()

  //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;

    }

说明:从注释中也可以看出此函数准备forkSystemServer进程;在startSystemServer方法中,通过Zygote.forkSystemServer方法创建了一个子进程,并将其用户和用户组的ID设置为1000

注意这里fork出来的子进程在handleSystemServerProcess 里开始初始化工作,初始化分两步,一部在native 完成,另外一部分(大部分)在Java端完成。 native端的工作在AppRuntime(AndroidRuntime的子类)::onZygoteInit()完成,做的一件事情就是启动了一个Thread, 这个ThreadSystemServer的主线程, 负责接收来至其他进程的Binder调用请求。

6runSelectLoop()

    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.1ZygoteConnection.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.2handleChildProc()

 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进程就已经分析完成,例如当一个应用要启动的时候,AMSZygote进程的socket连接,请求fork出一个新的子进程。那么流程又会从6.1ZygoteConnection.runOnce()处顺势往下调用,那么后续代码流程又是怎样呢?下次再专门写一篇关于Android应用程序启动的文章吧~~~~######

总结:

zygote 进程在初始化时会启动虚拟机,并加载一些系统资源。这样当 zygote fork 出子进程后,子进程也继承了能正常工作的虚拟机和各种系统资源,接下来只需装载 apk 文件的字节码就可以运行应用程序了,可以大大缩短应用的启动时间,这就是 zygote 进程的主要作用。 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值