当前位置:   article > 正文

Android学习---zygote(上)_android zygote预加载

android zygote预加载

Zygote意思是受精卵,它在Java世界中起到了很重要的作用,Android是基于Linux内核的,SDK是基于Java世界的,native语言是基于C和C++,起初一定是先存在native世界,那么Java世界是如何创建的?这就与zygote和system_server有关。

 

Zygote是一个native应用程序,原名是app_process,是在Android.mk文件中指定的,但是在运行的时候通过Linux下的pctrl系统调用将自己的名字改成了zygote,在0frameworks/base/cmds/app_process目录下,app_main函数中:

  1. if (0 == strcmp("--zygote", arg)) {
  2. bool startSystemServer = (i < argc) ?
  3. strcmp(argv[i], "--start-system-server") == 0 : false;
  4. setArgv0(argv0, "zygote");
  5. set_process_name("zygote");//设置本进程名字是zygote
  6. runtime.start("com.android.internal.os.ZygoteInit",
  7. startSystemServer);
  8. }

上面的函数中,调用了AppRuntime中的start方法,AppRuntime继承AndroidRuntime,调用的start也是AndroidRuntime里的方法。

AndroidRuntime.cpp

  1. //创建虚拟机
  2. if (startVm(&mJavaVM, &env) != 0)
  3. goto bail;
  4. ②注册JNI函数
  5. if (startReg(env) < 0) {
  6. LOGE("Unable to register all android natives\n");
  7. goto bail;
  8. }
  9. ③ 通过JNI调用ZygoteInit下的main函数 进入Java世界
  10. env->CallStaticVoidMethod(startClass, startMeth, strArray);

1 创建虚拟机

  1. int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)//大部分是设置虚拟机参数
  2. {
  3. //设置JNI check选项的 检查资源是否被正确释放 字符集的要求等 缺点:耗时
  4. property_get("dalvik.vm.checkjni", propBuf, "");
  5. //设置虚拟机的heapsize 默认是16MB 太小会导致操作大图片的时候无法分配内存
  6. strcpy(heapsizeOptsBuf, "-Xmx");
  7. property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");
  8. }

2 注册JNI函数

  1. /*static*/ int AndroidRuntime::startReg(JNIEnv* env)
  2. { //设置Thread类的线程创建函数是javaCreateThreadEtc
  3. androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
  4. env->PushLocalFrame(200);
  5. // 注册JNI函数 gRegJNI是一个全局数组
  6. /*register_jni_procs函数里调用数组的Proc方法,Proc方法是为了注册JNI函数,数组是gRegJNI包含了所需要注册的JNI函数*/
  7. if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
  8. env->PopLocalFrame(NULL);
  9. return -1;
  10. }
  11. env->PopLocalFrame(NULL);
  12. //createJavaThread("fubar", quickTest, (void*) "hello");
  13. return 0;
  14. }

 

接下来就进入了Java世界,Java世界的入口---frameworks/base/core/java/com/android/internal/os  ZygoteInit.java

  1. public static void main(String argv[]) {
  2. try{
  3. registerZygoteSocket(); //① 注册zygote用到的socket
  4. preloadClasses(); //②预加载类和资源
  5. preloadResources();
  6. if (argv[1].equals("true")) {
  7. startSystemServer(); //③启动SystemServer
  8. }
  9. if (ZYGOTE_FORK_MODE) {
  10. runForkMode(); //④
  11. } else {
  12. runSelectLoopMode();
  13. }
  14. }catch(MethodAndArgsCaller caller){
  15. caller.run(); //⑤
  16. }
  17. }
  • 建立IPC通信服务端registerZygoteSocket

IPC---InterProcess Communication 进程间通信,指的是在不同进程之间传播交换信息,不同进程之间用户空间独立,共享内存区是公用的,常见的IPC通信有:管道、消息队列、 信号量、共享内存、socket、Streams等

  1. private static void registerZygoteSocket() {
  2. if (sServerSocket == null) {
  3. int fileDesc;
  4. try { //从环境变量获取socket的fd(启动时传入)
  5. String env = System.getenv(ANDROID_SOCKET_ENV);
  6. fileDesc = Integer.parseInt(env);
  7. } ......
  8. try { //创建服务端socket
  9. sServerSocket = new LocalServerSocket(
  10. createFileDescriptor(fileDesc));
  11. }......
  12. }
  13. }
  1. 预加载类和资源
  1. private static void preloadClasses() {
  2. //预加载的类信息存储在PRELOADED_CLASSES里
  3. InputStream is = ZygoteInit.class.getClassLoader().getResourceAsStream(
  4. if (is == null) {
  5. Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
  6. } else { //准备工作 }
  7. //读取文件的每一行
  8. while ((line = br.readLine()) != null) {
  9. // Skip comments and blank lines.
  10. line = line.trim();
  11. if (line.startsWith("#") || line.equals("")) {
  12. continue;
  13. }
  14. //通过Java反射来加载类 line中存储的是预加载的类名
  15. Class.forName(line);
  16. }

在/AOSP/frameworks/base/preloaded-classes下是要加载的所有类,数量很多高达1200+行

 Preload_class文件由framework/base/tool/preload工具生成,他要判断每个类加载的时间是否大于1250us,超过这个时间写入到preload_classes文件中,由zygote预加载。由于要加载的类十分多,这也导致了android启动时间很长。

③启动system_server

StartSystemServer会创建Java世界中系统Service所驻留的进程,该进程是framework核心,他如果死了,zygote就会自杀。zygote压力大,分裂了一个子进程为他做一些事情。

  1. private static boolean startSystemServer()
  2. throws MethodAndArgsCaller, RuntimeException {
  3. //设置参数
  4. String args[] = {
  5. "--setuid=1000",
  6. "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
  7. "--capabilities=130104352,130104352",
  8. "--runtime-init",
  9. "--nice-name=system_server",//进程名
  10. "com.android.server.SystemServer",
  11. };
  12. ZygoteConnection.Arguments parsedArgs = null;
  13. int pid;
  14. try {
  15. parsedArgs = new ZygoteConnection.Arguments(args);
  16. int debugFlags = parsedArgs.debugFlags;
  17. if ("1".equals(SystemProperties.get("ro.debuggable")))
  18. debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
  19. /* zygote分裂了一个子进程 */
  20. pid = Zygote.forkSystemServer(
  21. parsedArgs.uid, parsedArgs.gid,
  22. parsedArgs.gids, debugFlags, null,
  23. parsedArgs.permittedCapabilities,
  24. parsedArgs.effectiveCapabilities);
  25. } catch (IllegalArgumentException ex) {
  26. throw new RuntimeException(ex);
  27. }
  28. if (pid == 0) {//pid=0表明处于子进程中,开始执行system_server的工作
  29. handleSystemServerProcess(parsedArgs);
  30. }
  31. return true;
  32. }

④ runSelectLoopMode

当函数分裂了system_server进程后进入到了下一个关键函数runSelectLoopMode,这里将会使用到前面第一步创建的socket

  1. private static void runSelectLoopMode() throws MethodAndArgsCaller {
  2. ArrayList<FileDescriptor> fds = new ArrayList();
  3. ArrayList<ZygoteConnection> peers = new ArrayList();
  4. FileDescriptor[] fdArray = new FileDescriptor[4];
  5. //第一步创建的服务端socket
  6. fds.add(sServerSocket.getFileDescriptor());
  7. peers.add(null);
  8. while (true) {
  9. int index=0;
  10. try {
  11. //selectReadable内部调用select,使用多路复用IO模型,有客户端连接//或者有数据时//selectReadable就会返回
  12. fdArray = fds.toArray(fdArray);
  13. index = selectReadable(fdArray);
  14. } catch (IOException ex) {
  15. throw new RuntimeException("Error in select()", ex);
  16. }
  17. //客户端代表的是ZygoteConnection,
  18. else if (index == 0) {
  19. ZygoteConnection newPeer = acceptCommandPeer();
  20. peers.add(newPeer);
  21. fds.add(newPeer.getFileDesciptor());
  22. } else {
  23. boolean done;
  24. // peers.get(index)返回的是ZygoteConnection,然后调用runOnce函数完成
  25. done = peers.get(index).runOnce();
  26. }

总结:主要是处理客户连接和客户请求,客户在zygote中用ZygoteConnection 表示,客户的请求由runOnce函数完成。

至此Zygote便睡去了,默默守护在我们周围。当收到子孙后代的请求后,会被随时叫醒。

下一章节,将来学习Zygote的子进程SystemServer

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/227938
推荐阅读
相关标签
  

闽ICP备14008679号