文章出处:http://blog.csdn.net/shift_wwx


前言:之前一篇博文(Android 的init过程详解)中记录了init启动过程,后来另一篇(Android init.rc详解 )中记录了init.rc的解析过程,android详细的启动过程,就需要将所有的init rc文件解剖之后,从action到service挨个分析。这里记录一下zygote的启动过程。


启动命令

init.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 media                                                        onrestart restart netd

通过app_process引导启动zygote,/system/bin/app_process 之后的都是命令参数。

接下来的socket关键字表示这个zygote进程需要一个名称为"zygote"的socket资源,这样,系统启动后,我们就可以在/dev/socket目录下看到有一个名为zygote的文件。ActivityManagerService就是通这个socket来和zygote进程通信请求fork一个应用程序进程的了。

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

详细的可以参考Android init.rc详解


下面来分析一下source code:

@/frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[]){#ifdef __arm__    /*     * b/7188322 - Temporarily revert to the compat memory layout     * to avoid breaking third party apps.     *     * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE.     *     * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466     * changes the kernel mapping from bottom up to top-down.     * This breaks some programs which improperly embed     * an out of date copy of Android's linker.     */    char value[PROPERTY_VALUE_MAX];    property_get("ro.kernel.qemu", value, "");    bool is_qemu = (strcmp(value, "1") == 0);    if ((getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) && !is_qemu) {        int current = personality(0xFFFFFFFF);        if ((current & ADDR_COMPAT_LAYOUT) == 0) {            personality(current | ADDR_COMPAT_LAYOUT);            setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1);            execv("/system/bin/app_process", argv);            return -1;        }    }    unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP");#endif    // 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* 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);    // Parse runtime arguments.  Stop at first unrecognized option.    bool zygote = false;    bool startSystemServer = false;    bool application = false;    const char* parentDir = NULL;    const char* niceName = NULL;    const char* className = NULL;    while (i < argc) {        const char* arg = argv[i++];        if (!parentDir) {            parentDir = arg;        } else if (strcmp(arg, "--zygote") == 0) {            zygote = true;            niceName = "zygote";        } else if (strcmp(arg, "--start-system-server") == 0) {            startSystemServer = true;        } else if (strcmp(arg, "--application") == 0) {            application = true;        } else if (strncmp(arg, "--nice-name=", 12) == 0) {            niceName = arg + 12;        } else {            className = arg;            break;        }    }    if (niceName && *niceName) {        setArgv0(argv0, niceName);        set_process_name(niceName);//进程名为zygote    }    runtime.mParentDir = parentDir;//没看懂是干嘛的,应该只是做个路径保存吧,/system/bin    if (zygote) {        runtime.start("com.android.internal.os.ZygoteInit",                startSystemServer ? "start-system-server" : "");//启动zygote    } else if (className) {//除了zygote,RuntimeInit也在这里启动        // Remainder of args get passed to startup class main()        runtime.mClassName = className;        runtime.mArgC = argc - i;        runtime.mArgV = argv + i;        runtime.start("com.android.internal.os.RuntimeInit",                application ? "application" : "tool");    } 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;    }}

刚开始的时候直接忽略了argv[0],直接从命令的路径开始,通过while循环逐个解析命令参数,parentDir、niceName、startSystemServer、zygote等等。

    if (niceName && *niceName) {        setArgv0(argv0, niceName);        set_process_name(niceName);    }
niceName是”zygote“,保存到了argv0,没看懂这个函数内部变量是干什么的?

设置了进程名为zygote。

@/syste/core/libcutils/process_name.c

void set_process_name(const char* new_name) {#ifdef HAVE_ANDROID_OS    char  propBuf[PROPERTY_VALUE_MAX];#endif    if (new_name == NULL) {        return;    }    // We never free the old name. Someone else could be using it.    int len = strlen(new_name);    char* copy = (char*) malloc(len + 1);    strcpy(copy, new_name);    process_name = (const char*) copy;#if defined(HAVE_PRCTL)    if (len < 16) {        prctl(PR_SET_NAME, (unsigned long) new_name, 0, 0, 0);    } else {        prctl(PR_SET_NAME, (unsigned long) new_name + len - 15, 0, 0, 0);    }#endif#ifdef HAVE_ANDROID_OS    // If we know we are not running in the emulator, then return.    if (running_in_emulator == 0) {        return;    }    // If the "running_in_emulator" variable has not been initialized,    // then do it now.    if (running_in_emulator == -1) {        property_get("ro.kernel.qemu", propBuf, "");        if (propBuf[0] == '1') {            running_in_emulator = 1;        } else {            running_in_emulator = 0;            return;        }    }    // If the emulator was started with the "-trace file" command line option    // then we want to record the process name in the trace even if we are    // not currently tracing instructions (so that we will know the process    // name when we do start tracing instructions).  We do not need to execute    // this code if we are just running in the emulator without the "-trace"    // command line option, but we don't know that here and this function    // isn't called frequently enough to bother optimizing that case.    int fd = open(PROCESS_NAME_DEVICE, O_RDWR);    if (fd < 0)        return;    write(fd, process_name, strlen(process_name) + 1);    close(fd);#endif}
后来通过
runtime.start("com.android.internal.os.ZygoteInit",                startSystemServer ? "start-system-server" : "");
来启动zygote,具体start做了什么可以参考 Dalvik虚拟机的启动过程
runtime.start最终会调用到ZygoteInit.java中的main函数:

 public static void main(String argv[]) { try { // Start profiling the zygote initialization. SamplingProfilerIntegration.start(); registerZygoteSocket(); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); if(!SystemProperties.getBoolean("config.enable_quickboot", false)) { preload(); } EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); // Finish profiling the zygote initialization. SamplingProfilerIntegration.writeZygoteSnapshot(); // Do an initial gc to clean up after startup gc(); // Disable tracing so that forked processes do not inherit stale tracing tags from // Zygote. Trace.setTracingEnabled(false); // If requested, start system server directly from Zygote if (argv.length != 2) { throw new RuntimeException(argv[0] + USAGE_STRING); } if (argv[1].equals("start-system-server")) { startSystemServer(); } else if (!argv[1].equals("")) { throw new RuntimeException(argv[0] + USAGE_STRING); } Log.i(TAG, "Accepting command socket connections"); runSelectLoop(); closeServerSocket(); } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; } }
最主要的就是做了三件事情:

1)创建zygote socket,用来和ActivityManagerService通讯

2)startSystemServer启动system_server

3)调用runSelectLoopMode函数进入一个无限循环在前面创建的socket接口上等待ActivityManagerService请求创建新的应用程序进程。


接下来对main函数做简单的分析:

1、数据统计

// Start profiling the zygote initialization.SamplingProfilerIntegration.start();......// Finish profiling the zygote initialization.SamplingProfilerIntegration.writeZygoteSnapshot();

2、registerZygoteSocket

private static void registerZygoteSocket() {    if (sServerSocket == null) {        int fileDesc;        try {            String env = System.getenv(ANDROID_SOCKET_ENV);            fileDesc = Integer.parseInt(env);        } catch (RuntimeException ex) {            throw new RuntimeException(                    ANDROID_SOCKET_ENV + " unset or invalid", ex);        }        try {            sServerSocket = new LocalServerSocket(                    createFileDescriptor(fileDesc));        } catch (IOException ex) {            throw new RuntimeException(                    "Error binding to local socket '" + fileDesc + "'", ex);        }    }}
这个socket接口是通过文件描述符来创建的,这个文件描符代表的就是我们前面说的/dev/socket/zygote文件了。这个文件描述符是通过环境变量ANDROID_SOCKET_ENV得到的,它定义为:
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);}
这里就将init.rc中的zygote传了进来,而ANDROID_SOCKET_ENV_PREFIX在system/core/include/cutils/sockets.h定义为:

#define ANDROID_SOCKET_ENV_PREFIX"ANDROID_SOCKET_"#define ANDROID_SOCKET_DIR"/dev/socket"
因此,这里就把上面得到的文件描述符写入到以"ANDROID_SOCKET_zygote"为key值的环境变量中。又因为上面的ZygoteInit.registerZygoteSocket函数与这里创建socket文件的create_socket函数是运行在同一个进程中,因此,上面的ZygoteInit.registerZygoteSocket函数可以直接使用这个文件描述符来创建一个Java层的LocalServerSocket对象。如果其它进程也需要打开这个/dev/socket/zygote文件来和Zygote进程进行通信,那就必须要通过文件名来连接这个LocalServerSocket了。

3、preload

if(!SystemProperties.getBoolean("config.enable_quickboot", false)) {    preload();}
对于preload这里不做过多的介绍,可以参考 android 系统资源的加载和获取

4、startSystemServer

private static boolean startSystemServer()        throws MethodAndArgsCaller, RuntimeException {    long capabilities = posixCapabilitiesAsBits(        OsConstants.CAP_KILL,        OsConstants.CAP_NET_ADMIN,        OsConstants.CAP_NET_BIND_SERVICE,        OsConstants.CAP_NET_BROADCAST,        OsConstants.CAP_NET_RAW,        OsConstants.CAP_SYS_MODULE,        OsConstants.CAP_SYS_NICE,        OsConstants.CAP_SYS_RESOURCE,        OsConstants.CAP_SYS_TIME,        OsConstants.CAP_SYS_TTY_CONFIG    );    /* 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,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);        /* 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);    }    /* For child process */    if (pid == 0) {        handleSystemServerProcess(parsedArgs);    }    return true;}
对于system_server进程,可以参考 android systemserver启动详解
重要的就是pid = Zygote.forkSystemServer(),创建一个新的进程来启动SystemServer组件,返回值pid等0的地方就是新的进程要执行的路径,即新创建的进程会执行handleSystemServerProcess函数。

    private static void handleSystemServerProcess(            ZygoteConnection.Arguments parsedArgs)            throws ZygoteInit.MethodAndArgsCaller {        closeServerSocket();        // set umask to 0077 so new files and directories will default to owner-only permissions.        Libcore.os.umask(S_IRWXG | S_IRWXO);        if (parsedArgs.niceName != null) {            Process.setArgV0(parsedArgs.niceName);        }        if (parsedArgs.invokeWith != null) {            WrapperInit.execApplication(parsedArgs.invokeWith,                    parsedArgs.niceName, parsedArgs.targetSdkVersion,                    null, parsedArgs.remainingArgs);        } else {            /*             * Pass the remaining arguments to SystemServer.             */            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);        }        /* should never reach here */    }

由于由Zygote进程创建的子进程会继承Zygote进程在前面Step 2中创建的Socket文件描述符,而这里的子进程又不会用到它,因此,这里就调用closeServerSocket函数来关闭它。这个函数接着调用RuntimeInit.zygoteInit函数来进一步执行启动SystemServer组件的操作。详细的可以参考android systemserver启动详解

5、runSelectLoop

    /**     * Runs the zygote process's select loop. Accepts new connections as     * they happen, and reads commands from connections one spawn-request's     * worth at a time.     *     * @throws MethodAndArgsCaller in a child process when a main() should     * be executed.     */    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;            /*             * Call gc() before we block in select().             * It's work that has to be done anyway, and it's better             * to avoid making every child do it.  It will also             * madvise() any free memory as a side-effect.             *             * Don't call it every time, because walking the entire             * heap is a lot of overhead to free a few hundred bytes.             */            if (loopCount <= 0) {//Zygote每循环GC_LOOP_COUNT(这里的值是10)次就会进行一次内存回收</span></span>                gc();                loopCount = GC_LOOP_COUNT;            } else {                loopCount--;            }            try {                fdArray = fds.toArray(fdArray);                index = selectReadable(fdArray);//内部由select()实现,在没有客户端事件时会堵塞            } catch (IOException ex) {                throw new RuntimeException("Error in select()", ex);            }            if (index < 0) {                throw new RuntimeException("Error in select()");            } else if (index == 0) {//index==0表示selcet接收到的是Zygote的socket的事件                ZygoteConnection newPeer = acceptCommandPeer();                peers.add(newPeer);                fds.add(newPeer.getFileDesciptor());            } else {//调用ZygoteConnection对象的runOnce方法,ZygoteConnection是在index==0时被添加到peers的                boolean done;                done = peers.get(index).runOnce();                if (done) {                    peers.remove(index);                    fds.remove(index);                }            }        }    }
这就是在等待ActivityManagerService来连接这个Socket,然后调用ZygoteConnection.runOnce函数来创建新的应用程序


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

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

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

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





更多相关文章

  1. [Android] [ Android启动流程 ] [ 下 ] [ Zygote、SystemServer
  2. 【Android 性能优化】应用启动优化 ( 安卓应用启动分析 | Launch
  3. Android中String资源文件的String.format方法(java)
  4. 在Ubuntu中和Android中添加开机自启动的守护进程
  5. android进程间共享简单数据
  6. Android中扫描多媒体文件操作详解
  7. Android名词解释之什么是APK文件
  8. Android 逆向apk的配置文件
  9. Android进程系列第六篇---LowmemoryKiller机制分析(上)

随机推荐

  1. Android screenOrientation 屏幕方向的设
  2. Android(安卓)4.0.3 联系人(通讯录)应用
  3. Android实用小技巧
  4. Android View MarqueeView 跑马灯效果
  5. 关于Android使用新浪API的一些说明
  6. Android高德地图自定义放大缩小控件
  7. 在android中使用OrmLite数据库框架
  8. Android map
  9. Mac 配置Android环境变量( 有图)
  10. Android 编辑框(EditText)属性