Android 系统启动流程

依旧是带着问题再去学习

首先,Android是怎么启动的?

Android服务是怎么启动的?

Android线程是怎么切换的?

Android ApplicationThread是怎么创建的?

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

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

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

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

首先 init进程如何启动的?

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

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

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 是什么呢?

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上

cc_binary {
//省略srcs: ["main.cpp"]}

时序图如下 

 main.cpp是Android系统的头文件,那么接下来我们接着看main.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

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);以及启动 selinuxupconst char* args[] = {path, "selinux_setup", nullptr};execv(path, const_cast<char**>(args));
333      return 1;
334  }

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

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

然后再次进入,启动 Second

 

SetupSelinux 是一个最小权限原则 

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

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

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

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语法进行解析

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循环当中

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

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层

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启动的

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方法

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 一些大小的初始化

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

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这块

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  }
 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

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方法 

  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 startupbootTimingsTraceLog.traceBegin("PostZygoteInitGC");gcAndFinalize();bootTimingsTraceLog.traceEnd(); // PostZygoteInitGCbootTimingsTraceLog.traceEnd(); // ZygoteInitZygote.initNativeState(isPrimaryZygote);ZygoteHooks.stopZygoteNoThreadCreation();这个实际上就是socket如果AMS需要zygote 创建一个进程,就在这通信zygoteServer = new ZygoteServer(isPrimaryZygote);if (startSystemServer) {启动systemServerRunnable 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方法所在的线程被称为主线程

   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是怎么执行的呢?

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系统关联起来

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/654799.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vp9协议梳理-header头文件

vp9协议梳理-header头文件 本文是对vp9视频码流中header中包含的语法元素的一个分类整理&#xff0c;及其对具体的解码过程的影响的分析。 这里写目录标题 vp9协议梳理-header头文件1. Vp9码流中的header头文件2. profile3. show_existing_frame, frame_to_show_map_idx4. fr…

What is Rust? Why Rust?

why Rust&#xff1f; 目前&#xff0c;Rust 变得越来越流行。然而&#xff0c;仍然有很多人&#xff08;和公司&#xff01;&#xff09;误解了 Rust 的主张价值是什么&#xff0c;甚至误解了它是什么。在本文中&#xff0c;我们将讨论 Rust 是什么以及为什么它是一种可以增强…

vivado 配置内存IP

配置内存IP UltraScale体系结构内存IP支持DDR3和DDR4 SDRAM的配置&#xff0c;QDRIIPLUS SRAM和RLDRAM3型接口。截至2015.3&#xff0c;内存IP已被拆分基于内存接口标准和工具流&#xff0c;将其划分为不同的IP。“自定义IP”对话框框包含基本和高级配置选项&#xff0c;其中包…

【C/C++ 05】快速排序

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序算法&#xff0c;其基本思想是&#xff1a;任取待排序序列中的某元素作为基准值&#xff0c;按照该基准值将待排序集合分割成两个子序列&#xff0c;左子序列中所有元素均小于基准值&#xff0c;右子序列中所有元素均大于…

数据在网络传输中为什么要加密?

在信息化浪潮席卷全球的今天&#xff0c;数据如同流淌在信息高速公路的生命血液&#xff0c;其安全传输的重要性不言而喻。随着网络空间中各种威胁与挑战日益凸显&#xff0c;加密技术已成为保护数据安全、维护用户隐私、确保业务连续性的关键手段。它就如同一道无形的防护盾&a…

Nestjs 全局拦截器

一、拦截器 拦截器作用&#xff1a; 在函数执行之前、之后绑定额外的逻辑转换函数的返回结果转换从函数抛出的异常扩展基本函数的行为根据所选条件重写函数 期望接口返回一个标准的json格式&#xff0c;利用拦截器对数据做全局的格式化 {code: "200",data: [],mess…

【文本到上下文 #7】探索 NLP 中的 Seq2Seq、编码器-解码器和注意力机制

一、说明 今天&#xff0c;我们将探讨序列到序列 &#xff08;seq2seq&#xff09; 模型的复杂工作原理&#xff0c;特别关注编码器-解码器架构和注意力机制。这些概念是各种 NLP 应用的基础&#xff0c;从机器翻译到问答系统。 这是可以期待的&#xff1a; Seq2Seq模型中的编码…

数据结构之单链表详解

前言 之前大摆了5天多&#xff0c;没怎么学编程&#xff0c;自昨日起&#xff0c;觉不可如此&#xff0c;痛定思痛&#xff0c;开始继续学习&#xff0c;昨天刷了20多道简单级别的力扣&#xff0c;今天想把链表好好巩固一下&#xff0c;于是乎&#xff0c;把单链表的增删查改搞…

基础算法之Huffman编码

// Type your code here, or load an example. #include<iostream> #include<string> #include<queue> #include <unordered_map> #include <vector>using namespace std;//树节点结构 struct Node {char ch;int freq;Node *left;Node *right;No…

数据结构3、基于栈的后缀算术表达式求值

1 题目描述 图1 中缀表达式转化为后缀表达式题目描述 图2 基于栈的后缀算术表达式求值题目描述 2 题目解读 借助一个运算符栈&#xff0c;可将中缀表达式转化为后缀表达式&#xff1b;借助一个运算数栈&#xff0c;可对后缀表达式求值。借助一个运算符栈和一个运算数栈&#xf…

Java基础数据结构之哈希表

概念 顺序结构以及平衡树 中&#xff0c;元素关键码与其存储位置之间没有对应的关系&#xff0c;因此在 查找一个元素时&#xff0c;必须要经过关键 码的多次比较 。 顺序查找时间复杂度为 O(N) &#xff0c;平衡树中为树的高度&#xff0c;即 O( log2N ) &#xff0c;搜索的效…

防火墙用户认证、NAT、策略路由、DNS透明代理以及双机热备笔记

用户认证 防火墙管理员登录认证 --- 检验身份的合法性&#xff0c;划分身份权限 用户认证 --- 上网行为管理的一部分 用户&#xff0c;行为&#xff0c;流量 --- 上网行为管理三要素 用户认证的分类 上网用户认证 --- 三层认证 --- 所有的跨网段的通信都可以属于上网行为。…

【Web前端实操19】商城官网_分析与顶部广告

本次实操主要是借用小米之前的网站来进行参考&#xff0c;达成网站静态页面开发的目的&#xff0c;而新学者想要一次性直接开发整个网站&#xff0c;肯定会很懵圈&#xff0c;因此&#xff0c;这个商城官网我会一部分一部分地进行拆分来写&#xff0c;最后合成整个界面。 本次…

国企重组整合后,如何严把“选人用人”关?

三年国企改革之后&#xff0c;新一轮国企改革明确重组方向&#xff0c;强调将“战略性重组和专业化整合”作为深化供给侧结构性改革从而建设世界一流企业的重要抓手&#xff0c;推动了国有资源的高效运转流动。在很多企业兼并、重组后&#xff0c;成立了新的集团性公司&#xf…

Mysql查询数据

1 基本查询语句 MySQL从数据表中查询数据的基本语句为SELECT语句。SELECT语句的基本格式是&#xff1a; 2 单表查询 2.1 查询所有字段 SELECT * FROM 表名; 2.2 在SELECT语句中指定所有字段 SELECT f_id, s_id ,f_name, f_price FROM fruits; 2.3 查询单个字段 SELECT 列名FR…

nginx部署前端(vue)项目及配置修改

目录 一、前端应用打包 二、部署前端应用 1、上传前端文件夹 2、修改nginx配置文件 3、重启nginx 三、查看效果 nginx安装参考&#xff1a;linux安装nginx-CSDN博客 一、前端应用打包 打包命令 npm run build 打包成功如下&#xff0c;会在项目路径下生成dist文件夹 二…

Windows Server 2003 Web服务器搭建

系列文章目录 目录 系列文章目录 前言 一、Web服务器是什么&#xff1f; 二、配置服务器 1.实验环境搭建 2.服务器搭建 1)控制面板中找到增加或删除程序打开 2)点击增加程序 3)安装Web服务器 4)查看安装是否成功 5)打开Internet信息服务(IIS)管理器,进行配置 6)找…

【开源之美】:cppcheck

一、项目链接 https://github.com/danmar/cppcheck/tree/main 二、效果示例

图像复原的天花板在哪里?SUPIR:开创性结合文本引导先验和模型规模扩大

SUPIR&#xff08;Scaling-UP Image Restoration&#xff09;&#xff0c;这是一种开创性的图像复原方法&#xff0c;利用生成先验和模型扩大规模的力量。通过利用多模态技术和先进的生成先验&#xff0c;SUPIR在智能和逼真的图像复原方面取得了重大进展。作为SUPIR中的关键催化…

如何配置MacLinuxWindows环境变量

这里写目录标题 什么是环境变量什么是PATH为什么要配置环境变量 如何配置环境变量环境变量有哪些环境变量加载顺序环境变量加载详解 配置参考方法一&#xff1a; export PATHLinux环境变量配置方法二&#xff1a;vim ~/.bashrcLinux环境变量配置方法三&#xff1a;vim ~/.bash_…