【Android体系启动】 Android Zygote 历程启动流程源码解析 ...

打印 上一主题 下一主题

主题 765|帖子 765|积分 2295

【Android体系启动】 Android Zygote 历程启动流程源码解析

媒介


  • 文章源码按照AOSP官网源码platform/superproject/main - Android Code Search代码进行解读;
  • 如有不妥之处,麻烦指出作者进行修正
代码位置

   

  • frameworks/base/cmds/app_process/app_main.cpp
    题外话, 之前找zygote源码的时候,本来想直接通过历程名找这个模块的源码,效果发现根本没有zygote这个名字的下令。通过下令查找到对应的历程目录发现,原来的历程的名字当时编译为app_process,实际文件一般在/system/bin下面。
  源码解析

Init拉起zygote

在system/core/rootdir/init.rc中,
  1. # It is recommended to put unnecessary data/ initialization from post-fs-data
  2. # to start-zygote in device's init.rc to unblock zygote start.
  3. on zygote-start
  4.     wait_for_prop odsign.verification.done 1
  5.     # A/B update verifier that marks a successful boot.
  6.     exec_start update_verifier
  7.     start statsd
  8.     start netd
  9.     start zygote
  10.     start zygote_secondary
复制代码
根据之前init.rc的官方README阐明文档,以及源码解析,均可得知这里start zygote开始了zygote服务;分析见下方。
  1. Start a service running if it is not already running. Note that this is not synchronous, and even if it were, there is no guarantee that the operating system’s scheduler will execute the service sufficiently to guarantee anything about the service’s status. See the exec_start command for a synchronous version of start.
  2. 如果服务尚未运行,则启动该服务。
  3. 请注意,这不是同步的,即使它是同步的,也不能保证操作系统的调度程序会充分执行服务以确保服务的状态。
  4. 参见 exec_start 命令,以获取 start 的同步版本。
复制代码
在init第二阶段的时候,有获取内置下令的逻辑,这部分下令用于解析执行init.rc
  1. // system/core/init/init.cpp
  2.         const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
  3.     Action::set_function_map(&function_map);
复制代码
这里的Map实际对应下面这个Map,而且可以得知start方法调用的是do_start;
do_start先从服务列表内里找到这个服务,然后调用封装好的Service::Start()方法进行调用。
  1. // system/core/init/builtins.cpp
  2. // Builtin-function-map start
  3. const BuiltinFunctionMap& GetBuiltinFunctionMap() {
  4.     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
  5.     // clang-format off
  6.     static const BuiltinFunctionMap builtin_functions = {
  7.         {"bootchart",               {1,     1,    {false,  do_bootchart}}},
  8.         {"chmod",                   {2,     2,    {true,   do_chmod}}},
  9.         {"chown",                   {2,     3,    {true,   do_chown}}},
  10.         {"class_reset",             {1,     1,    {false,  do_class_reset}}},
  11.         {"class_restart",           {1,     2,    {false,  do_class_restart}}},
  12.         {"class_start",             {1,     1,    {false,  do_class_start}}},
  13.         {"class_stop",              {1,     1,    {false,  do_class_stop}}},
  14.         {"copy",                    {2,     2,    {true,   do_copy}}},
  15.         {"copy_per_line",           {2,     2,    {true,   do_copy_per_line}}},
  16.         {"domainname",              {1,     1,    {true,   do_domainname}}},
  17.         {"enable",                  {1,     1,    {false,  do_enable}}},
  18.         {"exec",                    {1,     kMax, {false,  do_exec}}},
  19.         {"exec_background",         {1,     kMax, {false,  do_exec_background}}},
  20.         {"exec_start",              {1,     1,    {false,  do_exec_start}}},
  21.         {"export",                  {2,     2,    {false,  do_export}}},
  22.         {"hostname",                {1,     1,    {true,   do_hostname}}},
  23.         {"ifup",                    {1,     1,    {true,   do_ifup}}},
  24.         {"init_user0",              {0,     0,    {false,  do_init_user0}}},
  25.         {"insmod",                  {1,     kMax, {true,   do_insmod}}},
  26.         {"installkey",              {1,     1,    {false,  do_installkey}}},
  27.         {"interface_restart",       {1,     1,    {false,  do_interface_restart}}},
  28.         {"interface_start",         {1,     1,    {false,  do_interface_start}}},
  29.         {"interface_stop",          {1,     1,    {false,  do_interface_stop}}},
  30.         {"load_exports",            {1,     1,    {false,  do_load_exports}}},
  31.         {"load_persist_props",      {0,     0,    {false,  do_load_persist_props}}},
  32.         {"load_system_props",       {0,     0,    {false,  do_load_system_props}}},
  33.         {"loglevel",                {1,     1,    {false,  do_loglevel}}},
  34.         {"mark_post_data",          {0,     0,    {false,  do_mark_post_data}}},
  35.         {"mkdir",                   {1,     6,    {true,   do_mkdir}}},
  36.         // TODO: Do mount operations in vendor_init.
  37.         // mount_all is currently too complex to run in vendor_init as it queues action triggers,
  38.         // imports rc scripts, etc.  It should be simplified and run in vendor_init context.
  39.         // mount and umount are run in the same context as mount_all for symmetry.
  40.         {"mount_all",               {0,     kMax, {false,  do_mount_all}}},
  41.         {"mount",                   {3,     kMax, {false,  do_mount}}},
  42.         {"perform_apex_config",     {0,     1,    {false,  do_perform_apex_config}}},
  43.         {"umount",                  {1,     1,    {false,  do_umount}}},
  44.         {"umount_all",              {0,     1,    {false,  do_umount_all}}},
  45.         {"update_linker_config",    {0,     0,    {false,  do_update_linker_config}}},
  46.         {"readahead",               {1,     2,    {true,   do_readahead}}},
  47.         {"remount_userdata",        {0,     0,    {false,  do_remount_userdata}}},
  48.         {"restart",                 {1,     2,    {false,  do_restart}}},
  49.         {"restorecon",              {1,     kMax, {true,   do_restorecon}}},
  50.         {"restorecon_recursive",    {1,     kMax, {true,   do_restorecon_recursive}}},
  51.         {"rm",                      {1,     1,    {true,   do_rm}}},
  52.         {"rmdir",                   {1,     1,    {true,   do_rmdir}}},
  53.         {"setprop",                 {2,     2,    {true,   do_setprop}}},
  54.         {"setrlimit",               {3,     3,    {false,  do_setrlimit}}},
  55.         {"start",                   {1,     1,    {false,  do_start}}},
  56.         {"stop",                    {1,     1,    {false,  do_stop}}},
  57.         {"swapon_all",              {0,     1,    {false,  do_swapon_all}}},
  58.         {"enter_default_mount_ns",  {0,     0,    {false,  do_enter_default_mount_ns}}},
  59.         {"symlink",                 {2,     2,    {true,   do_symlink}}},
  60.         {"sysclktz",                {1,     1,    {false,  do_sysclktz}}},
  61.         {"trigger",                 {1,     1,    {false,  do_trigger}}},
  62.         {"verity_update_state",     {0,     0,    {false,  do_verity_update_state}}},
  63.         {"wait",                    {1,     2,    {true,   do_wait}}},
  64.         {"wait_for_prop",           {2,     2,    {false,  do_wait_for_prop}}},
  65.         {"write",                   {2,     2,    {true,   do_write}}},
  66.     };
  67.     // clang-format on
  68.     return builtin_functions;
  69. }
  70. static Result<void> do_start(const BuiltinArguments& args) {
  71.     Service* svc = ServiceList::GetInstance().FindService(args[1]);
  72.     if (!svc) return Error() << "service " << args[1] << " not found";
  73.     errno = 0;
  74.     if (auto result = svc->Start(); !result.ok()) {
  75.         return ErrorIgnoreEnoent() << "Could not start service: " << result.error();
  76.     }
  77.     return {};
  78. }
复制代码
Service::Start()比力冗长,省略了部分代码;其实质是通过判断设置值决定是调用 fork() 照旧 clone() 来创建子历程或克隆历程。
  1. Result<void> Service::Start() {
  2.    
  3.     // ...
  4.    
  5.     pid_t pid = -1;
  6.     if (namespaces_.flags) {
  7.         pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr);
  8.     } else {
  9.         pid = fork();
  10.     }
  11.     if (pid == 0) {
  12.         umask(077);
  13.         cgroups_activated.CloseWriteFd();
  14.         setsid_finished.CloseReadFd();
  15.         RunService(descriptors, std::move(cgroups_activated), std::move(setsid_finished));
  16.         _exit(127);
  17.     } else {
  18.         cgroups_activated.CloseReadFd();
  19.         setsid_finished.CloseWriteFd();
  20.     }
  21.     if (pid < 0) {
  22.         pid_ = 0;
  23.         return ErrnoError() << "Failed to fork";
  24.     }
  25.     // ...
  26.     LOG(INFO) << "... started service '" << name_ << "' has pid " << pid_;
  27.     return {};
  28. }
复制代码
然后补充一下,这个是system/core/rootdir/init.zygote32.rc,zygote通过initr.rc拉起时会逐一解析这些下令而且启动。(如果是64位体系,则为init.zygote64.rc)
  1. service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
  2.     class main
  3.     priority -20
  4.     user root
  5.     group root readproc reserved_disk
  6.     socket zygote stream 660 root system
  7.     socket usap_pool_primary stream 660 root system
  8.     onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
  9.     onrestart write /sys/power/state on
  10.     # NOTE: If the wakelock name here is changed, then also
  11.     # update it in SystemSuspend.cpp
  12.     onrestart write /sys/power/wake_lock zygote_kwl
  13.     onrestart restart audioserver
  14.     onrestart restart cameraserver
  15.     onrestart restart media
  16.     onrestart restart media.tuner
  17.     onrestart restart netd
  18.     onrestart restart wificond
  19.     task_profiles ProcessCapacityHigh
  20.     critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
复制代码
Zygote Main

上面已经讲完Init如何拉起zygote了。下面进入zygote模块本身的代码。从历程名查找到该下令为app_process,然后再从bp大概mk源码中找app_process,即可找到这个下令的位置了。
  1. int main(int argc, char* const argv[])
  2. {
  3.    
  4.     // --------- LOG -----------
  5.     if (!LOG_NDEBUG) {
  6.       String8 argv_String;
  7.       for (int i = 0; i < argc; ++i) {
  8.         argv_String.append(""");
  9.         argv_String.append(argv[i]);
  10.         argv_String.append("" ");
  11.       }
  12.       ALOGV("app_process main with argv: %s", argv_String.c_str());
  13.     }
  14.     // ------------ Runtime初始化 ------------
  15.     AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
  16.     // Process command line arguments
  17.     // ignore argv[0]
  18.     argc--;
  19.     argv++;
  20.     // Everything up to '--' or first non '-' arg goes to the vm.
  21.     //
  22.     // The first argument after the VM args is the "parent dir", which
  23.     // is currently unused.
  24.     //
  25.     // After the parent dir, we expect one or more the following internal
  26.     // arguments :
  27.     //
  28.     // --zygote : Start in zygote mode
  29.     // --start-system-server : Start the system server.
  30.     // --application : Start in application (stand alone, non zygote) mode.
  31.     // --nice-name : The nice name for this process.
  32.     //
  33.     // For non zygote starts, these arguments will be followed by
  34.     // the main class name. All remaining arguments are passed to
  35.     // the main method of this class.
  36.     //
  37.     // For zygote starts, all remaining arguments are passed to the zygote.
  38.     // main function.
  39.     //
  40.     // Note that we must copy argument string values since we will rewrite the
  41.     // entire argument block when we apply the nice name to argv0.
  42.     //
  43.     // As an exception to the above rule, anything in "spaced commands"
  44.     // goes to the vm even though it has a space in it.
  45.     const char* spaced_commands[] = { "-cp", "-classpath" };
  46.     // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
  47.     bool known_command = false;
  48.     // ------------ 解析参数
  49.     int i;
  50.     for (i = 0; i < argc; i++) {
  51.         if (known_command == true) {
  52.           runtime.addOption(strdup(argv[i]));
  53.           // The static analyzer gets upset that we don't ever free the above
  54.           // string. Since the allocation is from main, leaking it doesn't seem
  55.           // problematic. NOLINTNEXTLINE
  56.           ALOGV("app_process main add known option '%s'", argv[i]);
  57.           known_command = false;
  58.           continue;
  59.         }
  60.         for (int j = 0;
  61.              j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
  62.              ++j) {
  63.           if (strcmp(argv[i], spaced_commands[j]) == 0) {
  64.             known_command = true;
  65.             ALOGV("app_process main found known command '%s'", argv[i]);
  66.           }
  67.         }
  68.         if (argv[i][0] != '-') {
  69.             break;
  70.         }
  71.         if (argv[i][1] == '-' && argv[i][2] == 0) {
  72.             ++i; // Skip --.
  73.             break;
  74.         }
  75.         runtime.addOption(strdup(argv[i]));
  76.         // The static analyzer gets upset that we don't ever free the above
  77.         // string. Since the allocation is from main, leaking it doesn't seem
  78.         // problematic. NOLINTNEXTLINE
  79.         ALOGV("app_process main add option '%s'", argv[i]);
  80.     }
  81.     // Parse runtime arguments.  Stop at first unrecognized option.
  82.     bool zygote = false;
  83.     bool startSystemServer = false;
  84.     bool application = false;
  85.     String8 niceName;
  86.     String8 className;
  87.     ++i;  // Skip unused "parent dir" argument.
  88.     while (i < argc) {
  89.         const char* arg = argv[i++];
  90.         if (strcmp(arg, "--zygote") == 0) {
  91.             zygote = true;
  92.             niceName = ZYGOTE_NICE_NAME;
  93.         } else if (strcmp(arg, "--start-system-server") == 0) {
  94.             startSystemServer = true;
  95.         } else if (strcmp(arg, "--application") == 0) {
  96.             application = true;
  97.         } else if (strncmp(arg, "--nice-name=", 12) == 0) {
  98.             niceName = (arg + 12);
  99.         } else if (strncmp(arg, "--", 2) != 0) {
  100.             className = arg;
  101.             break;
  102.         } else {
  103.             --i;
  104.             break;
  105.         }
  106.     }
  107.     Vector<String8> args;
  108.     if (!className.empty()) {
  109.         // We're not in zygote mode, the only argument we need to pass
  110.         // to RuntimeInit is the application argument.
  111.         //
  112.         // The Remainder of args get passed to startup class main(). Make
  113.         // copies of them before we overwrite them with the process name.
  114.         args.add(application ? String8("application") : String8("tool"));
  115.         runtime.setClassNameAndArgs(className, argc - i, argv + i);
  116.         if (!LOG_NDEBUG) {
  117.           String8 restOfArgs;
  118.           char* const* argv_new = argv + i;
  119.           int argc_new = argc - i;
  120.           for (int k = 0; k < argc_new; ++k) {
  121.             restOfArgs.append(""");
  122.             restOfArgs.append(argv_new[k]);
  123.             restOfArgs.append("" ");
  124.           }
  125.           ALOGV("Class name = %s, args = %s", className.c_str(), restOfArgs.c_str());
  126.         }
  127.     } else {
  128.         // We're in zygote mode.
  129.         maybeCreateDalvikCache();
  130.         if (startSystemServer) {
  131.             args.add(String8("start-system-server"));
  132.         }
  133.         char prop[PROP_VALUE_MAX];
  134.         if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
  135.             LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
  136.                 ABI_LIST_PROPERTY);
  137.             return 11;
  138.         }
  139.         String8 abiFlag("--abi-list=");
  140.         abiFlag.append(prop);
  141.         args.add(abiFlag);
  142.         // In zygote mode, pass all remaining arguments to the zygote
  143.         // main() method.
  144.         for (; i < argc; ++i) {
  145.             args.add(String8(argv[i]));
  146.         }
  147.     }
  148.     if (!niceName.empty()) {
  149.         runtime.setArgv0(niceName.c_str(), true /* setProcName */);
  150.     }
  151.     // -------------------- runtime start
  152.     if (zygote) {
  153.         runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
  154.     } else if (!className.empty()) {
  155.         runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
  156.     } else {
  157.         fprintf(stderr, "Error: no class name or --zygote supplied.\n");
  158.         app_usage();
  159.         LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
  160.     }
  161. }
复制代码
上面主要干了这几件大事:
Debug Logging:如果 LOG_NDEBUG 为 false,将下令行参数以调试日记的形式输出。
AppRuntime 初始化:创建 AppRuntime 实例,用于处理应用程序的运行时环境。
处理下令行参数


  • 忽略程序名 argv[0]。
  • 将一些特定的下令行参数添加到运行时选项中。
  • 根据 “–” 或非 ‘-’ 开头的参数分隔下令行参数,一部分传递给虚拟机(VM),一部分用于启动类的 main() 方法。
解析运行时参数


  • 根据特定参数设置标志和属性(如 --zygote、--start-system-server、--application、--nice-name=<name>)。
  • 如果遇到 “–” 开头的参数或非 ‘-’ 开头的参数,则制止解析。
预备运行时参数列表


  • 如果存在类名 (className),则将其作为参数传递给 RuntimeInit。
  • 在 zygote 模式下,预备 ABI 列表和其他参数传递给 ZygoteInit。
设置历程名称


  • 如果指定了 --nice-name=<name>,则设置历程名称。
根据模式调用 runtime 的 start() 方法


  • 如果是 zygote 模式,则调用 start() 方法启动 ZygoteInit。
  • 如果存在类名 (className),则调用 start() 方法启动 RuntimeInit。
  • 否则,输出错误信息并退出程序。
总的来说就是,预备AppRuntime,解析参数,设置历程名,调用runtime start()方法。
从上面zygote的rc文件也可以看到,一开始的参数为–start-system-server
  1. service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
复制代码
AppRuntime start()

   frameworks/base/core/jni/AndroidRuntime.cpp
  1. /*
  2. * Start the Android runtime.  This involves starting the virtual machine
  3. * and calling the "static void main(String[] args)" method in the class
  4. * named by "className".
  5. *
  6. * Passes the main function two arguments, the class name and the specified
  7. * options string.
  8. */
  9. void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
  10. {
  11.     // 打印启动信息,包括类名和用户ID
  12.     ALOGD(">>>>>> START %s uid %d <<<<<<\n",
  13.             className != NULL ? className : "(unknown)", getuid());
  14.     // 判断是否是主要的 zygote 进程
  15.     static const String8 startSystemServer("start-system-server");
  16.     bool primary_zygote = false;
  17.     // 检查是否需要打印启动事件
  18.     for (size_t i = 0; i < options.size(); ++i) {
  19.         if (options[i] == startSystemServer) {
  20.             primary_zygote = true;
  21.             const int LOG_BOOT_PROGRESS_START = 3000;
  22.             LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
  23.         }
  24.     }
  25.     // 设置环境变量
  26.     const char* rootDir = getenv("ANDROID_ROOT");
  27.     if (rootDir == NULL) {
  28.         rootDir = "/system";
  29.         if (!hasDir("/system")) {
  30.             LOG_FATAL("No root directory specified, and /system does not exist.");
  31.             return;
  32.         }
  33.         setenv("ANDROID_ROOT", rootDir, 1);
  34.     }
  35.     const char* artRootDir = getenv("ANDROID_ART_ROOT");
  36.     if (artRootDir == NULL) {
  37.         LOG_FATAL("No ART directory specified with ANDROID_ART_ROOT environment variable.");
  38.         return;
  39.     }
  40.     const char* i18nRootDir = getenv("ANDROID_I18N_ROOT");
  41.     if (i18nRootDir == NULL) {
  42.         LOG_FATAL("No runtime directory specified with ANDROID_I18N_ROOT environment variable.");
  43.         return;
  44.     }
  45.     const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT");
  46.     if (tzdataRootDir == NULL) {
  47.         LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable.");
  48.         return;
  49.     }
  50.     // 初始化 JNI 调用
  51.     JniInvocation jni_invocation;
  52.     jni_invocation.Init(NULL);
  53.     JNIEnv* env;
  54.     // 启动虚拟机
  55.     if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
  56.         return;
  57.     }
  58.     onVmCreated(env);
  59.     // 注册 Android 原生方法
  60.     if (startReg(env) < 0) {
  61.         ALOGE("Unable to register all android natives\n");
  62.         return;
  63.     }
  64.     // 创建 String 数组,用于传递给 Java 的 main 方法
  65.     jclass stringClass;
  66.     jobjectArray strArray;
  67.     jstring classNameStr;
  68.     stringClass = env->FindClass("java/lang/String");
  69.     assert(stringClass != NULL);
  70.     strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
  71.     assert(strArray != NULL);
  72.     classNameStr = env->NewStringUTF(className);
  73.     assert(classNameStr != NULL);
  74.     env->SetObjectArrayElement(strArray, 0, classNameStr);
  75.     for (size_t i = 0; i < options.size(); ++i) {
  76.         jstring optionsStr = env->NewStringUTF(options.itemAt(i).c_str());
  77.         assert(optionsStr != NULL);
  78.         env->SetObjectArrayElement(strArray, i + 1, optionsStr);
  79.     }
  80.     // 调用 Java 的 main 方法启动应用程序
  81.     char* slashClassName = toSlashClassName(className != NULL ? className : "");
  82.     jclass startClass = env->FindClass(slashClassName);
  83.     if (startClass == NULL) {
  84.         ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
  85.         /* keep going */
  86.     } else {
  87.         jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
  88.             "([Ljava/lang/String;)V");
  89.         if (startMeth == NULL) {
  90.             ALOGE("JavaVM unable to find main() in '%s'\n", className);
  91.             /* keep going */
  92.         } else {
  93.             env->CallStaticVoidMethod(startClass, startMeth, strArray);
  94.         }
  95.     }
  96.     free(slashClassName);
  97.     ALOGD("Shutting down VM\n");
  98.     // 分离主线程
  99.     if (mJavaVM->DetachCurrentThread() != JNI_OK)
  100.         ALOGW("Warning: unable to detach main thread\n");
  101.     // 销毁虚拟机
  102.     if (mJavaVM->DestroyJavaVM() != 0)
  103.         ALOGW("Warning: VM did not shut down cleanly\n");
  104. }
复制代码
这里的主要职责:

  • 初始化:打印启动信息、判断是否为systemserver历程、设置环境变量等;
  • 初始化 JNI 调用和启动虚拟机

    • 使用 JniInvocation 初始化 JNI 调用;
    • 调用 startVm 方法启动虚拟机,并在虚拟机创建后调用 onVmCreated;
    • 调用 startReg 方法注册 Android 原生方法,内里遍历调用gRegJNI数组,数组是一组 JNI 函数的函数指针;

  • 创建并传递参数给 Java 的 main 方法

    • 创建 String 类型的数组 strArray,用于传递给 Java 的 main 方法;
    • 将类名和选项字符串转换为 Java 的 String 对象,并设置到 strArray 中;

  • 调用 Java 的 main 方法

    • 根据类名查找 startClass,并获取 main 方法的 startMeth;
    • 使用 env->CallStaticVoidMethod 调用 Java 的 main 方法启动应用程序;

  • 关闭虚拟机

    • 执行完 main 方法后,分离主线程并销毁虚拟机。

这里总体就是初始化打印、环境变量、参数等,然后启动虚拟机-传递参数-调用main方法-关闭虚拟机。
不过通过观察这里会发现:

  • 每次上层的历程启动会调用这个start方法,而start方法开启且仅开启了一个虚拟机,那就是zygote基础上每一个历程,都会对应一个本身的虚拟环境;
  • 每个上层应用需要渐渐调到体系层,都通过zygote这里JNI方式进行了调用。
ZygoteInit.Main()

通过上面传下来的参数,“com.android.internal.os.ZygoteInit”,可以得知Java层的包名,以此找到Java代码。
   frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
  1. /**
  2. * This is the entry point for a Zygote process.  It creates the Zygote server, loads resources,
  3. * and handles other tasks related to preparing the process for forking into applications.
  4. *
  5. * This process is started with a nice value of -20 (highest priority).  All paths that flow
  6. * into new processes are required to either set the priority to the default value or terminate
  7. * before executing any non-system code.  The native side of this occurs in SpecializeCommon,
  8. * while the Java Language priority is changed in ZygoteInit.handleSystemServerProcess,
  9. * ZygoteConnection.handleChildProc, and Zygote.childMain.
  10. *
  11. * @param argv  Command line arguments used to specify the Zygote's configuration.
  12. */
  13. @UnsupportedAppUsage
  14. public static void main(String[] argv) {
  15.     ZygoteServer zygoteServer = null;
  16.     // 标记 Zygote 启动 确保在此后创建线程会抛出错误。
  17.     // Mark zygote start. This ensures that thread creation will throw
  18.     // an error.
  19.     ZygoteHooks.startZygoteNoThreadCreation();
  20.     // 调用 Os.setpgid(0, 0) 将 Zygote 放入自己的进程组。
  21.     // Zygote goes into its own process group.
  22.     try {
  23.         Os.setpgid(0, 0);
  24.     } catch (ErrnoException ex) {
  25.         throw new RuntimeException("Failed to setpgid(0,0)", ex);
  26.     }
  27.     Runnable caller;
  28.     try {
  29.         // 解析命令行参数 argv,包括是否启动系统服务器 (start-system-server)、是否启用延迟预加载 (--enable-lazy-preload)、ABI 列表等。
  30.         // Store now for StatsLogging later.
  31.         final long startTime = SystemClock.elapsedRealtime();
  32.         final boolean isRuntimeRestarted = "1".equals(
  33.                 SystemProperties.get("sys.boot_completed"));
  34.         String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
  35.         TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
  36.                 Trace.TRACE_TAG_DALVIK);
  37.         bootTimingsTraceLog.traceBegin("ZygoteInit");
  38.         RuntimeInit.preForkInit();
  39.         boolean startSystemServer = false;
  40.         String zygoteSocketName = "zygote";
  41.         String abiList = null;
  42.         boolean enableLazyPreload = false;
  43.         for (int i = 1; i < argv.length; i++) {
  44.             if ("start-system-server".equals(argv[i])) {
  45.                 startSystemServer = true;
  46.             } else if ("--enable-lazy-preload".equals(argv[i])) {
  47.                 enableLazyPreload = true;
  48.             } else if (argv[i].startsWith(ABI_LIST_ARG)) {
  49.                 abiList = argv[i].substring(ABI_LIST_ARG.length());
  50.             } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
  51.                 zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
  52.             } else {
  53.                 throw new RuntimeException("Unknown command line argument: " + argv[i]);
  54.             }
  55.         }
  56.         final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
  57.         if (!isRuntimeRestarted) {
  58.             if (isPrimaryZygote) {
  59.                 FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
  60.                         BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START,
  61.                         startTime);
  62.             } else if (zygoteSocketName.equals(Zygote.SECONDARY_SOCKET_NAME)) {
  63.                 FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
  64.                         BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START,
  65.                         startTime);
  66.             }
  67.         }
  68.         if (abiList == null) {
  69.             throw new RuntimeException("No ABI list supplied.");
  70.         }
  71.         // 记录启动时间、预加载
  72.         // In some configurations, we avoid preloading resources and classes eagerly.
  73.         // In such cases, we will preload things prior to our first fork.
  74.         // 根据配置,预加载资源和类。如果未启用延迟预加载,则在第一次fork()之前预加载。
  75.         if (!enableLazyPreload) {
  76.             bootTimingsTraceLog.traceBegin("ZygotePreload");
  77.             EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
  78.                     SystemClock.uptimeMillis());
  79.             preload(bootTimingsTraceLog);
  80.             EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
  81.                     SystemClock.uptimeMillis());
  82.             bootTimingsTraceLog.traceEnd(); // ZygotePreload
  83.         }
  84.         // Do an initial gc to clean up after startup
  85.         bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
  86.         gcAndFinalize();
  87.         bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
  88.         bootTimingsTraceLog.traceEnd(); // ZygoteInit
  89.         // 初始化native状态
  90.         Zygote.initNativeState(isPrimaryZygote);
  91.         // 停止 Zygote 无线程创建标记
  92.         ZygoteHooks.stopZygoteNoThreadCreation();
  93.         // 创建 ZygoteServer 实例。
  94.         zygoteServer = new ZygoteServer(isPrimaryZygote);
  95.         
  96.         // 如果需要启动SystemServer,则调用 forkSystemServer 创建SystemServer的子进程,并在子进程中运行。
  97.         if (startSystemServer) {
  98.             Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
  99.             // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
  100.             // child (system_server) process.
  101.             if (r != null) {
  102.                 r.run();
  103.                 return;
  104.             }
  105.         }
  106.         
  107.         // 接受命令套接字连接
  108.         Log.i(TAG, "Accepting command socket connections");
  109.         // select 循环在 fork 后在子进程中提前返回,并在 zygote 中永远循环
  110.         // The select loop returns early in the child process after a fork and
  111.         // loops forever in the zygote.
  112.         caller = zygoteServer.runSelectLoop(abiList);
  113.     } catch (Throwable ex) {
  114.         Log.e(TAG, "System zygote died with fatal exception", ex);
  115.         throw ex;
  116.     } finally {
  117.         // 异常处理和资源清理 在最后关闭 zygoteServer 的服务器套接字。
  118.         if (zygoteServer != null) {
  119.             zygoteServer.closeServerSocket();
  120.         }
  121.     }
  122.     // We're in the child process and have exited the select loop. Proceed to execute the
  123.     // command.
  124.     // 执行命令 如果 caller 不为 null,则在子进程中执行命令。
  125.     if (caller != null) {
  126.         caller.run();
  127.     }
  128. }
复制代码
  补充一下注释翻译(这里告诉了修改历程优先级的native层和java层的地方):
  这是 Zygote 历程的入口点。它创建 Zygote 服务器、加载资源并处理与预备历程以分叉到应用程序相关的其他任务。
  此历程以 -20(最高优先级)的 nice 值启动。所有流入新历程的路径都必须将优先级设置为默认值或在执行任何非体系代码之前终止。native方面发生在 SpecializeCommon 中, 而 Java 语言优先级在 ZygoteInit.handleSystemServerProcess、ZygoteConnection.handleChildProc 和 Zygote.childMain 中更改。
  这里主要的职责有:

  • 初始化:标志zygote无线程启动、设置历程组、处理下令行参数;
           int setpgid(pid_t pid, pid_t pgid) 可以将一个历程加入一个现有的历程组,大概创建一个新的历程组且当前调用历程作为历程组组长(setpgid(0, 0))。pid 参数只能是 0 (当前历程)、当前历程 id、子历程 id(孙子历程不行)。
  • 记录启动时间,并根据是否为主要 Zygote 历程写入启动时间事件;
  • 预加载,根据设置在第一次fork前预加载;
  • 初始化native层状态;
  • 制止标志zygote无线程启动;
  • 创建 ZygoteServer,而且启动systemserver;
  • zygoteServer.runSelectLoop(abiList),建立systemserver和zygote的socket通信;
  • 关闭zygoteserver的socket;
然后挑一些告急的职责细讲一下:
ZygoteInit PreLoad

这里预加载的主要是一些体系类、资源、共享库so、文字、webview等等;
  1.     static void preload(TimingsTraceLog bootTimingsTraceLog) {
  2.         Log.d(TAG, "begin preload");
  3.         bootTimingsTraceLog.traceBegin("BeginPreload");
  4.         beginPreload();
  5.         bootTimingsTraceLog.traceEnd(); // BeginPreload
  6.         bootTimingsTraceLog.traceBegin("PreloadClasses");
  7.         preloadClasses();
  8.         bootTimingsTraceLog.traceEnd(); // PreloadClasses
  9.         bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
  10.         cacheNonBootClasspathClassLoaders();
  11.         bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
  12.         bootTimingsTraceLog.traceBegin("PreloadResources");
  13.         Resources.preloadResources();
  14.         bootTimingsTraceLog.traceEnd(); // PreloadResources
  15.         Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
  16.         nativePreloadAppProcessHALs();
  17.         Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
  18.         Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
  19.         maybePreloadGraphicsDriver();
  20.         Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
  21.         preloadSharedLibraries();
  22.         preloadTextResources();
  23.         // Ask the WebViewFactory to do any initialization that must run in the zygote process,
  24.         // for memory sharing purposes.
  25.         WebViewFactory.prepareWebViewInZygote();
  26.         endPreload();
  27.         warmUpJcaProviders();
  28.         Log.d(TAG, "end preload");
  29.         sPreloadComplete = true;
  30.     }
复制代码
而且preload也有个条件条件 enableLazyPreload = true --> 带有–enable-lazy-preload,只有system/core/rootdir/init.zygote64_32.rc才有这个参数 --> 只有在32和64位均需要启动的时候,才需要preload;
   

  • init.zygote32.rc:zygote 历程对应的执行程序是 app_process (纯 32bit 模式)
  • init.zygote64.rc:zygote 历程对应的执行程序是 app_process64 (纯 64bit 模式)
  • init.zygote32_64.rc:启动两个 zygote 历程 (名为 zygote 和 zygote_secondary),对应的执行程序分别是 app_process32 (主模式)、app_process64
  • init.zygote64_32.rc:启动两个 zygote 历程 (名为 zygote 和 zygote_secondary),对应的执行程序分别是 app_process64 (主模式)、app_process32
  ZygoteInit forkSystemServer

  1.     /**
  2.      * Prepare the arguments and forks for the system server process.
  3.      *
  4.      * @return A {@code Runnable} that provides an entrypoint into system_server code in the child
  5.      * process; {@code null} in the parent.
  6.      */
  7.     private static Runnable forkSystemServer(String abiList, String socketName,
  8.             ZygoteServer zygoteServer) {
  9.         long capabilities = posixCapabilitiesAsBits(
  10.                 OsConstants.CAP_IPC_LOCK,
  11.                 OsConstants.CAP_KILL,
  12.                 OsConstants.CAP_NET_ADMIN,
  13.                 OsConstants.CAP_NET_BIND_SERVICE,
  14.                 OsConstants.CAP_NET_BROADCAST,
  15.                 OsConstants.CAP_NET_RAW,
  16.                 OsConstants.CAP_SYS_MODULE,
  17.                 OsConstants.CAP_SYS_NICE,
  18.                 OsConstants.CAP_SYS_PTRACE,
  19.                 OsConstants.CAP_SYS_TIME,
  20.                 OsConstants.CAP_SYS_TTY_CONFIG,
  21.                 OsConstants.CAP_WAKE_ALARM,
  22.                 OsConstants.CAP_BLOCK_SUSPEND
  23.         );
  24.         /* Containers run without some capabilities, so drop any caps that are not available. */
  25.         StructCapUserHeader header = new StructCapUserHeader(
  26.                 OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
  27.         StructCapUserData[] data;
  28.         try {
  29.             data = Os.capget(header);
  30.         } catch (ErrnoException ex) {
  31.             throw new RuntimeException("Failed to capget()", ex);
  32.         }
  33.         capabilities &= Integer.toUnsignedLong(data[0].effective) |
  34.                 (Integer.toUnsignedLong(data[1].effective) << 32);
  35.         /* Hardcoded command line to start the system server */
  36.         String[] args = {
  37.                 "--setuid=1000",
  38.                 "--setgid=1000",
  39.                 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
  40.                         + "1024,1032,1065,3001,3002,3003,3005,3006,3007,3009,3010,3011,3012",
  41.                 "--capabilities=" + capabilities + "," + capabilities,
  42.                 "--nice-name=system_server",
  43.                 "--runtime-args",
  44.                 "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
  45.                 "com.android.server.SystemServer",
  46.         };
  47.         ZygoteArguments parsedArgs;
  48.         int pid;
  49.         try {
  50.             ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
  51.             try {
  52.                 parsedArgs = ZygoteArguments.getInstance(commandBuffer);
  53.             } catch (EOFException e) {
  54.                 throw new AssertionError("Unexpected argument error for forking system server", e);
  55.             }
  56.             commandBuffer.close();
  57.             Zygote.applyDebuggerSystemProperty(parsedArgs);
  58.             Zygote.applyInvokeWithSystemProperty(parsedArgs);
  59.             if (Zygote.nativeSupportsMemoryTagging()) {
  60.                 String mode = SystemProperties.get("persist.arm64.memtag.system_server", "");
  61.                 if (mode.isEmpty()) {
  62.                   /* The system server has ASYNC MTE by default, in order to allow
  63.                    * system services to specify their own MTE level later, as you
  64.                    * can't re-enable MTE once it's disabled. */
  65.                   mode = SystemProperties.get("persist.arm64.memtag.default", "async");
  66.                 }
  67.                 if (mode.equals("async")) {
  68.                     parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
  69.                 } else if (mode.equals("sync")) {
  70.                     parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_SYNC;
  71.                 } else if (!mode.equals("off")) {
  72.                     /* When we have an invalid memory tag level, keep the current level. */
  73.                     parsedArgs.mRuntimeFlags |= Zygote.nativeCurrentTaggingLevel();
  74.                     Slog.e(TAG, "Unknown memory tag level for the system server: "" + mode + """);
  75.                 }
  76.             } else if (Zygote.nativeSupportsTaggedPointers()) {
  77.                 /* Enable pointer tagging in the system server. Hardware support for this is present
  78.                  * in all ARMv8 CPUs. */
  79.                 parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI;
  80.             }
  81.             /* Enable gwp-asan on the system server with a small probability. This is the same
  82.              * policy as applied to native processes and system apps. */
  83.             parsedArgs.mRuntimeFlags |= Zygote.GWP_ASAN_LEVEL_LOTTERY;
  84.             if (shouldProfileSystemServer()) {
  85.                 parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
  86.             }
  87.             /* Request to fork the system server process */
  88.             pid = Zygote.forkSystemServer(
  89.                     parsedArgs.mUid, parsedArgs.mGid,
  90.                     parsedArgs.mGids,
  91.                     parsedArgs.mRuntimeFlags,
  92.                     null,
  93.                     parsedArgs.mPermittedCapabilities,
  94.                     parsedArgs.mEffectiveCapabilities);
  95.         } catch (IllegalArgumentException ex) {
  96.             throw new RuntimeException(ex);
  97.         }
  98.         /* For child process */
  99.         if (pid == 0) {
  100.             if (hasSecondZygote(abiList)) {
  101.                 waitForSecondaryZygote(socketName);
  102.             }
  103.             zygoteServer.closeServerSocket();
  104.             return handleSystemServerProcess(parsedArgs);
  105.         }
  106.         return null;
  107.     }
复制代码
内里的整体逻辑照旧很简单的 , 就是整理出参数,然后调用zygote的方法;主要调用了applyDebuggerSystemProperty、applyInvokeWithSystemProperty、forkSystemServer方法,

  • applyDebuggerSystemProperty:
           Applies debugger system properties to the zygote arguments.
    For eng builds all apps are debuggable with JDWP and ptrace.
    On userdebug builds if persist.debug.dalvik.vm.jdwp.enabled is 1 all apps are debuggable with JDWP and ptrace. Otherwise, the debugger state is specified via the “–enable-jdwp” flag in the
    spawn request.
    On userdebug builds if persist.debug.ptrace.enabled is 1 all apps are debuggable with ptrace.
        将调试器体系属性应用于 zygote 参数。
    对于 eng 版本,所有应用均可使用 JDWP 和 ptrace 进行调试。
    在 userdebug 版本中,如果 persist.debug.dalvik.vm.jdwp.enabled 为 1,则所有应用均可使用 JDWP 和 ptrace 进行调试。否则,调试器状态通过 spawn 请求中的“–enable-jdwp”标志指定。
    在 userdebug 版本中,如果 persist.debug.ptrace.enabled 为 1,则所有应用均可使用 ptrace 进行调试。
  • applyInvokeWithSystemProperty:将invoke-with体系属性应用于zygote参数
  • forkSystemServer 最终会调用到native层,fork出子历程;
  • closeServerSocket 关闭socket通信;
  • handleSystemServerProcess:完成新建子历程后剩余工作;
Q&A

为什么zygote要用socket,而不是用binder?

Zygote通信为什么用Socket,而不是Binder? - 简书 (jianshu.com)
参考


  • platform/superproject/main - Android Code Search
  • Android体系启动(二)- Zygote篇 - 掘金 (juejin.cn)
  • Android O体系启动流程–zygote篇 - Vane的博客 | Vane’s Blog (vanelst.site)

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

大连密封材料

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表