Android 系统启动流程

依旧是带着问题再去学习

首先,Android是怎么启动的?

Android服务是怎么启动的?

Android线程是怎么切换的?

Android ApplicationThread是怎么创建的?

那么接下来开始分析Android的启动流程 还是一步一图

先画一张流程图描述个大概

这里有个小知识点,线程和进程在Linux内核空间是一样的,只是因为共享内存,所以才有线程和进程区分,连调用方法都一样,只是传进去的参数线程会传入的是父进程的用户空间

言归正传,继续看Android的启动流程

首先 init进程如何启动的?

init 是在 system/bin/init 这个文件来启动的,那么这个文件是在哪执行的呢?

是这一层进行执行的 是一个叫 kenel_init 的方法,启动init进程

cpp 复制代码
1497static int __ref kernel_init(void *unused)
1498{
1499        int ret;
1500
1501        /*
1502         * Wait until kthreadd is all set-up.
1503         */
1504        wait_for_completion(&kthreadd_done);
1505
1506        kernel_init_freeable();
1507        /* need to finish all async __init code before freeing the memory */
1508        async_synchronize_full();
1509        kprobe_free_init_mem();
1510        ftrace_free_init_mem();
1511        kgdb_free_init_mem();
1512        exit_boot_config();
1513        free_initmem();
1514        mark_readonly();
1515
1516        /*
1517         * Kernel mappings are now finalized - update the userspace page-table
1518         * to finalize PTI.
1519         */
1520        pti_finalize();
1521
1522        system_state = SYSTEM_RUNNING;
1523        numa_default_policy();
1524
1525        rcu_end_inkernel_boot();
1526
1527        do_sysctl_args();
1528
1529        if (ramdisk_execute_command) {
1530                ret = run_init_process(ramdisk_execute_command);
1531                if (!ret)
1532                        return 0;
1533                pr_err("Failed to execute %s (error %d)\n",
1534                       ramdisk_execute_command, ret);
1535        }
1536
1537        /*
1538         * We try each of these until one succeeds.
1539         *
1540         * The Bourne shell can be used instead of init if we are
1541         * trying to recover a really broken machine.
1542         */
1543        if (execute_command) {
1544                ret = run_init_process(execute_command);
1545                if (!ret)
1546                        return 0;
1547                panic("Requested init %s failed (error %d).",
1548                      execute_command, ret);
1549        }
1550
1551        if (CONFIG_DEFAULT_INIT[0] != '\0') {
1552                ret = run_init_process(CONFIG_DEFAULT_INIT);
1553                if (ret)
1554                        pr_err("Default init %s failed (error %d)\n",
1555                               CONFIG_DEFAULT_INIT, ret);
1556                else
1557                        return 0;
1558        }
1559        
1560        if (!try_to_run_init_process("/sbin/init") ||
1561            !try_to_run_init_process("/etc/init") ||
                这个地方会启动Android的,init进程
1562            !try_to_run_init_process("/bin/init") ||
1563            !try_to_run_init_process("/bin/sh"))
1564                return 0;
1565
1566        panic("No working init found.  Try passing init= option to kernel. "
1567              "See Linux Documentation/admin-guide/init.rst for guidance.");
1568}

那么这个 try to run init process 是什么呢?

cpp 复制代码
1424static int run_init_process(const char *init_filename)
1425{
1426        const char *const *p;
1427
1428        argv_init[0] = init_filename;
1429        pr_info("Run %s as init process\n", init_filename);
1430        pr_debug("  with arguments:\n");
1431        for (p = argv_init; *p; p++)
1432                pr_debug("    %s\n", *p);
1433        pr_debug("  with environment:\n");
1434        for (p = envp_init; *p; p++)
1435                pr_debug("    %s\n", *p);
1436        return kernel_execve(init_filename, argv_init, envp_init);
1437}
1438
1439static int try_to_run_init_process(const char *init_filename)
1440{
1441        int ret;
1442
1443        ret = run_init_process(init_filename);
1444
1445        if (ret && ret != -ENOENT) {
1446                pr_err("Starting init: %s exists but couldn't execute it (error %d)\n",
1447                       init_filename, ret);
1448        }
1449
1450        return ret;
1451}

最终调用到 kernel_execve

那么这个init文件是谁生成的?调用init会调用到哪里?

实际上init文件是 Android.bp生成,最终调用到 main.cpp上

cpp 复制代码
cc_binary {
//省略

srcs: ["main.cpp"]

}

时序图如下

main.cpp是Android系统的头文件,那么接下来我们接着看main.cpp

cpp 复制代码
51  int main(int argc, char** argv) {
52  #if __has_feature(address_sanitizer)
53      __asan_set_error_report_callback(AsanReportCallback);
54  #endif
55  
56      if (!strcmp(basename(argv[0]), "ueventd")) {
57          return ueventd_main(argc, argv);
58      }
59  
60      if (argc > 1) {
61          if (!strcmp(argv[1], "subcontext")) {
62              android::base::InitLogging(argv, &android::base::KernelLogger);
63              const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
64  
65              return SubcontextMain(argc, argv, &function_map);
66          }
67  
68          if (!strcmp(argv[1], "selinux_setup")) {
69              return SetupSelinux(argv);
70          }
71  
72          if (!strcmp(argv[1], "second_stage")) {
73              return SecondStageMain(argc, argv);
74          }
75      }
76  
77      return FirstStageMain(argc, argv);
78  }

这是main.cpp的main函数,这个main方法会执行多次,Android系统最初的函数 先看 First

cpp 复制代码
int FirstStageMain(int argc, char** argv) {
175      if (REBOOT_BOOTLOADER_ON_PANIC) {
             检查,如果init挂掉了会重新启动
176          InstallRebootSignalHandlers();
177      }
178  
179      boot_clock::time_point start_time = boot_clock::now();
180  
181      std::vector<std::pair<std::string, int>> errors;
182  #define CHECKCALL(x) \
183      if ((x) != 0) errors.emplace_back(#x " failed", errno);
184  
185      // Clear the umask.
186      umask(0);
187  
188      CHECKCALL(clearenv());
189      CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));
190      // Get the basic filesystem setup we need put together in the initramdisk
191      // on / and then we'll let the rc file figure out the rest.
         挂载 创建一些文件
192      CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
193      CHECKCALL(mkdir("/dev/pts", 0755));
194      CHECKCALL(mkdir("/dev/socket", 0755));
195      省略
332      CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3)));
         输入输出
         SetStdioToDevNull(argv);
         以及启动 selinuxup
         const char* args[] = {path, "selinux_setup", nullptr};
         execv(path, const_cast<char**>(args));
333      return 1;
334  }

First 主要作用是挂载,初始化重要文件,重定向输入输出,log,以及启动 selinux_setup

execv函数会再走一次这个main函数

然后再次进入,启动 Second

SetupSelinux 是一个最小权限原则

cpp 复制代码
672  int SetupSelinux(char** argv) {
673      SetStdioToDevNull(argv);
674      InitKernelLogging(argv);

697      省略
698      const char* path = "/system/bin/init";
         打开 second_stage 
699      const char* args[] = {path, "second_stage", nullptr};
700      execv(path, const_cast<char**>(args));
701  
702      // execv() only returns if an error happened, in which case we
703      // panic and never return from this function.
704      PLOG(FATAL) << "execv(\"" << path << "\") failed";
705  
706      return 1;
707  }

selinux_setup 是一个安全策略 然后进入SecondStageMain

cpp 复制代码
if (!strcmp(argv[1], "second_stage")) {
73              return SecondStageMain(argc, argv);
74          }
cpp 复制代码
 int SecondStageMain(int argc, char** argv) {
    
    省略
    初始化一些属性域
    PropertyInit();
    
    处理子进程终止信号,僵尸进程
    InstallSignalFdHandler(&epoll);
    InstallInitNotifier(&epoll);
    StartPropertyService(&property_fd);
    
    匹配命令和函数之间的关系
    const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
    解析init.rc
    LoadBootScripts(am, sm);

}

然后看下如何解析init.rc这个工作吧

cpp 复制代码
272  static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {        
        创建解析器
273     std::string bootscript = GetProperty("ro.boot.init_rc", "");
276      if (bootscript.empty()) {
                解析init.rc
277          parser.ParseConfig("/system/etc/init/hw/init.rc");
278          if (!parser.ParseConfig("/system/etc/init")) {
279              late_import_paths.emplace_back("/system/etc/init");
280          }
281          // late_import is available only in Q and earlier release. As we don't
282          // have system_ext in those versions, skip late_import for system_ext.
283          parser.ParseConfig("/system_ext/etc/init");
284          if (!parser.ParseConfig("/product/etc/init")) {
285              late_import_paths.emplace_back("/product/etc/init");
286          }
287          if (!parser.ParseConfig("/odm/etc/init")) {
288              late_import_paths.emplace_back("/odm/etc/init");
289          }
290          if (!parser.ParseConfig("/vendor/etc/init")) {
291              late_import_paths.emplace_back("/vendor/etc/init");
292          }
293      } else {
294          parser.ParseConfig(bootscript);
296  }
297  

先看下这个CreateParser方法 创建三种解析器,对rc语法进行解析

cpp 复制代码
251  Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
252      Parser parser;
253  
254      parser.AddSectionParser("service", std::make_unique<ServiceParser>(
255                                                 &service_list, GetSubcontext(), std::nullopt));
256      parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, GetSubcontext()));
257      parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
258  
259      return parser;
260  }

解析出二进制文件这个地方省略,有兴趣可以后面研究

解析出init.rc后会进入一个while循环 还是这个 SecondStageMain 方法,接下来进入while循环当中

操作系统到最终还是一个死循环

cpp 复制代码
int SecondStageMain(int argc, char** argv) {

842      进入while
843      while (true) {
844          // By default, sleep until something happens.
845          auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
846  
847          auto shutdown_command = shutdown_state.CheckShutdown();
848          if (shutdown_command) {
849              HandlePowerctlMessage(*shutdown_command);
850          }
851  
852          if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
853              am.ExecuteOneCommand();
854          }
855          if (!IsShuttingDown()) {
856              auto next_process_action_time = HandleProcessActions();
857  
858              // If there's a process that needs restarting, wake up in time for that.
859              if (next_process_action_time) {
860                  epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
861                          *next_process_action_time - boot_clock::now());
862                  if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
863              }
864          }
865  
866          if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
867              // If there's more work to do, wake up again immediately.
868              if (am.HasMoreCommands()) epoll_timeout = 0ms;
869          }
870          这里有个Wait 会在这里循环等待
871          auto pending_functions = epoll.Wait(epoll_timeout);
872          if (!pending_functions.ok()) {
873              LOG(ERROR) << pending_functions.error();
874          } else if (!pending_functions->empty()) {
875              // We always reap children before responding to the other pending functions. This is to
876              // prevent a race where other daemons see that a service has exited and ask init to
877              // start it again via ctl.start before init has reaped it.
878              ReapAnyOutstandingChildren();
879              for (const auto& function : *pending_functions) {
880                  (*function)();
881              }
882          }
883          if (!IsShuttingDown()) {
884              HandleControlMessages();
885              SetUsbController();
886          }
887      }
888  
889      return 0;
890  }

一张时序图,接下来会进入init.rc当中

init处理几个重要事情

1.挂载文件

2.设置selinux 安全策略

3.设置属性服务 注册到epoll中

4.解析init.rc

5.循环处理脚本

6.循环等待

画张时序图

接下来继续分析,init.rc 就会启动zygote zygto 是第一个进入到java层,从zygto 开始才会开启java层

cpp 复制代码
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
13 
14 # Cgroups are mounted right before early-init using list from /etc/cgroups.json
15 on early-init
16     # Disable sysrq from keyboard
17     write /proc/sys/kernel/sysrq 0
18 
19     # Android doesn't need kernel module autoloading, and it causes SELinux
20     # denials.  So disable it by setting modprobe to the empty string.  Note: to
21     # explicitly set a sysctl to an empty string, a trailing newline is needed.
22     write /proc/sys/kernel/modprobe \n
    省略
   # Now we can start zygote for devices with file based encryption
443     trigger zygote-start
    
    当执行到这的时候就会启动 zygote
812 on zygote-start && property:ro.crypto.state=unencrypted
813     # A/B update verifier that marks a successful boot.
814     exec_start update_verifier_nonencrypted
815     start statsd
816     start netd
817     start zygote
818     start zygote_secondary

可以看到init.rc导入了这个 zygote的文件

然后实际上启动的是 init.zygote.32.rc / init.zygote.64.rc 文件

具体启动哪个,是要分系统32/64 位系统

主要作用是启动 zygote的main方法,还有 如果被关闭会重启

接下来启动app_main.cpp 的main方法,现在仍然是main方法

Android的运行环境就是zygto启动的

cpp 复制代码
172  
173  int main(int argc, char* const argv[])
174  {
175      if (!LOG_NDEBUG) {
176        String8 argv_String;
177        for (int i = 0; i < argc; ++i) {
178          argv_String.append("\"");
179          argv_String.append(argv[i]);
180          argv_String.append("\" ");
181        }
182        ALOGV("app_process main with argv: %s", argv_String.string());
183      }
184      
         Android 时运行环境
185      AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
186      // Process command line arguments
187      // ignore argv[0]
188      argc--;
189      argv++;
190  
216      const char* spaced_commands[] = { "-cp", "-classpath" };
218      bool known_command = false;
219  
220      int i;
         解析一堆东西,不详细看了
221      for (i = 0; i < argc; i++) {
222          if (known_command == true) {
223            runtime.addOption(strdup(argv[i]));
227            ALOGV("app_process main add known option '%s'", argv[i]);
228            known_command = false;
229            continue;
230          }
231  
232          for (int j = 0;
233               j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
234               ++j) {
235            if (strcmp(argv[i], spaced_commands[j]) == 0) {
236              known_command = true;
237              ALOGV("app_process main found known command '%s'", argv[i]);
238            }
239          }
240  
241          if (argv[i][0] != '-') {
242              break;
243          }
244          if (argv[i][1] == '-' && argv[i][2] == 0) {
245              ++i; // Skip --.
246              break;
247          }
248  
249          runtime.addOption(strdup(argv[i]));
250          // The static analyzer gets upset that we don't ever free the above
251          // string. Since the allocation is from main, leaking it doesn't seem
252          // problematic. NOLINTNEXTLINE
253          ALOGV("app_process main add option '%s'", argv[i]);
254      }
255  
256      // Parse runtime arguments.  Stop at first unrecognized option.
257      bool zygote = false;
258      bool startSystemServer = false;
259      bool application = false;
260      String8 niceName;
261      String8 className;
262  
263      ++i;  // Skip unused "parent dir" argument.
264      while (i < argc) {
265          const char* arg = argv[i++];
             如果是 zygote
266          if (strcmp(arg, "--zygote") == 0) {
267              zygote = true;
268              niceName = ZYGOTE_NICE_NAME;
             如果是 system-server
269          } else if (strcmp(arg, "--start-system-server") == 0) {
270              startSystemServer = true;
271          } else if (strcmp(arg, "--application") == 0) {
272              application = true;
273          } else if (strncmp(arg, "--nice-name=", 12) == 0) {
274              niceName.setTo(arg + 12);
275          } else if (strncmp(arg, "--", 2) != 0) {
276              className.setTo(arg);
277              break;
278          } else {
279              --i;
280              break;
281          }
282      }
283  
284      Vector<String8> args;
285      if (!className.isEmpty()) {
292          runtime.setClassNameAndArgs(className, argc - i, argv + i);
293  
294          if (!LOG_NDEBUG) {
295            String8 restOfArgs;
296            char* const* argv_new = argv + i;
297            int argc_new = argc - i;
298            for (int k = 0; k < argc_new; ++k) {
299              restOfArgs.append("\"");
300              restOfArgs.append(argv_new[k]);
301              restOfArgs.append("\" ");
302            }
303            ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
304          }
305      } else {
306          // We're in zygote mode.
307          maybeCreateDalvikCache();
308  
309          if (startSystemServer) {
310              args.add(String8("start-system-server"));
311          }
312  
313          char prop[PROP_VALUE_MAX];
314          if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
315              LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
316                  ABI_LIST_PROPERTY);
317              return 11;
318          }
319  
320          String8 abiFlag("--abi-list=");
321          abiFlag.append(prop);
322          args.add(abiFlag);
323  
324          // In zygote mode, pass all remaining arguments to the zygote
325          // main() method.
326          for (; i < argc; ++i) {
327              args.add(String8(argv[i]));
328          }
329      }
330  
331      if (!niceName.isEmpty()) {
332          runtime.setArgv0(niceName.string(), true /* setProcName */);
333      }
334  
335      if (zygote) {
             现在是zygote 走这里
336          runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
337      } else if (className) {
             App走这
338          runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
339      } else {
340          fprintf(stderr, "Error: no class name or --zygote supplied.\n");
341          app_usage();
342          LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
343      }
344  }

最终会走到 AndroidRuntime 的start 这里有三件事

启动虚拟机

注册jni

启动ZygtoInit.java的main方法

cpp 复制代码
1136  void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
1137  {
1138      ALOGD(">>>>>> START %s uid %d <<<<<<\n",
1139              className != NULL ? className : "(unknown)", getuid());
1140  
1141      static const String8 startSystemServer("start-system-server");
1142      // Whether this is the primary zygote, meaning the zygote which will fork system server.
1143      bool primary_zygote = false;
1144  
1145      /*
1146       * 'startSystemServer == true' means runtime is obsolete and not run from
1147       * init.rc anymore, so we print out the boot start event here.
1148       */
1149      for (size_t i = 0; i < options.size(); ++i) {
1150          if (options[i] == startSystemServer) {
1151              primary_zygote = true;
1152             /* track our progress through the boot sequence */
1153             const int LOG_BOOT_PROGRESS_START = 3000;
1154             LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
1155          }
1156      }
1157  
1158      const char* rootDir = getenv("ANDROID_ROOT");
1159      if (rootDir == NULL) {
1160          rootDir = "/system";
1161          if (!hasDir("/system")) {
1162              LOG_FATAL("No root directory specified, and /system does not exist.");
1163              return;
1164          }
1165          setenv("ANDROID_ROOT", rootDir, 1);
1166      }
1167  
1168      const char* artRootDir = getenv("ANDROID_ART_ROOT");
1169      if (artRootDir == NULL) {
1170          LOG_FATAL("No ART directory specified with ANDROID_ART_ROOT environment variable.");
1171          return;
1172      }
1173  
1174      const char* i18nRootDir = getenv("ANDROID_I18N_ROOT");
1175      if (i18nRootDir == NULL) {
1176          LOG_FATAL("No runtime directory specified with ANDROID_I18N_ROOT environment variable.");
1177          return;
1178      }
1179  
1180      const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT");
1181      if (tzdataRootDir == NULL) {
1182          LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable.");
1183          return;
1184      }
1185  
1186      //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
1187      //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
1188  
1189      /* start the virtual machine */
1190      JniInvocation jni_invocation;
1191      jni_invocation.Init(NULL);
1192      JNIEnv* env;
          启动虚拟机
1193      if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
1194          return;
1195      }
1196      onVmCreated(env);
1197  
1198      /*
1199       * Register android functions.
1200       */
          启动注册JNI (与java层通信的方法)只加载一部分
1201      if (startReg(env) < 0) {
1202          ALOGE("Unable to register all android natives\n");
1203          return;
1204      }
1205  
1206      /*
1207       * We want to call main() with a String array with arguments in it.
1208       * At present we have two arguments, the class name and an option string.
1209       * Create an array to hold them.
1210       */
1211      jclass stringClass;
1212      jobjectArray strArray;
1213      jstring classNameStr;
1214  
1215      stringClass = env->FindClass("java/lang/String");
1216      assert(stringClass != NULL);
1217      strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
1218      assert(strArray != NULL);
1219      classNameStr = env->NewStringUTF(className);
1220      assert(classNameStr != NULL);


          这里启动ZygoteInit.java文件
1221      env->SetObjectArrayElement(strArray, 0, classNameStr);
1222  
1223      for (size_t i = 0; i < options.size(); ++i) {
1224          jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
1225          assert(optionsStr != NULL);
1226          env->SetObjectArrayElement(strArray, i + 1, optionsStr);
1227      }
1228  
1229      /*
1230       * Start VM.  This thread becomes the main thread of the VM, and will
1231       * not return until the VM exits.
1232       */
1233      char* slashClassName = toSlashClassName(className != NULL ? className : "");
1234      jclass startClass = env->FindClass(slashClassName);
1235      if (startClass == NULL) {
1236          ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
1237          /* keep going */
1238      } else {
1239          jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
1240              "([Ljava/lang/String;)V");
1241          if (startMeth == NULL) {
1242              ALOGE("JavaVM unable to find main() in '%s'\n", className);
1243              /* keep going */
1244          } else {
1245              env->CallStaticVoidMethod(startClass, startMeth, strArray);
1246  
1247  #if 0
1248              if (env->ExceptionCheck())
1249                  threadExitUncaughtException(env);
1250  #endif
1251          }
1252      }
1253      free(slashClassName);
1254  
1255      ALOGD("Shutting down VM\n");
1256      if (mJavaVM->DetachCurrentThread() != JNI_OK)
1257          ALOGW("Warning: unable to detach main thread\n");
1258      if (mJavaVM->DestroyJavaVM() != 0)
1259          ALOGW("Warning: VM did not shut down cleanly\n");
1260  }

简单看下 setVM 一些大小的初始化

虚拟机到底是什么?其实就是一个内存管理

cpp 复制代码
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool primary_zygote)
610  {
611      JavaVMInitArgs initArgs;
612      char propBuf[PROPERTY_VALUE_MAX];
613      char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
614      char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
615      char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
         省略,但是都是对虚拟机进行的初始化
670      char jdwpProviderBuf[sizeof("-XjdwpProvider:") - 1 + PROPERTY_VALUE_MAX];
671      char opaqueJniIds[sizeof("-Xopaque-jni-ids:") - 1 + PROPERTY_VALUE_MAX];
672      char bootImageBuf[sizeof("-Ximage:") - 1 + PROPERTY_VALUE_MAX];

在看下注册jni这块

cpp 复制代码
1592  /*static*/ int AndroidRuntime::startReg(JNIEnv* env)
1593  {
1594      ATRACE_NAME("RegisterAndroidNatives");

1600      androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
1601  
1602      ALOGV("--- registering native functions ---\n");

1610      env->PushLocalFrame(200);
1611  
1612      if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
1613          env->PopLocalFrame(NULL);
1614          return -1;
1615      }
1616      env->PopLocalFrame(NULL);
1617  
1620      return 0;
1621  }
cpp 复制代码
 static const RegJNIRec gRegJNI[] = {
1449          REG_JNI(register_com_android_internal_os_RuntimeInit),
1450          REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
1451          REG_JNI(register_android_os_SystemClock),
1452          REG_JNI(register_android_util_EventLog),
1453          REG_JNI(register_android_util_Log),
1454          REG_JNI(register_android_util_MemoryIntArray),
1455          REG_JNI(register_android_app_admin_SecurityLog),
1456          REG_JNI(register_android_content_AssetManager),
1457          REG_JNI(register_android_content_StringBlock),
1458          REG_JNI(register_android_content_XmlBlock),
1459          REG_JNI(register_android_content_res_ApkAssets),
1460          REG_JNI(register_android_text_AndroidCharacter),
1461          REG_JNI(register_android_text_Hyphenator),

jni其实是一个函数指针,函数指针对应了java里的方法

这个是静态注册,我们搞个例子看下 jni 既可以native -> java 也可以 java-> native

cpp 复制代码
250  int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
251  {
252      const JNINativeMethod methods[] = {
253              {"nativeFinishInit", "()V",
254               (void*)com_android_internal_os_RuntimeInit_nativeFinishInit},
255              {"nativeSetExitWithoutCleanup", "(Z)V",
256               (void*)com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup},
257      };
258      return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
259          methods, NELEM(methods));
260  }

画一张时序图

接下来看下zygoteInit.java的main方法

java 复制代码
  public static void main(String[] argv) {
        ZygoteServer zygoteServer = null;

        // Mark zygote start. This ensures that thread creation will throw
        // an error.
        ZygoteHooks.startZygoteNoThreadCreation();

        // Zygote goes into its own process group.
        try {
            Os.setpgid(0, 0);
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to setpgid(0,0)", ex);
        }

        Runnable caller;
        try {
            // Store now for StatsLogging later.
            final long startTime = SystemClock.elapsedRealtime();
            final boolean isRuntimeRestarted = "1".equals(
                    SystemProperties.get("sys.boot_completed"));

            String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
            TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
                    Trace.TRACE_TAG_DALVIK);
            bootTimingsTraceLog.traceBegin("ZygoteInit");
            RuntimeInit.preForkInit();

            boolean startSystemServer = false;
            String zygoteSocketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
            if (!isRuntimeRestarted) {
                if (isPrimaryZygote) {
                    FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                            BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START,
                            startTime);
                } else if (zygoteSocketName.equals(Zygote.SECONDARY_SOCKET_NAME)) {
                    FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                            BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START,
                            startTime);
                }
            }

            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }

            // In some configurations, we avoid preloading resources and classes eagerly.
            // In such cases, we will preload things prior to our first fork.
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                        SystemClock.uptimeMillis());

                预加载资源,加速启动进程
                有一个preload_class 
                preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                        SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            }

            // Do an initial gc to clean up after startup
            bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
            gcAndFinalize();
            bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC

            bootTimingsTraceLog.traceEnd(); // ZygoteInit

            Zygote.initNativeState(isPrimaryZygote);

            ZygoteHooks.stopZygoteNoThreadCreation();
            
            这个实际上就是socket
            如果AMS需要zygote 创建一个进程,就在这通信
            zygoteServer = new ZygoteServer(isPrimaryZygote);

            if (startSystemServer) {

                启动systemServer
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                if (r != null) {
                    r.run();
                    return;
                }
            }

            Log.i(TAG, "Accepting command socket connections");

            // The select loop returns early in the child process after a fork and
            // loops forever in the zygote.
            启动一个循环,接收AMS的消息
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with fatal exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket();
            }
        }

        // We're in the child process and have exited the select loop. Proceed to execute the
        // command.
        if (caller != null) {
            caller.run();
        }
    }

现在知道AMS和zygote是靠socket通信,可是问题是为什么使用socket?

因为socket更安全,binder会有一个线程池,有死锁的风险,为什么有死锁风险?

这里有个题外话,为什么回调里不能加锁?当你在回调里加锁,如果回调里切了线程有锁,并且访问这把锁,下面代码又需要上一把锁就会死锁

binder这个死锁是另一个场景,如果你切换了进程,当前线程拿了一把锁,你在这里切进程,锁没人通知它解开就会一直锁住,也会死锁

AMS属于SystemServer里面,服务代码

还有一个小知识点,Loop之所以是主线程是因为main方法所在的线程被称为主线程

java 复制代码
   pid = Zygote.forkSystemServer(
                    parsedArgs.mUid, parsedArgs.mGid,
                    parsedArgs.mGids,
                    parsedArgs.mRuntimeFlags,
                    null,
                    parsedArgs.mPermittedCapabilities,
                    parsedArgs.mEffectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            sytemServer在这里通过反射执行
            return handleSystemServerProcess(parsedArgs);
        }

还是刚才的main方法,pid == 0 时候代表这段代码已经是SystemServer,所以这是一段 SystemServer专属方法

那么SystemServer fork是怎么执行的呢?

java 复制代码
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
2075          JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
2076          jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
2077          jlong effective_capabilities) {
2078    std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()),
2079                     fds_to_ignore(fds_to_close);
2080  
2081    fds_to_close.push_back(gUsapPoolSocketFD);
2082  
2083    if (gUsapPoolEventFD != -1) {
2084      fds_to_close.push_back(gUsapPoolEventFD);
2085      fds_to_ignore.push_back(gUsapPoolEventFD);
2086    }
2087  
2088    if (gSystemServerSocketFd != -1) {
2089        fds_to_close.push_back(gSystemServerSocketFd);
2090        fds_to_ignore.push_back(gSystemServerSocketFd);
2091    }
2092  
2093    pid_t pid = ForkCommon(env, true,
2094                           fds_to_close,
2095                           fds_to_ignore,
2096                           true);










static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
1076                          const std::vector<int>& fds_to_close,
1077                          const std::vector<int>& fds_to_ignore,
1078                          bool is_priority_fork) {
1091  
1114  
1115    pid_t pid = fork();

关于fork函数需要结合linux的知识,这个后面专门做一期了解,把它和android系统关联起来

相关推荐
前端赵哈哈1 小时前
初学者入门:Android 实现 Tab 点击切换(TabLayout + ViewPager2)
android·java·android studio
一条上岸小咸鱼4 小时前
Kotlin 控制流(二):返回和跳转
android·kotlin
Jasonakeke4 小时前
【重学 MySQL】九十二、 MySQL8 密码强度评估与配置指南
android·数据库·mysql
Mertrix_ITCH4 小时前
在 Android Studio 中修改 APK 启动图标(2025826)
android·ide·android studio
荏苒追寻4 小时前
Android OpenGL基础1——常用概念及方法解释
android
人生游戏牛马NPC1号5 小时前
学习 Android (十七) 学习 OpenCV (二)
android·opencv·学习
恋猫de小郭5 小时前
谷歌开启 Android 开发者身份验证,明年可能开始禁止“未经验证”应用的侧载,要求所有开发者向谷歌表明身份
android·前端·flutter
用户095 小时前
Gradle声明式构建总结
android
用户096 小时前
Gradle插件开发实践总结
android
Digitally16 小时前
如何将视频从安卓设备传输到Mac?
android·macos