Android boot process
introduction
The startup process of the Android system is as follows: the
entire process is divided into four stages, namely the boot phase , the kernel startup phase , the user mode init phase , and the Zygote startup phase . Since the Android system kernel is trimmed based on linux, its boot and kernel startup are basically the same as linux. The difference is the user mode init stage and the Zygote startup stage, especially the Zygote stage is unique to Android.
Note 1 : This article interrupts the analysis of the user mode init phase and Zygote startup phase, the boot phase and the kernel startup phase are not analyzed.
1 User mode init phase
1.1 Process overview
The entry main function of the first process init in user mode is in the /system/core/init/init.cpp file. The whole process is roughly summarized as follows: The
whole process is divided into five steps. First, filter the non-init process options, because some processes are also started from this entry; the second step, whether the disk device is started for the first time, if it is to initialize the device; the third step, initialize and set the system properties, prepare the environment, etc. Setup; the fourth step, load and execute the rc file; finally, enter the monitoring loop.
1.2 Interpretation of source code
The main flow of the main function is summarized as follows:
1 First, it judges whether the 0th parameter is ueventd or watchdogd, and then it judges whether the first parameter is subcontext. Because the binary and init processes executed by the three subsequent processes are the same. If it is not, we will really enter our init stage. The code is as follows:
545int main(int argc, char** argv) {
546 if (!strcmp(basename(argv[0]), "ueventd")) {
547 return ueventd_main(argc, argv);
548 }
549
550 if (!strcmp(basename(argv[0]), "watchdogd")) {
551 return watchdogd_main(argc, argv);
552 }
553
554 if (argc > 1 && !strcmp(argv[1], "subcontext")) {
555 InitKernelLogging(argv);
556 const BuiltinFunctionMap function_map;
557 return SubcontextMain(argc, argv, &function_map);
558 }
559
560 if (REBOOT_BOOTLOADER_ON_PANIC) {
561 InstallRebootSignalHandlers();
562 }
2 Then, judge whether it is the first boot, if it is, perform the first boot initialization, create some necessary files, mount some directories, initialize selinux, etc. The code is as follows:
564 bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
565
566 if (is_first_stage) {
567 boot_clock::time_point start_time = boot_clock::now();
568
569 // Clear the umask.
570 umask(0);
3 Initialize and load system properties, set some initial properties, start selinux, and finally start property services. The core code is as follows. The code of the property service is in /system/core/init/property_service.cpp. The 693 line of the code below calls the sigchld_handler_init function. This function is in the /system/core/init/sigchld_handler.cpp file. It is mainly used to monitor the death signal of the service child process, and then restart the service. This is why Android can Ensure that the service process can be restarted due to abnormal death.
658 property_init();
659
660 // If arguments are passed both on the command line and in DT,
661 // properties set in DT always have priority over the command-line ones.
662 process_kernel_dt();
663 process_kernel_cmdline();
664
665 // Propagate the kernel variables to internal variables
666 // used by init as well as the current required properties.
667 export_kernel_boot_props();
668
669 // Make the time that init started available for bootstat to log.
670 property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
671 property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
672
673 // Set libavb version for Framework-only OTA match in Treble build.
674 const char* avb_version = getenv("INIT_AVB_VERSION");
675 if (avb_version) property_set("ro.boot.avb_version", avb_version);
676
677 // Clean up our environment.
678 unsetenv("INIT_SECOND_STAGE");
679 unsetenv("INIT_STARTED_AT");
680 unsetenv("INIT_SELINUX_TOOK");
681 unsetenv("INIT_AVB_VERSION");
682
683 // Now set up SELinux for second stage.
684 SelinuxSetupKernelLogging();
685 SelabelInitialize();
686 SelinuxRestoreContext();
687
688 epoll_fd = epoll_create1(EPOLL_CLOEXEC);
689 if (epoll_fd == -1) {
690 PLOG(FATAL) << "epoll_create1 failed";
691 }
692
693 sigchld_handler_init();
694
695 if (!IsRebootCapable()) {
696 // If init does not have the CAP_SYS_BOOT capability, it is running in a container.
697 // In that case, receiving SIGTERM will cause the system to shut down.
698 InstallSigtermHandler();
699 }
700
701 property_load_boot_defaults();
702 export_oem_lock_status();
703 start_property_service();
704 set_usb_controller();
4 The following code is the core of the init process to start services and mount files. The first is to load the rc configuration file through LoadBootScripts. This function is also in /system/core/init/init.cpp. When the ro.boot.init_rc property is not set, the /init.rc file will be loaded, and then the / rc files in the system/etc/init, /product/etc/init, /odm/etc/init, /vendor/etc/init directory; then in turn trigger early-init, init, charger or late through the function ActionManager::QueueEventTrigger -init, these series of actions will trigger the custom actions in the rc file; then start various services.
706 const BuiltinFunctionMap function_map;
707 Action::set_function_map(&function_map);
708
709 subcontexts = InitializeSubcontexts();
710
711 ActionManager& am = ActionManager::GetInstance();
712 ServiceList& sm = ServiceList::GetInstance();
713
714 LoadBootScripts(am, sm);
715
716 // Turning this on and letting the INFO logging be discarded adds 0.2s to
717 // Nexus 9 boot time, so it's disabled by default.
718 if (false) DumpState();
719
720 am.QueueEventTrigger("early-init");
721
722 // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
723 am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
724 // ... so that we can start queuing up actions that require stuff from /dev.
725 am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
726 am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
727 am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
728 am.QueueBuiltinAction(keychord_init_action, "keychord_init");
729 am.QueueBuiltinAction(console_init_action, "console_init");
730
731 // Trigger all the boot actions to get us started.
732 am.QueueEventTrigger("init");
733
734 // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
735 // wasn't ready immediately after wait_for_coldboot_done
736 am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
737
738 // Don't mount filesystems or start core system services in charger mode.
739 std::string bootmode = GetProperty("ro.bootmode", "");
740 if (bootmode == "charger") {
741 am.QueueEventTrigger("charger");
742 } else {
743 am.QueueEventTrigger("late-init");
744 }
745
746 // Run all property triggers based on current state of the properties.
747 am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
5 Finally, enter the epoll loop to listen to the event and process it. For example, when the child service process dies abnormally, the corresponding signal function will write information to signal_write_fd, and then epoll will poll for processing.
749 while (true) {
750 // By default, sleep until something happens.
751 int epoll_timeout_ms = -1;
752
753 if (do_shutdown && !shutting_down) {
754 do_shutdown = false;
755 if (HandlePowerctlMessage(shutdown_command)) {
756 shutting_down = true;
757 }
758 }
759
760 if (!(waiting_for_prop || Service::is_exec_service_running())) {
761 am.ExecuteOneCommand();
762 }
763 if (!(waiting_for_prop || Service::is_exec_service_running())) {
764 if (!shutting_down) {
765 auto next_process_restart_time = RestartProcesses();
766
767 // If there's a process that needs restarting, wake up in time for that.
768 if (next_process_restart_time) {
769 epoll_timeout_ms = std::chrono::ceil<std::chrono::milliseconds>(
770 *next_process_restart_time - boot_clock::now())
771 .count();
772 if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
773 }
774 }
775
776 // If there's more work to do, wake up again immediately.
777 if (am.HasMoreCommands()) epoll_timeout_ms = 0;
778 }
779
780 epoll_event ev;
781 int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
782 if (nr == -1) {
783 PLOG(ERROR) << "epoll_wait failed";
784 } else if (nr == 1) {
785 ((void (*)()) ev.data.ptr)();
786 }
787 }
2 Zygote startup phase
The startup process of zygote will be added later. . .