Android boot process

introduction

The startup process of the Android system is as follows: the
Insert picture description here
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
Insert picture description here
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. . .

Guess you like

Origin blog.csdn.net/fs3296/article/details/103858223