安卓Zygote详解

Posted Leonban

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓Zygote详解相关的知识,希望对你有一定的参考价值。

一、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进行数据传递的。


以上是关于安卓Zygote详解的主要内容,如果未能解决你的问题,请参考以下文章

Android-Activity启动流程

Android4.4的zygote进程(上)

Android学习之zygote启动流程

Activity启动过程详解

Zygote浅谈

Android 进阶——系统启动之Android进程造物者Zygote 进程启动详解