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.rhkb.cn/news/250208.html

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

相关文章

jenkins pipeline配置maven可选参数

1、在Manage Jenkins下的Global Tool Configuration下对应的maven项添加我们要用得到的不同版本的maven安装项 2、pipeline文件内容具体如下 我们maven是单一的&#xff0c;所以我们都是配置单选参数 pipeline {agent anyparameters {gitParameter(name: BRANCH_TAG, type: …

Jenkins手把手图文教程[基于Jenkins 2.164.1]

Jenkins手把手图文教程[基于Jenkins 2.164.1] 本文基于当前最新的 LTS 版本 2.164.1 &#xff0c;理论上适应于Jenkins 2.x所有版本。 一、下载 前往https://jenkins.io/download/ &#xff0c;按需下载。如用于生产&#xff0c;建议下载Long-term Support (LTS) 版本&#xf…

【全网最全】2024美赛ABCDEF题思路模型全解(后续会更新)

欲获取更多资料&#xff0c;一定要点击这里并关注文末的公众号&#xff01;&#xff01;&#xff01; 最新更新&#xff1a;我们团队不仅在第一时间更新了24美赛全题目的深度翻译和深入分析&#xff0c;经过爆肝奋战&#xff0c;我们在第一时间给出了ABCDEF全题目的完整建模过程…

Swagger学习使用

swagger升级导致访问ui页面地址不一样 方式一 依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.3.RELEASE</version> </parent> <dependen…

随机 Transformer

在这篇博客中&#xff0c;我们将通过一个端到端的示例来讲解 Transformer 模型中的数学原理。我们的目标是对模型的工作原理有一个良好的理解。为了使内容易于理解&#xff0c;我们会进行大量简化。我们将减少模型的维度&#xff0c;以便我们可以手动推理模型的计算过程。例如&…

某赛通电子文档安全管理系统 UploadFileList 任意文件读取漏洞复现

0x01 产品简介 某赛通电子文档安全管理系统(简称:CDG)是一款电子文档安全加密软件,该系统利用驱动层透明加密技术,通过对电子文档的加密保护,防止内部员工泄密和外部人员非法窃取企业核心重要数据资产,对电子文档进行全生命周期防护,系统具有透明加密、主动加密、智能…

微信小程序 安卓/IOS兼容问题

一、背景 在开发微信小程序时&#xff0c;不同的手机型号会出现兼容问题&#xff0c;特此记录一下 二、安卓/IOS兼容问题总结 2.1、new Date()时间转换格式时&#xff0c;IOS不兼容 问题&#xff1a;在安卓中时间格式2024-1-31 10:10:10&#xff0c;但是在iOS中是不支持 &q…

Electron桌面应用实战:Element UI 导航栏橙色轮廓之谜与Bootstrap样式冲突解决方案

目录 引言 问题现象及排查过程 描述问题 深入探索 查明原因 解决方案与策略探讨 重写样式 禁用 Bootstrap 样式片段 深度定制 Element UI 组件 隔离样式作用域 结语 引言 在基于 Electron 开发桌面应用的过程中&#xff0c;我们可能时常遇到各种意想不到的问题…

JavaScript高级:防抖和节流

1 防抖&#xff08;debounce&#xff09; 单位时间内&#xff0c;频繁触发事件&#xff0c;只执行最后一次 【例子】王者荣耀英雄回城&#xff0c;只要被打断就要重新来 【应用场景】1. 搜索框搜索输入。只需用户最后一次输入完&#xff0c;再发送请求&#xff1b;2. 手机号、…

美国将限制中国,使用Azure、AWS等云,训练AI大模型

1月29日&#xff0c;美国商务部在Federal Register&#xff08;联邦公报&#xff09;正式公布了&#xff0c;《采取额外措施应对与重大恶意网络行为相关的国家紧急状态》提案。 该提案明确要求美国IaaS&#xff08;云服务&#xff09;厂商在提供云服务时&#xff0c;要验证外国…

生产问题排查系列——未知404状态接口请求

引言 我们的产品主打金融服务领域&#xff0c;以B端客户为我们的核心合作伙伴&#xff0c;然而&#xff0c;我们的服务最终将惠及C端消费者。在技术实现上&#xff0c;我们采用了公司自主研发的微服务框架&#xff0c;该框架基于SpringBoot&#xff0c;旨在提供高效、可靠的服…

Day06-Linux下目录命令讲解及重要文件讲解

Day06-Linux下目录命令讲解及重要文件讲解 1. Linux目录文件1.1 Linux系统目录结构介绍1.1.1 Linux与Windows目录结构对比 1.2 重要的Linux配置文件介绍1.2.1 /etc系统初始化及设置相关重要文件1.2.2 /usr目录的重要知识介绍------应用程序目录1.2.3 /var目录下的路径知识-----…

Mac如何设置一位数密码?

一、问题 Mac如何设置一位数密码&#xff1f; 二、解答 1、打开终端 2、清除全局账户策略 sudo pwpolicy -clearaccountpolicies 输入开机密码&#xff0c;这里是看不见的&#xff0c;输入完回车即可 3、重新设置密码 &#xff08;1&#xff09;打开设置-->用户和群组…

jenkins 下载插件sentry-cli失败 证书过期

现状 npm set ENTRYCLI_CDNURLhttps://cdn.npm.taobao.org/dist/sentry-cli npm set sentrycli_cdnurlhttps://cdn.npm.taobao.org/dist/sentry-cli 原因是npm原域名停止解析&#xff0c;在访问上面sentry-cli的cdn资源的时候 证书过期无法下载。 解决&#xff1a; 替换证书过期…

解析Excel文件内容,按每列首行元素名打印出某个字符串的统计占比(超详细)

目录 1.示例&#xff1a; 1.1 实现代码1&#xff1a;列数为常量 运行结果&#xff1a; 1.2 实现代码2&#xff1a;列数为变量 运行结果&#xff1a; 1.示例&#xff1a; 开发需求&#xff1a;读取Excel文件&#xff0c;统计第3列到第5列中每列的"False"字段占…

机器学习算法决策树

决策树的介绍 决策树是一种常见的分类模型&#xff0c;在金融风控、医疗辅助诊断等诸多行业具有较为广泛的应用。决策树的核心思想是基于树结构对数据进行划分&#xff0c;这种思想是人类处理问题时的本能方法。例如在婚恋市场中&#xff0c;女方通常会先询问男方是否有房产&a…

【c语言】简单贪吃蛇的实现

目录 一、游戏说明 ​编辑 二、地图坐标​ ​编辑 三、头文件 四、蛇身和食物​ 五、数据结构设计​ 蛇节点结构如下&#xff1a; 封装一个Snake的结构来维护整条贪吃蛇&#xff1a;​ 蛇的方向&#xff0c;可以一一列举&#xff0c;使用枚举&#xff1a; 游戏状态&a…

C# winform 多语言(json)方式实现

前后对比 使用nuget json工具包1.总体思路 创建对应的json字典对照表 { "测试":"Test", "语言":"Language", "设置":"Set", "中文(默认)":"Chinese (default)", "英文":"E…

用通俗易懂的方式讲解:一文详解大模型 RAG 模块

文章目录 什么是 RAG&#xff1f;技术交流&资料通俗易懂讲解大模型系列 RAG模块化什么是模块化RAG&#xff1f; 索引模块块优化滑动窗口从小到大元数据附加 结构化组织层次化索引知识图谱文档组织 预检索模块查询扩展多查询子查询CoVe 查询转换重写HyDE 查询路由元数据路由…

Java对象属性设置方式

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; 对象属性设置方式 直接赋值 SystemMappingCode systemMappingCode new SystemMappingCode();systemMappingCode.setCodeResp(request.getCodeResp());systemMapping…