• Android系统启动之init进程启动+Zygote进程启动分析


    一、基础概念理解

    init进程

            Android系统所有进程的祖先,是Android系统内核初始化完毕后,进入用户空间启动的第一个进程。

    Android虚拟机

            Dalvik虚拟机是谷歌自己设计的用于Android平台的虚拟机。Android4.4同时提供了Dalvik和ART虚拟机。Android5.0以后,Dalvik虚拟机彻底被删除,ART虚拟机取而代之。

    Zygote

            中文翻译为“受精卵、结合子”

            Zygote是Android系统中,负责孵化所有其他应用进程的一个进程,Android系统是基于Linux内核的系统,所以Zygote进程是由Linux启动的用户级init进程创建的,Zygote是init进程的子进程,Zygote是一个java进程,负责启动Android虚拟机(Dalvik、ART)。

    二、Android系统启动过程

    第一步:BootLoader

            BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。

    第二步:Kernel

            Kernel指的是操作系统内核Linux初始化及启动。

    第三步:init进程启动

            init进程是Android内核初始化之后创建并启动的第一个进程,是所有进程的父进程,init进程首先调用/system/core/init/init.cpp(点击链接查看源码)的main方法,该方法做了两件事:

    (1),搭建系统运行环境,创建相关目录,设置相关路径和属性;

    (2),解析rc配置文件,执行rc配置文件所要求的动作和命令

    三、Zygote进程启动

    1,init如何启动Zygote服务

    (1)解析init.rc

            init.cpp的main方法中其中有一句代码parser.ParseConfig("/init.rc");用来读取rc配置并执行init.rc位于/system/core/rootdir/init.rc(点击链接查看源码)

    7 import /init.environ.rc

    8 import /system/etc/init/hw/init.usb.rc

    9 import /init.${ro.hardware}.rc

    10 import /vendor/etc/init/hw/init.${ro.hardware}.rc

    11 import /system/etc/init/hw/init.usb.configfs.rc

    12 import /system/etc/init/hw/init.${ro.zygote}.rc

    ...

    946 # It is recommended to put unnecessary data/ initialization from post-fs-data

    947 # to start-zygote in device's init.rc to unblock zygote start.

    948 on zygote-start && property:ro.crypto.state=unencrypted

    949 wait_for_prop odsign.verification.done 1

    950 # A/B update verifier that marks a successful boot.

    951 exec_start update_verifier_nonencrypted

    952 start statsd

    953 start netd

    954 start zygote

    955 start zygote_secondary

    956

    957 on zygote-start && property:ro.crypto.state=unsupported

    958 wait_for_prop odsign.verification.done 1

    959 # A/B update verifier that marks a successful boot.

    960 exec_start update_verifier_nonencrypted

    961 start statsd

    962 start netd

    963 start zygote

    964 start zygote_secondary

    965

    966 on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file

    967 wait_for_prop odsign.verification.done 1

    968 # A/B update verifier that marks a successful boot.

    969 exec_start update_verifier_nonencrypted

    970 start statsd

    971 start netd

    972 start zygote

    973 start zygote_secondary

    /init.${ro.zygote}.rc会根据硬件实际的配置,选择导入32位还是64位。在Android12上有这几个选择:init.zygote32.rcinit.zygote64.rcinit.zygote64_32.rc(点击链接查看源码)

    (2)启动Zygote服务

    start zygote是启动Zygote服务的方式,所以Zygote服务就会被启动

    Zygote服务就是下面配置文件中的服务【service zygote】

    比如设备是64位的,则init启动的就是/system/core/rootdir/init.zygote64.rc(点击链接查看源码)配置文件中的【service zygote】

    1 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server

    2 class main

    3 socket zygote stream 660 root system

    4 onrestart write /sys/android_power/request_state wake

    5 onrestart write /sys/power/state on

    6 onrestart restart audioserver

    7 onrestart restart cameraserver

    8 onrestart restart media

    9 onrestart restart netd

    10 writepid /dev/cpuset/foreground/tasks

    综上所述,Zygote进程是Init进程通过解析init.rc过程中又去解析了init.zygote64.rc或者init.zygote32.rc配置文件,以Service的方式创建并启动

    2,Zygote服务启动后,做了什么

    上面的zygote service配置中,有一个重要选项/system/bin/app_process64,通过执行app_process来进入zygote进程。

    app_process主要作用是解析启动参数,然后根据启动参数选择不同的启动模式

    执行 /system/bin/app_process64命令之后,程序就会执行到/frameworks/base/cmds/app_process/,该目录下面就是可执行文件,该路径下有app_main.cpp(点击链接查看源码),最终执行的就是app_main.cpp的main方法:

    /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server

    上面标红的是调用app_main.cpp的main()方法的入参,使用中间的空格符切割一下,得到5个值如下:

    1. /system/bin/app_process64
    2. -Xzygote
    3. /system/bin
    4. --zygote
    5. --start-system-server

    下面的main()函数两个入参,int argc,char* const argv[],其中argc是传入参数的数目,这里应该等于5,argv是传入参数的值,就是上面这5个切割后的字符串

    1. int main(int argc, char* const argv[])
    2. {
    3. ...
    4. //argc=5
    5. // argv[0]="/system/bin/app_process64"
    6. // argv[1]="-Xzygote"
    7. // argv[2]="/system/bin"
    8. // argv[3]="--zygote"
    9. // argv[4]="--start-system-server"
    10. argv[0]="/system/bin/app_process64"被传入runtime
    11. //AppRuntime继承自AndroidRuntime,
    12. //这里创建AppRuntime对象,main方法的操作都是通过这个runtime完成的
    13. AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    14. argc--;//执行此语句块后,argc=4
    15. argv++;//argv[0]被忽略
    16. // argc=4
    17. // argv[1]="-Xzygote"
    18. // argv[2]="/system/bin"
    19. // argv[3]="--zygote"
    20. // argv[4]="--start-system-server"
    21. int i;
    22. for (i = 0; i < argc; i++) {
    23. if (argv[i][0] != '-') {//很明显遍历到argv[2]="/system/bin"时候直接break
    24. break;
    25. }
    26. if (argv[i][1] == '-' && argv[i][2] == 0) {
    27. ++i; // Skip --.
    28. break;
    29. }
    30. //只有argv[1]="-Xzygote"会走到这一步,再往后遍历直接break了
    31. runtime.addOption(strdup(argv[i]));
    32. }
    33. //上一步又使用了一个参数argv[1]="-Xzygote"。忽略掉,所以代码走到这里还剩下三个参数
    34. // argc=3
    35. // argv[2]="/system/bin"
    36. // argv[3]="--zygote"
    37. // argv[4]="--start-system-server"
    38. bool zygote = false;
    39. bool startSystemServer = false;
    40. bool application = false;
    41. String8 niceName;
    42. String8 className;
    43. ++i; // Skip unused "parent dir" argument.
    44. while (i < argc) {
    45. const char* arg = argv[i++];
    46. if (strcmp(arg, "--zygote") == 0) {
    47. // argv[3]="--zygote"满足条件,zygote=true,表示当前进程是zygote
    48. zygote = true;
    49. //static const char ZYGOTE_NICE_NAME[] = "zygote64";
    50. //static const char ZYGOTE_NICE_NAME[] = "zygote";
    51. niceName = ZYGOTE_NICE_NAME;//设置niceName为zygote64或者zygote
    52. } else if (strcmp(arg, "--start-system-server") == 0) {
    53. // argv[4]="--start-system-server",这里说明需要启动System Server
    54. startSystemServer = true;
    55. } else if (strcmp(arg, "--application") == 0) {
    56. application = true;
    57. } else if (strncmp(arg, "--nice-name=", 12) == 0) {
    58. niceName.setTo(arg + 12);
    59. } else if (strncmp(arg, "--", 2) != 0) {
    60. className.setTo(arg);
    61. break;
    62. } else {
    63. --i;
    64. break;
    65. }
    66. }
    67. //设置后面调用ZygoteInit.java的main方法或者RuntimeInit.java的Main方法的参数
    68. //这里的参数先是传给了Runtime的start方法,start方法里面又将其转成Java参数的
    69. Vector args;
    70. if (!className.isEmpty()) {
    71. //非Zygote模式,这种情况可能是application模式或者tool模式
    72. args.add(application ? String8("application") : String8("tool"));
    73. runtime.setClassNameAndArgs(className, argc - i, argv + i);
    74. } else {
    75. //Zygote模式,这里可以证明后续调用ZygoteInit的main方法,会启动System Server服务
    76. if (startSystemServer) {
    77. args.add(String8("start-system-server"));
    78. }
    79. char prop[PROP_VALUE_MAX];
    80. if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
    81. LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
    82. ABI_LIST_PROPERTY);
    83. return 11;
    84. }
    85. String8 abiFlag("--abi-list=");
    86. abiFlag.append(prop);
    87. args.add(abiFlag);
    88. // In zygote mode, pass all remaining arguments to the zygote
    89. // main() method.
    90. for (; i < argc; ++i) {
    91. args.add(String8(argv[i]));
    92. }
    93. }
    94. //niceName在参数解析时被设置。此处变更了app_process启动的进程名为zygote。
    95. if (!niceName.isEmpty()) {
    96. runtime.setArgv0(niceName.string());
    97. set_process_name(niceName.string());
    98. }
    99. //runtime.start启动Android运行环境
    100. if (zygote) {
    101. //com.android.internal.os.ZygoteInit是Android Java运行时环境的初始化类,
    102. runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    103. } else if (className) {
    104. //非Zygote模式,则执行RuntimeInit.java的main方法
    105. runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    106. } else {
    107. fprintf(stderr, "Error: no class name or --zygote supplied.\n");
    108. app_usage();
    109. LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    110. return 10;
    111. }
    112. }

    app_main.cpp的main方法,主要做了三件事儿:

    1. 初始化AndroidRuntime;
    2. 解析main函数的参数,判断当前是不是Zygote模式;
    3. 根据是否是Zygote模式,调用AndroidRuntime的start方法传入不同的参数

    app_process是c++本地程序,源码目录为 frameworks/base/cmds/app_process/

    app_process是可以执行java代码的命令(因为它启动了一个java虚拟机),它有两种启动模式:

    1.zygote 模式:通常情况下,在–start-system-server启动参数的配置下,app_process启动之后,直接fork system_server 子进程,拉起整个android系统,之后用来孵化apk进程

    2.非zygote模式:分两种子模式

    (1).application模式:这种模式是zygote 创建进程后通过shell来重新加载app_process命令再执行的

    (2).tool模式:这个模式主要是用来执行调试命令(如am\pm\wm等等)

    AppRuntime继承自AndroidRuntime,AndroidRuntime的start方法,我们暂且先看下它的注释吧:

    启动Android运行时。这涉及到启动虚拟机并在类中调用“static void main(String[] args)”方法由“className”命名。

    传递给main函数两个参数,类名和指定的选项字符串。

    /frameworks/base/core/jni/AndroidRuntime.cpp(点击链接查看源码)的start方法

    1. void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
    2. {
    3. ...
    4. /* start the virtual machine */
    5. JniInvocation jni_invocation;
    6. jni_invocation.Init(NULL);
    7. JNIEnv* env;
    8. //startVm 创建、启动虚拟机,并且设置相关参数。Dalvik或者ART虚拟机
    9. if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
    10. return;
    11. }
    12. onVmCreated(env);
    13. /*
    14. *向虚拟机注册Android JNI native函数,(系统so库,用户自定义so库,加载函数等)
    15. */
    16. if (startReg(env) < 0) {
    17. ALOGE("Unable to register all android natives\n");
    18. return;
    19. }
    20. //给接下来要调用的java main方法准备参数
    21. //非常经典的在Native层创建Java层对象的操作:
    22. //创建一个java.lang.String的数组对象
    23. //并根据传入的参数对数组对象逐个元素进行赋值
    24. jclass stringClass;
    25. jobjectArray strArray;
    26. jstring classNameStr;
    27. stringClass = env->FindClass("java/lang/String");
    28. assert(stringClass != NULL);
    29. strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    30. assert(strArray != NULL);
    31. classNameStr = env->NewStringUTF(className);
    32. assert(classNameStr != NULL);
    33. env->SetObjectArrayElement(strArray, 0, classNameStr);
    34. for (size_t i = 0; i < options.size(); ++i) {
    35. jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
    36. assert(optionsStr != NULL);
    37. env->SetObjectArrayElement(strArray, i + 1, optionsStr);
    38. }
    39. ....
    40. //找到传进来的类的main方法,比如ZygoteInit的main方法
    41. jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
    42. "([Ljava/lang/String;)V");
    43. if (startMeth == NULL) {
    44. ALOGE("JavaVM unable to find main() in '%s'\n", className);
    45. /* keep going */
    46. } else {
    47. //通过JNI技术调用main方法
    48. env->CallStaticVoidMethod(startClass, startMeth, strArray);
    49. #if 0
    50. if (env->ExceptionCheck())
    51. threadExitUncaughtException(env);
    52. #endif
    53. }
    54. }
    55. ...
    56. }

    综上所述,AndroidRuntime.star方法,主要做了三件事儿:

    1. 创建、启动了Android虚拟机;
    2. 向虚拟机注册了Android JNI native函数;
    3. 利用JNI技术调用了参数传进来的className对应类的main()函数。

    如果不考虑非Zygote模式,那么Zygote服务的启动,执行app_main.cpp的main方法

    而app_main.cpp的main方法做了四件事:

    1. 创建、启动了Android虚拟机;
    2. 向虚拟机注册了Android JNI native函数;
    3. 准备Java类的main方法的参数
    4. 利用JNI技术调用了ZygoteInit的main()方法。

    下面就要分析ZygoteInit了

    3,执行ZygoteInit.java的main方法

    ZygoteInit:负责Zygote进程Java层的初始化工作

    1. public static void main(String argv[]) {
    2. //创建Zygote服务管理类,用来注册Socket监听
    3. ZygoteServer zygoteServer = new ZygoteServer();
    4. //这里主要目的是拦截创建线程,
    5. //调用了这句代码以后,标记着Zygote进程开始Java层的初始化工作
    6. //如果此时创建线程会产生错误
    7. ZygoteHooks.startZygoteNoThreadCreation();
    8. // 将Zygote设置进他自己的进程组
    9. try {
    10. //将参数pid指定进程所属的组识别码设为参数pgid指定的组识别码。
    11. //Os.setpgid(int pid, int pgid)
    12. //pid=0表示设置当前进程所在的组的进程组pgid
    13. //pgid=0表示当前进程的PID为进程组pgid
    14. Os.setpgid(0, 0);
    15. } catch (ErrnoException ex) {
    16. throw new RuntimeException("Failed to setpgid(0,0)", ex);
    17. }
    18. final Runnable caller;
    19. try {
    20. // Report Zygote start time to tron unless it is a runtime restart
    21. ...日志打印
    22. //启动DDMS虚拟机监控调试服务
    23. RuntimeInit.enableDdms();
    24. //参数解析
    25. boolean startSystemServer = false;
    26. String socketName = "zygote";
    27. String abiList = null;
    28. boolean enableLazyPreload = false;
    29. for (int i = 1; i < argv.length; i++) {
    30. if ("start-system-server".equals(argv[i])) {
    31. //开启系统服务,这个参数是传进来的
    32. startSystemServer = true;
    33. } else if ("--enable-lazy-preload".equals(argv[i])) {
    34. enableLazyPreload = true;
    35. } else if (argv[i].startsWith(ABI_LIST_ARG)) {
    36. //abi类型,"--abi-list="这个参数也是传经来的
    37. abiList = argv[i].substring(ABI_LIST_ARG.length());
    38. } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
    39. //解析Socket name
    40. socketName = argv[i].substring(SOCKET_NAME_ARG.length());
    41. } else {//未知参数
    42. throw new RuntimeException("Unknown command line argument: " + argv[i]);
    43. }
    44. }
    45. //没有指定ABI参数会抛异常
    46. if (abiList == null) {
    47. throw new RuntimeException("No ABI list supplied.");
    48. }
    49. //注册Zygote的Socket服务端,用来监听接收启动应用程序的消息,这里的IPC不是Binder通信
    50. zygoteServer.registerServerSocketFromEnv(socketName);
    51. // In some configurations, we avoid preloading resources and classes eagerly.
    52. // In such cases, we will preload things prior to our first fork.
    53. if (!enableLazyPreload) {//没有延迟加载
    54. ...
    55. //执行预加载操作,包括系统预加载类,FrameWork资源,OpenGL资源
    56. preload(bootTimingsTraceLog);
    57. ...
    58. } else {//有延迟加载
    59. //重置线程优先级,设置为默认的Thread.NORM_PRIORITY
    60. Zygote.resetNicePriority();
    61. }
    62. ...
    63. //运行几个指定的GC,尝试清除几代的软引用和可达的对象,以及任何其他垃圾。
    64. //这只在fork()之前有用。强制进行了一次垃圾收集
    65. gcAndFinalize();
    66. ...
    67. //在fork之前调用一些安全初始化操作
    68. Zygote.nativeSecurityInit();
    69. //将整体的的存储目录/storage卸载,取而代之的是挂载临时目录,
    70. //这个动作和Android的沙箱(隔离存储)有关
    71. Zygote.nativeUnmountStorageOnInit();
    72. //呼应前面的ZygoteHooks.startZygoteNoThreadCreation()方法
    73. //告诉虚拟机,现在可以创建县城了
    74. ZygoteHooks.stopZygoteNoThreadCreation();
    75. if (startSystemServer) {//启动systemServer进程
    76. //这里的forkSystemServer方法导致进程进程发生了fork,也就是孵化裂变
    77. //从Zygote进程变成了Zygote和systemserver两个进程,fork会导致堆栈段的复制
    78. //进程会切换执行,涉及到CPU的切换,上下文的切换导致两个进程代码执行都停留在fork函数
    79. //两个进程都执行到fork函数等待返回,因此fork函数我们看代码是两次返回。
    80. //实际上fork函数的两次返回,是在两个进程中进行的:
    81. //先是在父进程中返回了被fork出来的子进程的pid
    82. //CPU执行切换到子进程之后因为在没有fork子进程,所以返回了0
    83. Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
    84. //如果r=null,说明当前代码在Zygote进程中执行,直接跳过
    85. if (r != null) {
    86. //如果r!=null,说明当前代码在子进程(systemserver)中执行
    87. //启动进程后返回
    88. //因为Runnable的run方法实际上包装了SystemServer的main方法,所以这里会运行main方法
    89. r.run();
    90. return;
    91. }
    92. }
    93. //走到这一步,代码没有返回,说明这里的代码是在Zygote进程中执行的,
    94. //因为如果是孵化的子进程的话,走不到这一步代码就return了
    95. //此处进入一个无限循环,处理Zygote Socket接收到的数据,
    96. caller = zygoteServer.runSelectLoop(abiList);
    97. } catch (Throwable ex) {
    98. Log.e(TAG, "System zygote died with exception", ex);
    99. throw ex;
    100. } finally {
    101. //关闭释放Sockte连接
    102. //这里的代码主要是给子进程调用的,因为Zygote进程在runSelectLoop中无限循环阻塞了,
    103. //正常情况不会执行到这
    104. //子进程是由Zygote这个父进程fork出来的,所以也会附带有Socket连接,
    105. //但是子进程不需要Zygote的Socket服务,这里保证关闭
    106. zygoteServer.closeServerSocket();
    107. }
    108. //我们在子进程中并退出了select循环。继续执行命令。
    109. if (caller != null) {
    110. caller.run();
    111. }
    112. }

    (1)registerServerSocketFromEnv注册Zygote的Socket服务

    1. void registerServerSocketFromEnv(String socketName) {
    2. ...
    3. //这里的socketName来源于上面的main函数zygote
    4. //所以最终fullSocketName=ANDROID_SOCKET_zygote
    5. final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
    6. ...
    7. //找到名称为ANDROID_SOCKET_zygote的环境变量
    8. String env = System.getenv(fullSocketName);
    9. fileDesc = Integer.parseInt(env);
    10. ...
    11. FileDescriptor fd = new FileDescriptor();
    12. fd.setInt$(fileDesc);
    13. //创建一个本地socket服务,赋值给全局变量mServerSocket
    14. mServerSocket = new LocalServerSocket(fd);
    15. ...
    16. }

    注意上面的这句代码:

    String env = System.getenv(fullSocketName);

            获取进程中名字为ANDROID_SOCKET_zygote的环境变量,那么这个环境变量是什么时候写进去的呢?我们前面分析/system/core/rootdir/init.rc(点击链接查看源码)时候讲到,他会解析/system/core/rootdir/init.zygote64.rc(点击链接查看源码)这个配置文件,init.zygote64.rc(点击链接查看源码)里面有这样一句socket zygote stream 660 root system,init进程在解析到这句配置的时候,会创建一个Socket fileDesc(简称socket fd)也就进程独有的文件描述符并且与ANDROID_SOCKET_zygote这个名字绑定,然后将socket名字(ANDROID_SOCKET_zygote)和socket fd注册到init进程的环境变量里面。其他进程都是init进程的子进程,可以通过System.getenv("ANDROID_SOCKET_zygote")获取到这个环境变量。

    我们感兴趣的可以看下某 socket fd长什么样子?如下:

    root@ubuntu:~# ll /proc/1583/fd

    total 0

    lrwx------ 1 root root 64 Jul 19 12:37 7 -> socket:[18892]

    lrwx------ 1 root root 64 Jul 19 12:37 8 -> socket:[18893]

    LocalSocket是Google为我们带来的,比Java的socket效率更高,没有经过协议栈,是Android自己实现的类似共享内存一样的东西,在传输大量数据的时候就需要用到。

    (2)preload预加载

            Android的Java进程都是通过Zygote进程fork的,Zygote通过预加载类和资源可以加快子进程的执行速度和内存优化,因为预加载的类和资源比较多,所以开机时也需要重点关注preload的耗时。

    1. static void preload(TimingsTraceLog bootTimingsTraceLog) {
    2. //设置软引用保护,避免在预加载期间创建的引用被GC回收
    3. beginIcuCachePinning();
    4. //预加载系统类
    5. //读取设备本地/system/etc/preloaded-classes文件,解析该文件,
    6. //通过反射技术加载文件中声明的所有类,不同的手机厂商定义的类数量有差异,
    7. //有时需要加载数千个类,这也是设备启动慢的原因之一
    8. //Android12中preloaded-classes的源码在/frameworks/base/config/preloaded-classes
    9. preloadClasses();
    10. //预加载系统资源
    11. //com.android.internal.R.array.preloaded_drawables
    12. //com.android.internal.R.array.preloaded_color_state_lists
    13. //Android系统有一个framework-res.apk包,这些系统资源就是存在这个当中
    14. //Android应用可以使用这些公共资源
    15. preloadResources();
    16. //调用native方法加载HAL(硬件抽象层)代码
    17. //所谓HAL硬件抽象层
    18. nativePreloadAppProcessHALs();
    19. 加载OpenGL资源
    20. preloadOpenGL();
    21. //加载一些so库:libandroid.so、libcompiler_rt.so、libjnigraphics.so
    22. preloadSharedLibraries();
    23. //加载字体资源
    24. preloadTextResources();
    25. //要求WebViewFactory所有初始化必须在Zygote进程中进行
    26. WebViewFactory.prepareWebViewInZygote();
    27. //与前面的beginIcuCachePinning()呼应,取消软引用保护
    28. endIcuCachePinning();
    29. //初始化JCA相关参数
    30. warmUpJcaProviders();
    31. sPreloadComplete = true;
    32. }

            Zygote进程启动时候预加载了不少资源,那么后续Zygote在fork新进程的时候,采用了COW(copy-on-write)技术,即写时拷贝技术。当App通过fork创建的时候,为了节省开销、加快应用启动,Zygote fork子进程不进行内存复制,而是共享Zygote进程预加载的系统类和系统资源,只有当子进程需要修改共享资源时,才会将共享内存复制到自己的进程内做修改。

    (3)forkSystemServer孵化systemserver进程并启动

    SystemServer是Android基本服务的提供者,是Android系统运行的最基本需求,所有Service运行在一个叫system_server的进程中,system_server为Android系统提供了各种Service。system_server进程是Android Java虚拟机中第一个进程,可以说整个Android系统的业务都是system_server展开的。

    forkSystemServer方法,为孵化SystemServer进程准备参数,并且fork出systemServer进程

            注意,forkSystemServer方法因为是fork新的进程出来,新进程代码也会执行到forkSystemServer方法,这就会导致Zygote进程、system_server进程一起从fork函数返回。如果方法是在Zygote进程中执行的,则返回被fork出的SystemServer进程的Runnable对象;如果方法是在SystemServer进程中执行的,则因为其没有继续fork子进程,所以没有需要执行的Runnable任务,返回null

    1. private static Runnable forkSystemServer(String abiList, String socketName,
    2. ZygoteServer zygoteServer) {
    3. ...
    4. //参数准备
    5. String args[] = {
    6. "--setuid=1000",
    7. "--setgid=1000",
    8. "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
    9. "--capabilities=" + capabilities + "," + capabilities,
    10. "--nice-name=system_server",
    11. "--runtime-args",
    12. "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
    13. "com.android.server.SystemServer",
    14. };
    15. ZygoteConnection.Arguments parsedArgs = null;
    16. int pid;
    17. try {
    18. //参数解析,生成目标函数
    19. parsedArgs = new ZygoteConnection.Arguments(args);
    20. ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
    21. ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
    22. boolean profileSystemServer = SystemProperties.getBoolean(
    23. "dalvik.vm.profilesystemserver", false);
    24. if (profileSystemServer) {
    25. parsedArgs.runtimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
    26. }
    27. //这里是重点,fork出system_server进程,并运行system_server进程
    28. //fork动作会产生一个新的与Zygote一样的新的进程,并且云心新进程,
    29. //这样就导致了Zygote进程与system_server两个进程CPU执行权切换,
    30. //两个进程都停留在fork方法等待返回,两个fork方法是在两个进程中运行的,自然分别有对应返回值。
    31. //当fork方法运行在Zygote进程中时候,则返回其fork出子进程的pid,也就是system_server的pid;
    32. //当fork方法运行在system_server进程中时候,因为其没有继续fork的子进程,所以返回0
    33. pid = Zygote.forkSystemServer(
    34. parsedArgs.uid, parsedArgs.gid,
    35. parsedArgs.gids,
    36. parsedArgs.runtimeFlags,
    37. null,
    38. parsedArgs.permittedCapabilities,
    39. parsedArgs.effectiveCapabilities);
    40. } catch (IllegalArgumentException ex) {
    41. throw new RuntimeException(ex);
    42. }
    43. /* For child process */
    44. if (pid == 0) {
    45. //走到这里说明当前代码运行在system_Server进程当中
    46. if (hasSecondZygote(abiList)) {
    47. //如果设备同时配置了两个Zygote进程,那么这里等待第二个Zygote进程
    48. //这里主要是一些设备配置了init.zygote32_64.rc或者init.zygote64_32.rc
    49. //这样就会启动两个Zygote进程,一个为主,一个为次
    50. waitForSecondaryZygote(socketName);
    51. }
    52. //子进程是由Zygote孵化出来的,所以也具备了zygoteServer的Socket服务
    53. //但是子进程用不到,所以直接关闭
    54. zygoteServer.closeServerSocket();
    55. //handleSystemServerProcess方法的作用:
    56. //利用反射技术找到SystemServer的main函数,并将这个函数包装到Runnable的run方法中
    57. //返回包装后的Runnable对象
    58. return handleSystemServerProcess(parsedArgs);
    59. }
    60. return null;
    61. }

    (4)zygoteServer.runSelectLoop进入循环阻塞等待for新进程的请求

            Zygote进程会启动一个Socket本地服务,等待Socket客户端连接请求,当新的App启动的时候,就会请求zygote server服务fork新的进程。

            zygoteServer.runSelectLoop会进入循环阻塞等待,等待处理启动新应用的请求,一旦收到请求会fork新的进程出来。

            与上面的forkSystemServer一个道理,Zygote在fork新的进程,就会造成新老进程的runSelectLoop方法都执行但是返回值不同。当在子进程中时,会跳出runSelectLoop的循环,返回Runnable对象,也就是说在子进程中是不存在阻塞的,Zygote进程会保持阻塞监控新的连接请求

    1. Runnable runSelectLoop(String abiList) {
    2. ArrayList fds = new ArrayList();
    3. ArrayList peers = new ArrayList();
    4. //执行完下面这句代码,表示fds中只有一个元素,那就是mServerSocket
    5. fds.add(mServerSocket.getFileDescriptor());
    6. peers.add(null);
    7. while (true) {
    8. //每次循环都会动态创建新的pollFds
    9. StructPollfd[] pollFds = new StructPollfd[fds.size()];
    10. for (int i = 0; i < pollFds.length; ++i) {
    11. pollFds[i] = new StructPollfd();
    12. pollFds[i].fd = fds.get(i);
    13. //关注事件的到来
    14. pollFds[i].events = (short) POLLIN;
    15. }
    16. try {
    17. //Os.pull是Linux系统的一个处理文件描述符的方法,等待文件描述符上的某个事件,I/O服用机制
    18. //监听pollFds数组中的事件,当pollFds有事件到来就往下执行
    19. //这里的-1表示当没有事件到来时一直阻塞,
    20. Os.poll(pollFds, -1);
    21. } catch (ErrnoException ex) {
    22. throw new RuntimeException("poll failed", ex);
    23. }
    24. //代码走到这里说明上面的poll阻塞方法有返回了,也就是pollFds有数据到来了
    25. for (int i = pollFds.length - 1; i >= 0; --i) {
    26. if ((pollFds[i].revents & POLLIN) == 0) {
    27. //采用I/O多路复用机制,当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行;
    28. //否则进入continue,跳出本次循环。
    29. continue;
    30. }
    31. if (i == 0) {
    32. //fds[0]是mServerSocket
    33. //Socket服务端是LocalServerSocket,Socket客户端应该是LocalSocket
    34. //acceptCommandPeer方法就是给mServerSocket创建了一个与之连接的LocalSocket客户端
    35. //ZygoteConnection内部分装了LocalSocket客户端
    36. ZygoteConnection newPeer = acceptCommandPeer(abiList);
    37. peers.add(newPeer);
    38. //将通信对象添加到fds
    39. fds.add(newPeer.getFileDesciptor());
    40. } else {
    41. //这里就是遍历到了上面新添加的Socket通信对象
    42. try {
    43. ZygoteConnection connection = peers.get(i);
    44. //processOneCommand会读取参数并且fork新的子进程及相关操作
    45. //因为这里最终会是fork操作,所以同样的会造成父进程子进程都运行这段代码
    46. //当在子进程中运行,则command不为空,Zygote中command为空
    47. final Runnable command = connection.processOneCommand(this);
    48. if (mIsForkChild) {
    49. //已经fork了子进程,并且当前代码运行在子进程
    50. if (command == null) {
    51. //保证fork子进程后必须有command返回
    52. throw new IllegalStateException("command == null");
    53. }
    54. //在子进程中,返回command
    55. return command;
    56. } else {
    57. if (command != null) {
    58. //保证父进程不能存在command
    59. throw new IllegalStateException("command != null");
    60. }
    61. //Zygote进程,完成了子进程的fork后,应该关闭本次的Socket连接,并清除该连接
    62. if (connection.isClosedByPeer()) {
    63. connection.closeSocket();
    64. peers.remove(i);
    65. fds.remove(i);
    66. }
    67. }
    68. } catch (Exception e) {
    69. if (!mIsForkChild) {
    70. //发生异常后清除操作
    71. ZygoteConnection conn = peers.remove(i);
    72. conn.closeSocket();
    73. fds.remove(i);
    74. } else {
    75. Log.e(TAG, "Caught post-fork exception in child process.", e);
    76. throw e;
    77. }
    78. } finally {
    79. //每次处理完客户端请求后,保证mIsForkChild为false
    80. mIsForkChild = false;
    81. }
    82. }
    83. }
    84. }
    85. }

    下面看下connection.processOneCommand(this)方法的源码

    1. Runnable processOneCommand(ZygoteServer zygoteServer) {
    2. String args[];
    3. Arguments parsedArgs = null;
    4. FileDescriptor[] descriptors;
    5. try {
    6. //读取参数
    7. args = readArgumentList();
    8. descriptors = mSocket.getAncillaryFileDescriptors();
    9. } catch (IOException ex) {
    10. throw new IllegalStateException("IOException on command socket", ex);
    11. }
    12. ...
    13. //解析参数
    14. parsedArgs = new Arguments(args);
    15. if (parsedArgs.abiListQuery) {
    16. handleAbiListQuery();
    17. return null;
    18. }
    19. if (parsedArgs.preloadDefault) {
    20. handlePreload();
    21. return null;
    22. }
    23. if (parsedArgs.preloadPackage != null) {
    24. handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs,
    25. parsedArgs.preloadPackageLibFileName, parsedArgs.preloadPackageCacheKey);
    26. return null;
    27. }
    28. if (parsedArgs.apiBlacklistExemptions != null) {
    29. handleApiBlacklistExemptions(parsedArgs.apiBlacklistExemptions);
    30. return null;
    31. }
    32. if (parsedArgs.hiddenApiAccessLogSampleRate != -1) {
    33. handleHiddenApiAccessLogSampleRate(parsedArgs.hiddenApiAccessLogSampleRate);
    34. return null;
    35. }
    36. if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
    37. throw new ZygoteSecurityException("Client may not specify capabilities: " +
    38. "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
    39. ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
    40. }
    41. //参数检查和设置
    42. // 检查客户端手有权限指定进程的用户ID、组ID
    43. // 如果是 root 进程,可以任意指定
    44. // 如果是 sys 进程,需要在ro.factorytest值 > 0时可以指定
    45. applyUidSecurityPolicy(parsedArgs, peer);
    46. // 判断是否具有invoke-with的执行权限
    47. applyInvokeWithSecurityPolicy(parsedArgs, peer);
    48. // 如果ro.debuggable是1的话,启动JDWP协议
    49. applyDebuggerSystemProperty(parsedArgs);
    50. // 如果ro.debuggable是1的话,启动JDWP协议
    51. applyInvokeWithSystemProperty(parsedArgs);
    52. ...
    53. //fork子进程,fork方法孵化子进程后,与Zygote进程都会运行并返回值
    54. //当前代码运行在Zygote进程中时,返回的pid就是fork得到的子进程的pid
    55. //当前代码如果运行在子进程中,则pid=0
    56. pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
    57. parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
    58. parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
    59. parsedArgs.instructionSet, parsedArgs.appDataDir);
    60. try {
    61. if (pid == 0) {
    62. //当前处于子进程中
    63. zygoteServer.setForkChild();
    64. //子进程由Zygote进程fork出来,所以也具备了zygoteServer,但是不需要,所以关闭
    65. zygoteServer.closeServerSocket();
    66. IoUtils.closeQuietly(serverPipeFd);
    67. serverPipeFd = null;
    68. //在子进程中完成子进程的初始化工作
    69. return handleChildProc(parsedArgs, descriptors, childPipeFd,
    70. parsedArgs.startChildZygote);
    71. } else {
    72. //fork完子进程后,父进程中处理一些关闭及清理的工作
    73. IoUtils.closeQuietly(childPipeFd);
    74. childPipeFd = null;
    75. handleParentProc(pid, descriptors, serverPipeFd);
    76. return null;
    77. }
    78. } finally {
    79. IoUtils.closeQuietly(childPipeFd);
    80. IoUtils.closeQuietly(serverPipeFd);
    81. }
    82. }

    我们来看下fork出子进程之后,子进程是如何完成初始化的操作的,handleChildProc方法源码如下

    1. private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
    2. FileDescriptor pipeFd, boolean isZygote) {
    3. //关闭本次操作的Socket连接
    4. closeSocket();
    5. ...
    6. if (parsedArgs.invokeWith != null) {
    7. //启动参数有--invoke-with
    8. WrapperInit.execApplication(parsedArgs.invokeWith,
    9. parsedArgs.niceName, parsedArgs.targetSdkVersion,
    10. VMRuntime.getCurrentInstructionSet(),
    11. pipeFd, parsedArgs.remainingArgs);
    12. // Should not get here.
    13. throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
    14. } else {//通常情况下--invoke-with参数为空,所以代码会进入这里
    15. if (!isZygote) {
    16. //很显然当前是在子进程运行而非Zygote进程中,所以代码执行这里
    17. return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
    18. null /* classLoader */);
    19. } else {
    20. return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
    21. parsedArgs.remainingArgs, null /* classLoader */);
    22. }
    23. }
    24. }

    我们进入ZygoteInit.zygoteInit方法

    1. public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
    2. String[] argv, ClassLoader classLoader) {
    3. ...
    4. //一些通用的简单初始化
    5. RuntimeInit.commonInit();
    6. //调用了一个本地native方法,最终调用了我们前面提到的AndroidRuntime的子类AppRuntime的onZygoteInit()方法
    7. //初始化binder的使用环境
    8. ZygoteInit.nativeZygoteInit();
    9. //这里最终调用了RuntimeInit.findStaticMain方法
    10. return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
    11. classLoader);
    12. }

    我们先来看一下AppRuntime的onZygoteInit()方法的源码,源码在app_main.cppAppRuntime下面

    1. virtual void onZygoteInit(){
    2. sp proc = ProcessState::self();
    3. ALOGV("App process: starting thread pool.\n");
    4. proc->startThreadPool();
    5. }

    这个onZygoteInit主要就是用来初始化Binder的使用环境

    我们最后看下RuntimeInit.findStaticMain方法,其实这个方法在前面forkSystemServer中也用过这个方法,findStaticMain方法,会将参数传入的className通过反射的技术,找到其main方法,并且包装到Runnable的run方法中返回

    1. protected static Runnable findStaticMain(String className, String[] argv,
    2. ClassLoader classLoader) {
    3. Class cl;
    4. try {
    5. cl = Class.forName(className, true, classLoader);
    6. } catch (ClassNotFoundException ex) {
    7. throw new RuntimeException(
    8. "Missing class when invoking static main " + className,
    9. ex);
    10. }
    11. Method m;
    12. try {
    13. m = cl.getMethod("main", new Class[] { String[].class });
    14. } catch (NoSuchMethodException ex) {
    15. throw new RuntimeException(
    16. "Missing static main on " + className, ex);
    17. } catch (SecurityException ex) {
    18. throw new RuntimeException(
    19. "Problem getting static main on " + className, ex);
    20. }
    21. ...
    22. return new MethodAndArgsCaller(m, argv);
    23. }
    1. static class MethodAndArgsCaller implements Runnable {
    2. private final Method mMethod;
    3. private final String[] mArgs;
    4. public MethodAndArgsCaller(Method method, String[] args) {
    5. mMethod = method;
    6. mArgs = args;
    7. }
    8. public void run() {
    9. ...
    10. mMethod.invoke(null, new Object[] { mArgs });
    11. ...
    12. }
    13. }

            而我们这里,handleChildProc方法,最终返回的MethodAndArgsCaller(Runnable的子类),实际上是利用反射技术将android.app.ActivityThread的main()方法封装到Runnable的run()方法里面。而ActivityThread的main方法正式整个App入口。

    (5)caller.run()子进程调用App启动入口方法ActivityThread.main

    我们回顾一下ZygoteInit.main方法的最后处理逻辑

    1. public static void main(String argv[]) {
    2. ...
    3. final Runnable caller;
    4. try {
    5. ...
    6. if (startSystemServer) {//启动systemServer进程
    7. Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
    8. if (r != null) {
    9. r.run();
    10. return;
    11. }
    12. }
    13. //如果当前代码运行在Zygote进程,则返回null
    14. //如果当前代码运行在子进程,则返回caller
    15. caller = zygoteServer.runSelectLoop(abiList);
    16. } catch (Throwable ex) {
    17. Log.e(TAG, "System zygote died with exception", ex);
    18. throw ex;
    19. } finally {
    20. zygoteServer.closeServerSocket();
    21. }
    22. //根据前面的讲解,我们能够知道Zygote在fork进程时会发生两个进程各自运行同一处代码,
    23. //根据桑上面的runSelectLoop方法会将Zygote进程处于阻塞状态,无限循环等待Socket客户端
    24. //发起请求,比如App的启动会出发zygoteServer与Zocket客户端连接,然后fork出App的进程
    25. //当代码运行在App进程(子进程)中时,将会跳出阻塞,返回caller,Zygote父进程继续保持
    26. //阻塞监听。
    27. if (caller != null) {
    28. //执行到这一步,我们可以确定当前代码运行在子进程,此处的run方法运行的就是ActivityThread
    29. //的main方法。
    30. caller.run();
    31. }
    32. }

    4,Android如何利用Zygote启动一个新进程

            Android启动一个新的进程都是在ActivityManagerService(简称AMS)中完成的,可能会有很多原因导致系统启动一个新的进程,最终在AMS中都是通过调用startProcess()方法来实现。

            通过查看ActivityManagerService.startProcess的源码,找到了关键的代码,最终调用了ZygoteProcess类的一个私有方法startViaZygote()方法,我们重点看下startViaZygote的关键代码

    1. private Process.ProcessStartResult startViaZygote(final String processClass,
    2. final String niceName,
    3. final int uid, final int gid,
    4. final int[] gids,
    5. int runtimeFlags, int mountExternal,
    6. int targetSdkVersion,
    7. String seInfo,
    8. String abi,
    9. String instructionSet,
    10. String appDataDir,
    11. String invokeWith,
    12. boolean startChildZygote,
    13. String[] extraArgs)
    14. throws ZygoteStartFailedEx {
    15. ArrayList argsForZygote = new ArrayList();
    16. // --runtime-args, --setuid=, --setgid=,
    17. // and --setgroups= must go first
    18. argsForZygote.add("--runtime-args");
    19. argsForZygote.add("--setuid=" + uid);
    20. argsForZygote.add("--setgid=" + gid);
    21. argsForZygote.add("--runtime-flags=" + runtimeFlags);
    22. if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
    23. argsForZygote.add("--mount-external-default");
    24. } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
    25. argsForZygote.add("--mount-external-read");
    26. } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
    27. argsForZygote.add("--mount-external-write");
    28. }
    29. argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
    30. // --setgroups is a comma-separated list
    31. if (gids != null && gids.length > 0) {
    32. StringBuilder sb = new StringBuilder();
    33. sb.append("--setgroups=");
    34. int sz = gids.length;
    35. for (int i = 0; i < sz; i++) {
    36. if (i != 0) {
    37. sb.append(',');
    38. }
    39. sb.append(gids[i]);
    40. }
    41. argsForZygote.add(sb.toString());
    42. }
    43. if (niceName != null) {
    44. argsForZygote.add("--nice-name=" + niceName);
    45. }
    46. if (seInfo != null) {
    47. argsForZygote.add("--seinfo=" + seInfo);
    48. }
    49. if (instructionSet != null) {
    50. argsForZygote.add("--instruction-set=" + instructionSet);
    51. }
    52. if (appDataDir != null) {
    53. argsForZygote.add("--app-data-dir=" + appDataDir);
    54. }
    55. if (invokeWith != null) {
    56. argsForZygote.add("--invoke-with");
    57. argsForZygote.add(invokeWith);
    58. }
    59. if (startChildZygote) {
    60. argsForZygote.add("--start-child-zygote");
    61. }
    62. argsForZygote.add(processClass);
    63. if (extraArgs != null) {
    64. for (String arg : extraArgs) {
    65. argsForZygote.add(arg);
    66. }
    67. }
    68. //关键代码就是这一句
    69. //1,openZygoteSocketIfNeeded会创建与Zygote进程ServerSocket的连接
    70. //2,zygoteSendArgsAndGetResult会将进程启动的参数发送给Zygote进程,fork出新进程后会将进程的pid返回
    71. synchronized(mLock) {
    72. return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
    73. }
    74. }

    openZygoteSocketIfNeeded方法源码

    1. private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
    2. Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
    3. if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
    4. try {
    5. //与Zygote的Socket服务建立连接
    6. primaryZygoteState = ZygoteState.connect(mSocket);
    7. } catch (IOException ioe) {
    8. throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
    9. }
    10. ...
    11. }
    12. ...
    13. if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
    14. try {
    15. //针对一些设备配置了init.zygote32_64.rc或者init.zygote64_32.rc
    16. //需要与另一个Zygote的Socket服务建立连接
    17. secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
    18. } catch (IOException ioe) {
    19. throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
    20. }
    21. ...
    22. }
    23. ...
    24. }

    ZygoteState的connect方法

    1. public static ZygoteState connect(LocalSocketAddress address) throws IOException {
    2. ...
    3. final LocalSocket zygoteSocket = new LocalSocket();
    4. ...
    5. try {
    6. zygoteSocket.connect(address);
    7. ...
    8. } catch (IOException ex) {
    9. try {
    10. zygoteSocket.close();
    11. } catch (IOException ignore) {
    12. }
    13. throw ex;
    14. }
    15. ...
    16. return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
    17. Arrays.asList(abiListString.split(",")));
    18. }

    zygoteSendArgsAndGetResult方法源码

    1. private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
    2. ZygoteState zygoteState, ArrayList args)
    3. throws ZygoteStartFailedEx {
    4. ...
    5. //输出流,参数写入给Zygote
    6. final BufferedWriter writer = zygoteState.writer;
    7. //输入流,从Zygote进程读取fork得到的新进程
    8. final DataInputStream inputStream = zygoteState.inputStream;
    9. writer.write(Integer.toString(args.size()));
    10. writer.newLine();
    11. for (int i = 0; i < sz; i++) {
    12. String arg = args.get(i);
    13. writer.write(arg);
    14. writer.newLine();
    15. }
    16. //App启动参数写入发送
    17. writer.flush();
    18. //fork子进程后读取新的进程
    19. Process.ProcessStartResult result = new Process.ProcessStartResult();
    20. result.pid = inputStream.readInt();
    21. result.usingWrapper = inputStream.readBoolean();
    22. ...
    23. return result;
    24. } catch (IOException ex) {
    25. zygoteState.close();
    26. throw new ZygoteStartFailedEx(ex);
    27. }
    28. }

    四、总结

    Android系统启动流程,前两步我们简单说明下

    1,BootLoader

    BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境;

    2,Kernel

    Kernel指的是操作系统内核Linux初始化及启动;

    3,init进程启动

    硬件初始化、内核初始化及启动之后,init将会启动

    init进程启动先调用了init.cpp中的main()方法,init.cpp的main()方法中有这样一句代码:parser.ParseConfig("/init.rc"),解析init.rc文件,init.rc文件中有zygote start等启动zygote的命令,而且有导入zygote配置的语句import /system/etc/init/hw/init.${ro.zygote}.rc,$(ro.zygote).rc这个引用具体会指向设备具体的配置文件,配置文件按照不同的硬件厂商目前有3种:

    init.zygote32.rcinit.zygote32_64.rcinit.zygote64.rc,这三种文件决定了启动32位还是64位的Zygote服务。不过这几个文件中第一行配置就是service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server这一句,service zygote意思是Zygote进程是以Service服务的方式启动,所以会先启动一个Zygote service服务,/system/bin/app_process64表示回去执行app_process,最终会去执行app_main.cpp中的main方法,并且会将下面的参数传给app_main.cpp的main方法:

    1. /system/bin/app_process64
    2. -Xzygote
    3. /system/bin
    4. --zygote
    5. --start-system-server

    app_main.cpp的main方法,主要干了三件事:

    1. 初始化AndroidRuntime的子类:AppRuntime;
    2. 解析main函数的参数,判断当前是不是Zygote模式;
    3. 根据是否是Zygote模式,调用AndroidRuntime的start方法传入不同的参数

    AndroidRuntime的start方法主要做三件事

    1. 创建、启动了Android虚拟机;
    2. 向虚拟机注册了Android JNI native函数;
    3. 利用JNI技术调用了参数传进来的className对应类的main()函数

            我们上面的分析,传给start方法的className是ZygoteInit,所以最终会调用ZygoteInit的main方法

            我的理解是Zygote进程在上面的init解析init.zygote.rc配置文件后,以service的方式启动了。所以在调用ZygoteInit.java的main方法之前,Zygote进程已经启动了

            ZygoteInit的main方法是通过Zygote进程去调用的,总结一下ZygoteInit.java的main方法做了什么:

    1. ZygoteHooks.startZygoteNoThreadCreation()拦截线程创建;
    2. Os.setpgid(0, 0)将Zygote设置进他自己的进程组;
    3. RuntimeInit.enableDdms()启动DDMS虚拟机监控调试服务;
    4. 解析AndroidRuntime传进来的参数;
    5. zygoteServer.registerServerSocketFromEnv(socketName)创建注册本地LocalServerSocket服务,用来与后面的客户端LocalSocket通信,注意这里并不是Binder通信;
    6. preload预加载,包括预加载系统类、Framwork资源、OpenGL等;
    7. gcAndFinalize在执行fork之前,做一次GC垃圾回收;
    8. Zygote.nativeSecurityInit()在fork之前调用一些安全初始化操作;
    9. Zygote.nativeUnmountStorageOnInit()将整体的的存储目录/storage卸载,取而代之的是挂载临时目录,这个动作和Android的沙箱(隔离存储)有关;
    10. ZygoteHooks.stopZygoteNoThreadCreation()呼应前面的ZygoteHooks.startZygoteNoThreadCreation()方法告诉虚拟机,现在可以创建线程了;
    11.  Runnable r = forkSystemServer fork出system_server进程。如果当前代码执行在system_server进程中,则返回的Runnable不为空,继续执行run方法之后return,这里的run方法就是SystemServer的main方法;如果当前代码执行在Zygote进程中,则Runnable为空,跳过run方法。
    12. caller = zygoteServer.runSelectLoop,当前代码执行在Zygote进程中则代码进入阻塞无线循环,等待并且等待Socket发起的请求,如果有新的进程要创建启动,则Zygote会fork出新的进程。此时,如果代码运行在Zygote进程中,则继续保持阻塞,等待下一次请求;如果代码运行在子进程,则return跳出runSelectLoop方法,返回caller,意味着子进程跳出阻塞。
    13. caller.run();这是main方法的最后一步,只有跳出阻塞的子进程才会走到这一步,这里的run方法与上面的forkSystemServer原理一样,都是利用反射技术,将某一个类的main方法封装到Runnable的run方法中,这里封装的是ActivityThread的main方法。

    五、题外,为什么Zygote进程与其子进程的通信采用的是Socket而非Binder

    (133条消息) android中AMS通知Zygote去fork进程为什么使用socket而不使用binder?_失落夏天的博客-CSDN博客_安卓socke zygote

  • 相关阅读:
    Scala函数式编程
    Linux基础Linux建议收藏
    css格式和样式选择器-学习记录
    LeetCode 1765 Map of Highest Peak (多源点BFS 推荐)
    看板任务管理,让你分分钟提高工作效率!
    DFS与回溯专题:路径总和问题
    基于AHP模型指标权重分析python整理
    人体神经网络的应用领域,神经网络生活中的应用
    lamp环境搭建(kali,docker,ubuntu)
    c++Flood Fill算法之池塘计数,城堡问题,山峰与山谷(acwing)
  • 原文地址:https://blog.csdn.net/qq_29405933/article/details/133637502