相关源码:

/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_第1张图片

一、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层的调用示意图如下:

Zygote_第2张图片

2、 zygote在java层的调用主要是由ZygoteInit.java完成的,调用示意图如下:

Zygote_第3张图片


   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);    }





更多相关文章

  1. 跑马灯效果实现方式三种
  2. android获取CPU参数(命令行方式)
  3. Android使用okHttp(get方式)登录
  4. Android分享到腾讯微博,信息,新浪微博等等,的实现方式
  5. 第四例:Intent启动Activity的几种方式(一)
  6. Android Studio 中module需要单独引用jdk的方式
  7. android 栈方式退出
  8. 绑定方式开始服务&调用服务的方法

随机推荐

  1. 一定能成功的Android(安卓)NDK环境配置教
  2. 安卓手机恶意代码——Samsapo
  3. Android(安卓)之如何优化 UI 渲染(下)
  4. Android待机的suspend_sys_sync_queue分
  5. Android(安卓)MediaPlayer音频播放器详解
  6. Android(安卓)进程间通信之binder - 实战
  7. 推荐阅读:Android开发者的博客
  8. android的消息处理机制(图+源码分析)——Lo
  9. Android事件分发机制四:学了事件分发有什
  10. [Android(安卓)Pro] Android(安卓)手机ro