【Android源码 栏目提醒】:网学会员鉴于大家对Android源码 十分关注,论文会员在此为大家搜集整理了“Android系统进程Zygote启动过程的源代码分析 - 企业软件开发”一文,供大家参考学习
Android系统进程Zygote启动过程的源代码分析 在
Android系统中所有的应用程序进程以及系统服务进程SystemServer都是由Zygote进程孕育fork出来的这也许就是为什么要把它称为Zygote受精卵的原因吧。
由于Zygote进程在
Android系统中有着如此重要的地位本文将详细分析它的启动过程。
在前面一篇文章
Android应用程序进程启动过程的源代码分析中我们看到了当ActivityManagerService启动一个应用程序的时候就会通过Socket与Zygote进程进行通信请求它fork一个子进程出来作为这个即将要启动的应用程序的进程在前面两篇文章
Android应用程序安装过程源代码分析和
Android系统默认Home应用程序Launcher的启动过程源代码分析中我们又看到了系统中的两个重要服务PackageManagerService和ActivityManagerService都是由SystemServer进程来负责启动的而SystemServer进程本身是Zygote进程在启动的过程中fork出来的。
我们知道
Android系统是基于Linux内核的而在Linux系统中所有的进程都是init进程的子孙进程也就是说所有的进程都是直接或者间接地由init进程fork出来的。
Zygote进程也不例外它是在系统启动的过程由init进程创建的。
在系统启动脚本system/core/rootdir/init.rc文件中我们可以看到启动Zygote进程的脚本命令 plain view plaincopy 1. service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server 2. socket zygote stream 666 3. onrestart write /sys/
android_power/request_state wake 4. onrestart write /sys/power/state on 5. onrestart restart media 6. onrestart restart netd 前面的关键字service告诉init进程创建一个名为quotzygotequot的进程这个zygote进程要执行的程序是/system/bin/app_process后面是要传给app_process的参数。
接下来的socket关键字表示这个zygote进程需要一个名称为quotzygotequot的socket资源这样系统启动后我们就可以在/dev/socket目录下看到有一个名为zygote的文件。
这里定义的socket的类型为unix domain socket它是用来作本地进程间通信用的具体可以参考前面一篇文章
Android学习启动篇提到的一书《Linux内核源代码情景分析》的第七章--基于socket的进程间通信。
前面我们说到的ActivityManagerService就是通这个socket来和zygote进程通信请求fork一个应用程序进程的了。
最后的一系列onrestart关键字表示这个zygote进程重启时需要执行的命令。
关于init.rc文件的更多信息请参考system/core/init/readme.txt文件。
了解了这个信息之后我们就知道Zygote进程要执行的程序便是system/bin/app_process了它的源代码位于frameworks/base/cmds/app_process/app_main.cpp文件中入口函数是main。
在继续分析Zygote进程启动的过程之前我们先来看看它的启动序列图 下面我们就详细分析每一个步骤。
Step 1. app_process.main 这个函数定义在frameworks/base/cmds/app_process/app_main.cpp文件中 cpp view plaincopy 1. int mainint argc const char const argv 2. 3. // These are global variables in ProcessState.cpp 4. mArgC argc 5. mArgV argv 6. 7. mArgLen 0 8. for int i0 iltargc i 9. mArgLen strlenargvi 1 10. 11. mArgLen-- 12. 13. AppRuntime runtime 14. const char arg 15. argv0 argv0 16. 17. // Process command line arguments 18. // ignore argv0 19. argc-- 20. argv 21. 22. // Everything up to -- or first non - arg goes to the vm 23. 24. int i runtime.addVmArgumentsargc argv 25. 26. // Next arg is parent directory 27. if i lt argc 28. runtime.mParentDir argvi 29. 30. 31. // Next arg is startup classname or quot--zygotequot 32. if i lt argc 33. arg argvi 34. if 0 strcmpquot--zygotequot arg 35. bool startSystemServer i lt argc 36. strcmpargvi quot--start-system-serverquot 0 : false 37. setArgv0argv0 quotzygotequot 38. set_process_namequotzygotequot 39. runtime.startquotcom.
android.internal.os.ZygoteInitquot 40. startSystemServer 41. else 42. set_process_nameargv0 43. 44. runtime.mClassName arg 45. 46. // Remainder of args get passed to startup class main 47. runtime.mArgC argc-i 48. runtime.mArgV argvi 49. 50. LOGVquotApp process is starting with pidd classs.nquot 51. getpid runtime.getClassName 52. runtime.start 53. 54. else 55. LOG_ALWAYS_FATALquotapp_process: no class name or --zygote supplied.quot 56. fprintfstderr quotError: no class name or --zygote supplied.nquot 57. app_usage 58. return 10 59. 60. 61. 这个函数的主要作用就是创建一个AppRuntime变量然后调用它的start成员函数。
AppRuntime这个类我们在
Android应用程序进程启动过程的源代码分析一文中已经有过介绍了它同样是在frameworks/base/cmds/app_process/app_main.cpp文件中定义 cpp view plaincopy 1. class AppRuntime : public AndroidRuntime 2. 3. ...... 4. 它约继承于AndroidRuntime类 AndroidRuntime类定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中 cpp view plaincopy 1. ...... 2. 3. static AndroidRuntime gCurRuntime NULL 4. 5. ...... 6. 7. AndroidRuntime::AndroidRuntime 8. 9. ...... 10. 11. assertgCurRuntime NULL // one per process 12. gCurRuntime this 13. 当AppRuntime对象创建时会调用其父类AndroidRuntime的构造函数而在AndroidRuntime类的构造函数里面会将this指针保存在静态全局变量gCurRuntime中这样当其它地方需要使用这个AppRuntime对象时就可以通过同一个文件中的这个函数来获取这个对象的指针 cpp view plaincopy 1. AndroidRuntime AndroidRuntime::getRuntime 2. 3. return gCurRuntime 4. 回到上面的main函数中由于我们在init.rc文件中设置了app_process启动参数--zygote和--start-system-server因此在main函数里面最终会执行下面语句 cpp view plaincopy 1. runtime.startquotcom.
android.internal.os.ZygoteInitquot 2. rtSystemServer 这里的参数startSystemServer为true表示要启动SystemServer组件。
由于AppRuntime没有实现自己的start函数它继承了父类AndroidRuntime的start函数因此下面会执行AndroidRuntime类的start函数。
Step 2. AndroidRuntime.start 这个函数定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中 cpp view plaincopy 1. / 2. Start the
Android runtime. This involves starting the virtual machine 3. and calling the quotstatic void mainString argsquot method in the class 4. named by quotclassNamequot. 5. / 6. void AndroidRuntime::startconst char className const bool startSystemServer 7. 8. ...... 9. 10. char slashClassName NULL 11. char cp 12. JNIEnv env 13. 14. ...... 15. 16. / start the virtual machine / 17. if startVmampmJavaVM ampenv 0 18. goto bail 19. 20. / 21. Register
android functions. 22. / 23. if startRegenv lt 0 24. LOGEquotUnable to register all
android nativesnquot 25. goto bail 26. 27. 28. / 29. We want to call main with a String array with arguments in it. 30. At present we only have one argument the class name. Create an 31. array to hold it. 32. / 33. jclass stringClass 34. jobjectArray strArray 35. jstring classNameStr 36. jstring startSystemServerStr 37. stringClass env-gtFindClassquotjava/lang/Stringquot 38. assertstringClass NULL 39. strArray env-gtNewObjectArray2 stringClass NULL 40. assertstrArray NULL 41. classNameStr env-gtNewStringUTFclassName 42. assertclassNameStr NULL 43. env-gtSetObjectArrayElementstrArray 0 classNameStr 44. startSystemServerStr env-gtNewStringUTFstartSystemServer 45. quottruequot : quotfalsequot 46. env-gtSetObjectArrayElementstrArray 1 startSystemServerStr 47. 48. / 49. Start VM. This thread becomes the main thread of the VM and will 50. not return until the VM exits. 51. / 52. jclass startClass 53. jmethodID startMeth 54. 55. slashClassName strdupclassName 56. for cp slashClassName cp 0 cp 57. if cp . 58. cp / 59. 60. startClass env-gtFindClassslashClassName 61. if startClass NULL 62. ...... 63. else 64. startMeth env-gtGetStaticMethodIDstartClass quotmainquot 65. quotLjava/lang/StringVquot 66. if startMeth NULL 67. ...... 68. else 69. env-gtCallStaticVoidMethodstartClass startMeth strArray 70. ...... 71. 72. 73. 74. ...... 75. 这个函数的作用是启动
Android系统运行时库它主要做了三件事情一是调用函数startVM启动虚拟机二是调用函数startReg注册JNI方法三是调用了com.
android.internal.os.ZygoteInit类的main函数。
Step 3. ZygoteInit.main 这个函数定义在frameworks/base/core/java/com/
android/internal/os/ZygoteInit.java文件中 java view plaincopy 1. public class ZygoteInit 2. ...... 3. 4. public static void mainString argv 5. try 6. ...... 7. 8. registerZygoteSocket 9. 10. ...... 11. 12. ...... 13. 14. if argv1.equalsquottruequot 15. startSystemServer 16. else if argv1.equalsquotfalsequot 17. ...... 18. 19. 20. ...... 21. 22. if ZYGOTE_FORK_MODE 23. ...... 24. else 25. runSelectLoopMode 26. 27. 28. ...... 29. catch MethodAndArgsCaller caller 30. ...... 31. catch RuntimeException ex 32. ...... 33. 34. 35. 36. ...... 37. 它主要作了三件事情一个调用registerZygoteSocket函数创建了一个socket接口用来和ActivityManagerService通讯二是调用startSystemServer函数来启动SystemServer组件三是调用runSelectLoopMode函数进入一个无限循环在前面创建的socket接口上等待ActivityManagerService请求创建新的应用程序进程。
Step 4. ZygoteInit.registerZygoteSocket 这个函数定义在frameworks/base/core/java/com/
android/internal/os/ZygoteInit.java文件中 java view plaincopy 1. public class ZygoteInit 2. ...... 3. 4. / 5. Registers a server socket for zygote command connections 6. 7. throws RuntimeException when open fails 8. / 9. private static void registerZygoteSocket 10. if sServerSocket null 11. int fileDesc 12. try 13. String env System.getenvANDROID_SOCKET_ENV 14. fileDesc Integer.parseIntenv 15. catch RuntimeException ex 16. ...... 17. 18. 19. try 20. sServerSocket new LocalServerSocket 21. createFileDescriptorfileDesc 22. catch IOException ex 23. ....... 24. 25. 26. 27. 28. ...... 29. 这个socket接口是通过文件描述符来创建的这个文件描符代表的就是我们前面说的/dev/socket/zygote文件了。
这个文件描述符是通过环境变量
ANDROID_SOCKET_ENV得到的它定义为 java view plaincopy 1. public class ZygoteInit 2. ...... 3. 4. private static final String
ANDROID_SOCKET_ENV quotANDROID_SOCKET_zygotequot 5. 6. ...... 7. 那么这个环境变量的值又是由谁来设置的呢我们知道系统启动脚本文件system/core/rootdir/init.rc是由init进程来解释执行的而init进程的源代码位于system/core/init目录中在init.c文件中是由service_start函数来解释init.rc文件中的service命令的 cpp view plaincopy 1. void service_startstruct service svc const char dynamic_args 2. 3. ...... 4. 5. pid_t pid 6. 7. ...... 8. 9. pid fork 10. 11. if pid 0 12. struct socketinfo si 13. 14. ...... 15. 16. for si svc-gtsockets si si si-gtnext 17. int socket_type 18. strcmpsi-gttype quotstreamquot SOCK_STREAM : 19. strcmpsi-gttype quotdgramquot SOCK_DGRAM : SOCK_SEQPACKET 20. int s create_socketsi-gtname socket_type 21. si-gtperm si-gtuid si-gtgid 22. if s gt 0 23. publish_socketsi-gtname s 24. 25. 26. 27. ...... 28. 29. 30. ...... 31. 每一个service命令都会促使init进程调用fork函数来创建一个新的进程在新的进程里面会分析里面的socket选项对于每一个socket选项都会通过create_socket函数来在/dev/socket目录下创建一个文件在这个场景中这个文件便是zygote了然后得到的文件描述符通过publish_socket函数写入到环境变量中去 cpp view plaincopy 1. static void publish_socketconst char name int fd 2. 3. char key64
ANDROID_SOCKET_ENV_PREFIX 4. char val64 5. 6. strlcpykey sizeofANDROID_SOCKET_ENV_PREFIX - 1 7. name 8. sizeofkey - sizeofANDROID_SOCKET_ENV_PREFIX 9. snprintfval sizeofval quotdquot fd 10. add_environmentkey val 11. 12. / make sure we dont close-on-exec / 13. fcntlfd F_SETFD 0 14. 这里传进来的参数name值为quotzygotequot而
ANDROID_SOCKET_ENV_PREFIX在system/core/include/cutils/sockets.h定义为 cpp view plaincopy 1. define
ANDROID_SOCKET_ENV_PREFIX quotANDROID_SOCKET_quot 因此这里就把上面得到的文件描述符写入到以quotANDROID_SOCKET_zygotequot为key值的环境变量中。
又因为上面的ZygoteInit.registerZygoteSocket函数与这里创建socket文件的create_socket函数是运行在同一个进程中因此上面的ZygoteInit.registerZygoteSocket函数可以直接使用这个文件描述符来创建一个Java层的LocalServerSocket对象。
如果其它进程也需要打开这个/dev/socket/zygote文件来和Zygote进程进行通信那就必须要通过文件名来连接这个LocalServerSocket了参考
Android应用程序进程启动过程的源代码分析一文中的Step 4ActivityManagerService是通过Process.start函数来创建一个新的进程的而Process.start函数会首先通过Socket连接到Zygote进程中最终由Zygote进程来完成创建新的应用程序进程而Process类是通过openZygoteSocketIfNeeded函数来连接到Zygote进程中的Socket的 java view plaincopy 1. public class Process 2. ...... 3. 4. private static void openZygoteSocketIfNeeded 5. throws ZygoteStartFailedEx 6. 7. ...... 8. 9. for int retry 0 10. sZygoteSocket null ampamp retry lt retryCount 1 11. retry 12. 13. ...... 14. 15. try 16. sZygoteSocket new LocalSocket 17. sZygoteSocket.connectnew LocalSocketAddressZYGOTE_SOCKET 18. LocalSocketAddress.Namespace.RESERVED 19. 20. sZygoteInputStream 21. new DataInputStreamsZygoteSocket.getInputStream 22. 23. sZygoteWriter 24. new BufferedWriter 25. new OutputStreamWriter 26. sZygoteSocket.getOutputStream 27. 256 28. 29. ...... 30. catch IOException ex 31. ...... 32. 33. 34. 35. ...... 36. 37. 38. ...... 39. 这里的ZYGOTE_SOCKET定义为 java view plaincopy 1. public class Process 2. ...... 3. 4. private static final String ZYGOTE_SOCKET quotzygotequot 5. 6. ...... 7. 它刚好就是对应/dev/socket目录下的zygote文件了。
Android系统中的socket机制和binder机制一样都是可以用来进行进程间通信读者可以自己对比一下这两者的不同之处Binder进程间通信机制可以参考
Android进程间通信IPC机制Binder简要介绍和学习计划一文。
Socket对象创.
上一篇:
Android应用程序开发(第二版)课后习题答案
下一篇:
硕士毕业论文要从技术上进行规范化调整