安卓Zygote详解

来源:互联网 发布:酷客网络代刷网 编辑:程序博客网 时间:2024/06/07 09:23
一、Zygote, 意为“受精卵”,Android系统中几乎所有的应用进程都是由Zygote进程孵化出来的,Java环境也是由Zygote创建起来的,它建立了我们app运行所需要的环境,是app的祖先,因此,分析它的启动以及内部逻辑显得非常有必要。
    *Android系统是基于Linux内核的,而在Linux系统中,所有的进程都是init进程的子孙进程,也就是说,所有的进程都是直接或者间接地由init进程fork出来的。Zygote进程也不例外,它是在系统启动的过程,由init进程创建的。在系统启动脚本system/core/rootdir/init.rc文件中,我们可以看到启动Zygote进程的脚本命令:
<span style="font-size:14px;">service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server     class main     socket zygote stream 660 root system  # zygote需要一个套接字     onrestart write /sys/android_power/request_state wake  # zygote重启的话,需要执行这个操作     onrestart write /sys/power/state on     onrestart restart media     onrestart restart netd</span>
    *上述脚本表示要启动一个进程,名称为zygote, 可执行文件为/system/bin/app_process,  --Xzygote /system/bin --zygote --start-system-server这些是传给zygote的参数,其余部分的作用见注释。

二、app_process对应的源码在frameworks/base/cmds/app_process目录下,其入口函数main在文件app_main.cpp中,接下来我们就从这个main函数入手来分析zygote的内部逻辑。
<span style="font-size:14px;">int main(int argc, 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* 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);    }    runtime.mParentDir = parentDir;    if (zygote) {        runtime.start("com.android.internal.os.ZygoteInit",                startSystemServer ? "start-system-server" : "");    } else if (className) {        // 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;    }}</span>
三、main函数主要就是创建了runtime实例,并且解析参数,然后调用runtime的start函数,接着我们分析AppRuntime的start函数
    这个函数定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中:
<span style="font-size:14px;">// 首先明确下传进来的参数  className == "com.android.internal.os.ZygoteInit"  options == "start-system-server"void AndroidRuntime::start(const char* className, const char* options){    ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",            className != NULL ? className : "(unknown)");    /*     * 'startSystemServer == true' means runtime is obsolete and not run from     * init.rc anymore, so we print out the boot start event here.     */    if (strcmp(options, "start-system-server") == 0) {        /* track our progress through the boot sequence */        const int LOG_BOOT_PROGRESS_START = 3000;        LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,                       ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));    }    const char* rootDir = getenv("ANDROID_ROOT");    if (rootDir == NULL) {        rootDir = "/system";        if (!hasDir("/system")) {            LOG_FATAL("No root directory specified, and /android does not exist.");            return;        }        setenv("ANDROID_ROOT", rootDir, 1);  //配置ANDROID_ROOT环境变量    }    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");    //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);    /* start the virtual machine */    JniInvocation jni_invocation;    jni_invocation.Init(NULL);    JNIEnv* env;    if (startVm(&mJavaVM, &env) != 0) { // 创建虚拟机        return;    }    onVmCreated(env);    /*     * Register android functions.     */    if (startReg(env) < 0) {        ALOGE("Unable to register all android natives\n");        return;    }    /*     * We want to call main() with a String array with arguments in it.     * At present we have two arguments, the class name and an option string.     * Create an array to hold them.     */    jclass stringClass;    jobjectArray strArray;    jstring classNameStr;    jstring optionsStr;    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);    optionsStr = env->NewStringUTF(options);    env->SetObjectArrayElement(strArray, 1, optionsStr);    /*     * Start VM.  This thread becomes the main thread of the VM, and will     * not return until the VM exits.     */    char* slashClassName = toSlashClassName(className);    jclass startClass = env->FindClass(slashClassName);    if (startClass == NULL) {        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);        /* keep going */    } else {        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 {            /* 调用com.android.internal.os.ZygoteInit的main函数,strArray是参数,数组里面有两个元素,            className == "com.android.internal.os.ZygoteInit"  options == "start-system-server" */            env->CallStaticVoidMethod(startClass, startMeth, strArray);#if 0            if (env->ExceptionCheck())                threadExitUncaughtException(env);#endif        }    }    free(slashClassName);    ALOGD("Shutting down VM\n");    if (mJavaVM->DetachCurrentThread() != JNI_OK)        ALOGW("Warning: unable to detach main thread\n");    if (mJavaVM->DestroyJavaVM() != 0)        ALOGW("Warning: VM did not shut down cleanly\n");}</span>
四、start函数主要做了以下几件事情:
    调用startVm函数创建虚拟机;
    调用startReg函数注册Android Natvie函数;
    让虚拟机去执行com.android.internal.os.ZygoteInit的main函数。
    接下来分析下com.android.internal.os.ZygoteInit的main函数,frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
<span style="font-size:14px;">public static void main(String argv[]) {        try {            // Start profiling the zygote initialization.            SamplingProfilerIntegration.start();            registerZygoteSocket();  // 1、创建一个套接字,用于监听ams发过来的fork请求            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,                SystemClock.uptimeMillis());            preload(); // 2、加载classes 和resources, 后面会详细分析            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();            // 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(); //3、 创建system server进程,ams wms pms等常见service都在该进程里面            } else if (!argv[1].equals("")) {                throw new RuntimeException(argv[0] + USAGE_STRING);            }            Log.i(TAG, "Accepting command socket connections");            if (ZYGOTE_FORK_MODE) {                runForkMode();            } else {                runSelectLoopMode(); // 4、进入循环监听模式,监听外来请求            }            closeServerSocket();        } catch (MethodAndArgsCaller caller) {            caller.run();        } catch (RuntimeException ex) {            Log.e(TAG, "Zygote died with exception", ex);            closeServerSocket();            throw ex;        }    }</span>
五、com.android.internal.os.ZygoteInit的main函数主要做了四件事情:
    调用 registerZygoteSocket()创建一个套接字,用于监听ams发过来的fork请求;
    调用preload()预加载classes 和resources;
    调用startSystemServer()创建system server进程,ams wms pms等常见service都在该进程里面;
    调用runSelectLoopMode()进入循环监听模式,监听外来请求。

1、 registerZygoteSocket
    fork()创建子进程,父进程返回true。子进程执行RuntimeInit.zygoteInit。
    @frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
<span style="font-size:14px;">public class ZygoteInit {  ...  private static LocalServerSocket sServerSocket;  private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";    private static void registerZygoteSocket() {    if(sServerSocket == NULL) {      int fileDesc;      String env = System.getenv(ANDROID_SOCKET_ENV);// 获取环境变量      fileDesc = Integer.parseInt(env);      sServerSocket = new LocalServerSocket(createFileDescriptor(fileDesc));    }  }}</span>
    *这里通过System.getenv()获取环境变量ANDROID_SOCKET_ENV的值,通过这个文件描述符表示/dev/socket/zygote。那么这个环境变量又是谁设置的呢?执行系统启动脚本init.rc的init.c文件里面有个service_start()函数就是用来分析zygote并创建和设置相应socket的。
<span style="font-size:14px;">void service_start(struct service *svc, const char* dynamic_args) {  ...  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);      publish_socket(si->name, s);    }  }  ...}#define ANDROID_SOCKET_ENV_PREFIX  "ANDROID_SOCKET_"#define ANDROID_SOCKET_DIR "/dev/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);// ANDROID_SOCKET_zygote = val  fcntl(fd, F_SETFD, 0);}</span>
    *这里每一个service命令都会使init进程调用fork函数创建一个新的进程来分析里面的socket选项,然后调用create_socket()函数在/dev/socket目录下创建一个设备文件,然后获得一个文件描述符并通过publish_socket()写入到环境变量中去。这样就把zygote这个socket的文件描述符写到ANDROID_SOCKET_zygote里面去了,这里创建socket文件描述符的create_socket()函数,最后通过调用execve(svc->args[0], (char**)arg_ptrs, (char**)ENV)去执行zygote的可执行程序,并将环境变量ENV参数传递过去了。所以ZygoteInit.registerZygoteSocket()函数就可以直接从环境变量中取出这个文件描述符来使用。如果其他进程需要打开这个/dev/socket/zygote 文件来和Zygote进程通信就需要通过文件名字连接LocalServerSocket。

2、startSystemServer
    @frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
<span style="font-size:14px;">private static boolean startSystemServer() {  String args[] = {    "--setuid=1000",     "--setgid=1000",     "--setgroups=1001,1002,1003,1004,1005,1006...",    "--capabilities=13010432,130104352",    "--runtime-init",    "--nice-name=system_server",    "com.android.server.SystemServer",  };  ZygoteConnection.Arguments parsedArgs = null;  parsedArgs = new ZygoteConnection.Arguments(args);  ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);  ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);  int pid = Zygote.forkSystemServer(    parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,    parsedArgs.debugFlags, null, parsedArgs.permittedCapabilities,    parsedArgs.effectiveCapabilities));  if (pid == 0) {// 子进程    handleSystemServerProcess(parsedArgs);  }  return true;// 父进程直接返回true}</span>
    *这里Zygote进程通过调用Zygote.forkSystemServer()函数创建一个新的进程来启动SystemServer组件。
<span style="font-size:14px;">public class ZygoteInit {  ....  private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {    closeServerSocket();// 子进程不需要zygote套接字,直接关闭      FileUtils.setUMask(FileUtils.S_IRWXG | FileUtils.S_IRWXO);    ...    RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);  }}public class RuntimeInit {  ...    public static final void zygoteInit(int targetSdkVersion, String[] argv) {    redirectLogStreams();    commonInit();    zygoteInitNative();// 是一个native函数,主要完成Binder通信机制的初始化    applicationInit(targetSdkVersion, argv);  }  public static final native void zygoteInitNative();    private static void applicationInit(int targetSdkVersion, String[] argv) {    VMRuntime.getRuntime().setTargetHeapUtilizatoin(0.75f);    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);    final Arguments args;    args = new Arguments(argv);    invokeStaticMain(args.startClass, args.startArgs);  }  // 这个 className = "com.android.server.SystemServer"  private static void invokeStaticMain(String className, String[] argv) {    Class<?> cl;    cl = Class.forName(className);    Method m;    m = cl.getMethod("main", new Class[] {String[].class});    ...    throw new ZygoteInit.MethodAndArgsCaller(m, argv);  }}</span>
    *这个RuntimeInit.ZygoteInit()函数主要执行两个操作:一是调用zygoteInitNative来执行一个Binder进程间通信机制的初始化工作;二是调用com.android.server.SystemServer类的main函数。
    *zygoteInitNative: 
    @frameworks/base/core/jni/AndroidRuntime.cpp
<span style="font-size:14px;">static JNINativeMethod gMethods[] = {   ....  { "zygoteInitNative", "()V", (void*) com_android_internal_os_RuntimeInit_zygoteInit },  .... };static void com_android_internal_os_RuntimeInit_zygoteInit(JNIEnv* env, jobject clazz){    gCurRuntime->onZygoteInit();    // 就是启动Binder通信}virtual void onZygoteInit(){  sp<ProcessState> proc = ProcessState::self();// 每个进程一份ProcessState对象,打开Binder驱动  if(proc->supportsProcess()){    proc->startThreadPool();// 启动一个线程用于Binder通信  }}</span>
    *SystemServer.main :
    @frameworks/base/services/java/com/android/server/SystemServer.java
<span style="font-size:14px;">public class SystemServer {  native public static void init1(Strig[] args);    public static void main(String[] args) {    ....    VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);    System.loadLibrary("android_servers");    init1(args);  }    public static final void init2() {    Thread thr = new ServerThread();    thr.setName("android.server.ServerThread");    thr.start();  }}</span>
    *@frameworks/base/services/jni/com_android_server_SystemServer.cpp
<span style="font-size:14px;">static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz){  system_init();}status_t system_init(){  sp<ProcessState> proc(ProcessState::self());  sp<IServiceManager> sm = defaultServiceManager();  ...  AndroidRuntime* runtime = AndroidRuntime::getRuntime();  JNIEnv* env = rungime->getJNIEnv();  jclass clazz = env->FindClass("com/android/server/SystemServer");  jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V");  env->CallStaticVoidMethod(clazz, methodId);    ProcessState::self()->startThreadPool();  IPCThreadState::self()->joinThreadPool();  return NO_ERROR;}</span>
    *这个SystemServer的main()函数首先会调用JNI方法init1,init1()会调用SystemServer的init2,在init2里面创建一个ServerThread线程执行一些系统关键服务的启动操作。
<span style="font-size:14px;">class ServerThread extends Thread {  ...  public void run() {    Looper.prepare();    // Critical services ...    ServiceManager.addService(Context.POWER_SERVICE, new PoperManagerService());    ActivityManagerService.main();    PackageManagerService.main(context);    ...  }}</span>
    *到现在为止,zygote已经fork()子进程完成了SystemServer组件的初始化启动操作,回到zygote.main()里面调用runSelectLoopMode()进入一个循环再前面创建的socket接口上等待ActivityManagerService请求创建新的应用程序。


3、runSelectLoopMode

<span style="font-size:14px;">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;// 10    while(true) {      fdArray = fds.toArray(fdArray);      index = selectReadble(fdArray);// 类似Linux下的select轮询,native 函数      if(index < 0) {        ...      } else if(index == 0) {// 表示有客户端连接上        ZygoteConnection newPeer = acceptCommandPeer();        peers.add(newPeer);        fds.add(newPeer.getFileDescriptor());      } else {// 客户端发送了请求过来,交给ZygoteConnection的runOnce()函数完成        boolean done = peers.get(index).runOnce();        if(done) {          peers.remove(index);          fds.remove(index);        }      }    }  }    private static ZygoteConnection acceptCommandPeer() {    ...    return new ZygoteConnection(sServerSocket.accept());  }}</span>
    *这里while(true)循环里面调用selectReadble(),这是一个native函数,类似select使用多路复用I/O模型。当返回0的时候表示有客户端连接上,ZygoteConnection表示Zygote的一个客户端,每当客户端连接上的时候acceptCommandPeer()返回一个ZygoteConnection对象,ZygoteConnection里面保存着accpet()返回的LocalSocket对象。然后将相应的文件描述符添加到fds里面,下次再对其调用selelct轮询。当返回值大于0的时候表示有客户端发过来的数据请求,交给ZygoteConnection对象的runOnce()函数处理。
    *selectReadable()函数对应native函数为:com_android_internal_os_ZygoteInit_SelectReadable()
<span style="font-size:14px;">static jint com_android_internal_os_ZygoteInit_selectReadable (    JNIEnv *env, jobject clazz, jobjectArray fds){  if (fds == NULL) {    jniThrowNullPointerException(env, "fds == null");    return -1;  }  jsize length = env->GetArrayLength(fds);  fd_set fdset;  if (env->ExceptionOccurred() != NULL) {    return -1;  }  FD_ZERO(&fdset);  int nfds = 0;  for (jsize i = 0; i < length; i++) {    jobject fdObj = env->GetObjectArrayElement(fds, i);    if  (env->ExceptionOccurred() != NULL) {      return -1;    }    if (fdObj == NULL) {      continue;    }    int fd = jniGetFDFromFileDescriptor(env, fdObj);    if  (env->ExceptionOccurred() != NULL) {      return -1;    }    FD_SET(fd, &fdset);    if (fd >= nfds) {      nfds = fd + 1;    }  } int err;  do {    err = select (nfds, &fdset, NULL, NULL, NULL);  } while (err < 0 && errno == EINTR);  if (err < 0) {    jniThrowIOException(env, errno);    return -1;  }  for (jsize i = 0; i < length; i++) {    jobject fdObj = env->GetObjectArrayElement(fds, i);    if  (env->ExceptionOccurred() != NULL) {      return -1;    }    if (fdObj == NULL) {      continue;    }    int fd = jniGetFDFromFileDescriptor(env, fdObj);    if  (env->ExceptionOccurred() != NULL) {      return -1;    }    if (FD_ISSET(fd, &fdset)) {      return (jint)i;    }  }  return -1;}</span>
总结:
    *在android中SystemService的启动是在Zygote进程创建好后进行的,并且由Zygote进程建立好DVM运行环境,加载ZygoteInit的main函数,最终调用Zygote的本地方法forkSystemServer,并执行linux的fork方法创建SystemServer进程。
    *应用程序的进程也是由Zygote创建的,在ActivityManagerService中的startProcessLocked中调用了Process.start()方法。并通过连接调用Zygote的native方法forkAndSpecialize,执行fork任务。

    *应用进程和服务进程位于不同的进程中,他们之间是通过IPC进行数据传递的。


1 0
原创粉丝点击