init进程的启动

2,186 阅读6分钟

android源码分析目录

(注:以下代码分析基于android-10.0.0_r30)

一 概述

因为Android系统是基于Linux内核,所以Android系统的启动首先是从Linux开始的,当我们启动Android手机的时候,会经过一系列的调用,直到启动zygote进程,也是我们系统的第一个进程

system/core/init/main.cpp
system/core/init/init.cpp
system/core/init/parser.cpp
system/core/init/epoll.h
system/core/init/epoll.cpp
system/core/rootdir/init.rc
system/core/rootdir/init.zygote64.rc

二 init

最初的启动,是在Android系统目录system/core/init/main.cpp中的main函数中执行的

main函数中主要有几个函数

  1. FirstStageMain:系统启动的第一阶段
  2. SetupSelinux:加载SELinux规则
  3. SecondStageMain:系统启动的第二个阶段

它们是通过传递不同的参数来进行调用的

[main.cpp]

int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif
    // 设置优先级,这个优先级会在SecondStageMain中被还原
    setpriority(PRIO_PROCESS, 0, -20);

    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }

    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap function_map;
            //
            return SubcontextMain(argc, argv, &function_map);
        }

        if (!strcmp(argv[1], "selinux_setup")) {
            //加载SELinux规则,并进入第二阶段
            return SetupSelinux(argv);
        }

        if (!strcmp(argv[1], "second_stage")) {
                //系统启动关键的第二步
            return SecondStageMain(argc, argv);
        }
    }
        //系统启动关键的第一步
    return FirstStageMain(argc, argv);
}

FirstStageMain

init进程启动的第一步,这一步主要做了几件事

  1. 挂载一些分区并创建关键目录
  2. 初始化Kernel日志系统
  3. 进入SetupSelinux阶段

[init.cpp]

int FirstStageMain(int argc, char** argv) {
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        //用于init进程崩溃时,启动bootloader,让开发者定位问题
        InstallRebootSignalHandlers();
    }

    boot_clock::time_point start_time = boot_clock::now();

    std::vector<std::pair<std::string, int>> errors;
#define CHECKCALL(x) \
    if ((x) != 0) errors.emplace_back(#x " failed", errno);

    // Clear the umask.
    umask(0);
    //创建并挂载一些启动需要的系统文件
    CHECKCALL(clearenv());
    ...
#undef CHECKCALL
    //重定向标准输入输出错误输出到 dev/null,第一阶段和第二阶段都需要做
    SetStdioToDevNull(argv);
    //初始化linux log,因为现在android的log还没有启动
    InitKernelLogging(argv);

    //加载一些ramdisk
    ...

    //传入参数selinux_setup,进入selinux_setup阶段
    const char* path = "/system/bin/init";
    const char* args[] = {path, "selinux_setup", nullptr};
    auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);
    close(fd);
    execv(path, const_cast<char**>(args));

    return 1;
}

SetupSelinux

SELinux全称是Security-Enhanced Linux,它是一个Linux相关的安全子系统,这里在作为这些相关操作后,会进入

SecondStageMain阶段

int SetupSelinux(char** argv) {
    //一些Selinux相关的初始化
    ...
    //进入init进程的第二阶段
    const char* path = "/system/bin/init";
    const char* args[] = {path, "second_stage", nullptr};
    execv(path, const_cast<char**>(args));

    return 1;
}

SecondStageMain

init进程启动的第二步,这一步做的操作非常多

  1. 系统会进行一些linux的相关设置
  2. 然后系统会初始化一些属性PropertyInit
  3. 进行一些SELinux的设置
  4. 创建一个epoll,它会接受一下信号并处理
  5. 设置系统属性StartPropertyService
  6. 解析rc文件,开始添加action,这些ation可以分为四个阶段:early-init,init,early-boot,boot
  7. 进入死循环,执行这些action

[init.cpp]

int SecondStageMain(int argc, char** argv) {
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        //用于init进程崩溃时,启动bootloader,让开发者定位问题
        InstallRebootSignalHandlers();
    }

    boot_clock::time_point start_time = boot_clock::now();

    trigger_shutdown = [](const std::string& command) { shutdown_state.TriggerShutdown(command); };
    //和第一步中一样,重定向标准输入输出错误输出到 dev/null
    SetStdioToDevNull(argv);
    InitSecondStageLogging(argv);

    //前面会有一些linux相关的设置,这里略去
    ...
    //初始化一些属性
    PropertyInit();

    //debug相关
    if (load_debug_prop) {
        UmountDebugRamdisk();
    }

    //挂载filesystems文件
    MountExtraFilesystems();

    //设置SELinux
    SelinuxSetupKernelLogging();
    //初始化Selabel
    SelabelInitialize();
    //设置Selinux并恢复一些上下文
    SelinuxRestoreContext();
    //新建epoll
    Epoll epoll;
    if (auto result = epoll.Open(); !result.ok()) {
        PLOG(FATAL) << result.error();
    }
    //设置子进程退出的信号处理函数
    InstallSignalFdHandler(&epoll);
    //设置属性更改的通知函数
    InstallInitNotifier(&epoll);
    //设置系统属性
    StartPropertyService(&property_fd);

    // Make the time that init stages started available for bootstat to log.
    RecordStageBoottimes(start_time);

    // 设置 libavb 版本
    if (const char* avb_version = getenv("INIT_AVB_VERSION"); avb_version != nullptr) {
        SetProperty("ro.boot.avb_version", avb_version);
    }
    unsetenv("INIT_AVB_VERSION");

    fs_mgr_vendor_overlay_mount_all();
    export_oem_lock_status();
    MountHandler mount_handler(&epoll);
    SetUsbController();

    const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
    Action::set_function_map(&function_map);

    if (!SetupMountNamespaces()) {
        PLOG(FATAL) << "SetupMountNamespaces failed";
    }
    //初始化第二阶段上下文
    InitializeSubcontext();
    //构建ActionManager和ServiceList相关对象,用来解析rc相关文件的action、service
    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();
    //加载启动的配置文件,即一些rc文件
    LoadBootScripts(am, sm);

    // Turning this on and letting the INFO logging be discarded adds 0.2s to
    // Nexus 9 boot time, so it's disabled by default.
    if (false) DumpState();

    // 确保 gsi 可用
    auto is_running = android::gsi::IsGsiRunning() ? "1" : "0";
    SetProperty(gsi::kGsiBootedProp, is_running);
    auto is_installed = android::gsi::IsGsiInstalled() ? "1" : "0";
    SetProperty(gsi::kGsiInstalledProp, is_installed);
    //添加一下action
    am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
    am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
    am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux");
    //init有四个阶段:early-init,init,early-boot,boot
    //第一阶段 early-init
    am.QueueEventTrigger("early-init");

    // 等待冷启动队列的完成,用来确认ueventd已经设置所有的/dev
    am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");

    // 开始处理需要/dev的action
    am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
    am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
    //初始化/dev/keychord设备,调试相关
    Keychords keychords;
    am.QueueBuiltinAction(
            [&epoll, &keychords](const BuiltinArguments& args) -> Result<void> {
                for (const auto& svc : ServiceList::GetInstance()) {
                    keychords.Register(svc->keycodes());
                }
                keychords.Start(&epoll, HandleKeychord);
                return {};
            },
            "KeychordInit");

    // 第二阶段,init阶段
    am.QueueEventTrigger("init");
    //如果wait_for_coldboot_done没有准备好,就重复mix_hwrng_into_linux_rng
    am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");

    // Don't mount filesystems or start core system services in charger mode.
    std::string bootmode = GetProperty("ro.bootmode", "");
    if (bootmode == "charger") {
        am.QueueEventTrigger("charger");
    } else {
        //在非charger模式下挂着filesystems,启动core system
        am.QueueEventTrigger("late-init");
    }

    // 在当前状态下运行所有的属性触发器
    am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");

    // 还原优先级
    setpriority(PRIO_PROCESS, 0, 0);
    while (true) {
        // 这里是一个死循环,主要就是处理之前添加的各种事件,如果对应的子进程挂掉,也会重启对应的子进程
        auto epoll_timeout = std::optional<std::chrono::milliseconds>{};

        auto shutdown_command = shutdown_state.CheckShutdown();
        if (shutdown_command) {
            LOG(INFO) << "Got shutdown_command '" << *shutdown_command
                      << "' Calling HandlePowerctlMessage()";
            HandlePowerctlMessage(*shutdown_command);
            shutdown_state.set_do_shutdown(false);
        }

        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
            //执行之前添加到action中的Command
            am.ExecuteOneCommand();
        }
        if (!IsShuttingDown()) {
            auto next_process_action_time = HandleProcessActions();

            // 如果进程需要重启,就唤醒
            if (next_process_action_time) {
                epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
                        *next_process_action_time - boot_clock::now());
                if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
            }
        }

        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
            // 如果工作没做完,就继续唤醒
            if (am.HasMoreCommands()) epoll_timeout = 0ms;
        }
        //循环等待事件
        auto pending_functions = epoll.Wait(epoll_timeout);
        if (!pending_functions.ok()) {
            LOG(ERROR) << pending_functions.error();
        } else if (!pending_functions->empty()) {
            //在处理其他功能前,先处理children,避免守护进程看到程序退出而产生init竞争
            ReapAnyOutstandingChildren();
            //处理等待的事件
            for (const auto& function : *pending_functions) {
                (*function)();
            }
        }
        if (!IsShuttingDown()) {
            HandleControlMessages();
            SetUsbController();
        }
    }

    return 0;
}

三 Epoll

关于Epoll,它的百度百科如下

epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。epoll除了提供select/poll那种IO事件的水平触发(Level Triggered)外,还提供了边缘触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。

具体的定义在system/core/init/epoll.h

class Epoll {
  public:
    Epoll();

    Result<void> Open();
    Result<void> RegisterHandler(int fd, std::function<void()> handler, uint32_t events = EPOLLIN);
    Result<void> UnregisterHandler(int fd);
    Result<std::vector<std::function<void()>*>> Wait(
            std::optional<std::chrono::milliseconds> timeout);

  private:
    android::base::unique_fd epoll_fd_;
    std::map<int, std::function<void()>> epoll_handlers_;
};

在初始化中,调用了两个函数

//设置子进程退出的信号处理函数
InstallSignalFdHandler(&epoll);
//设置属性更改的通知函数
InstallInitNotifier(&epoll);

InstallSignalFdHandler

注册子进程的SIGCHLD信号来监听子进程的运行状况,如果子进程挂断,那么就就移除或者重启挂掉的子进程而避免它成为僵尸进程

[init.cpp]

static void InstallSignalFdHandler(Epoll* epoll) {
    ...

    // Register a handler to unblock signals in the child processes.
    const int result = pthread_atfork(nullptr, nullptr, &UnblockSignals);
    if (result != 0) {
        LOG(FATAL) << "Failed to register a fork handler: " << strerror(result);
    }

    signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
    if (signal_fd == -1) {
        PLOG(FATAL) << "failed to create signalfd";
    }
    //注册signal_fd事件
    if (auto result = epoll->RegisterHandler(signal_fd, HandleSignalFd); !result.ok()) {
        LOG(FATAL) << result.error();
    }
}

InstallInitNotifier

注册一个wake_main_thread_fd事件的监听

[init.cpp]

static void InstallInitNotifier(Epoll* epoll) {
    wake_main_thread_fd = eventfd(0, EFD_CLOEXEC);
    if (wake_main_thread_fd == -1) {
        PLOG(FATAL) << "Failed to create eventfd for waking init";
    }
    auto clear_eventfd = [] {
        uint64_t counter;
        TEMP_FAILURE_RETRY(read(wake_main_thread_fd, &counter, sizeof(counter)));
    };

    if (auto result = epoll->RegisterHandler(wake_main_thread_fd, clear_eventfd); !result.ok()) {
        LOG(FATAL) << result.error();
    }
}

四 Android Init Language

当前面的几步做完之后,就需要来加载init.rc的相关文件了,在android 10中,rc文件有多个,这些rc文件是通过AIL(Android Init Language)语言编写的,关于AIL的官方文档在这里

五 zygote

LoadBootScripts

LoadBootScripts是通过解析器Parser对rc文件进行解析,比较常见的有Action、Command、import等

[init.cpp]

static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser = CreateParser(action_manager, service_list);
    //获取rc文件的值,默认是空
    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    if (bootscript.empty()) {
        parser.ParseConfig("/system/etc/init/hw/init.rc");
        if (!parser.ParseConfig("/system/etc/init")) {
            late_import_paths.emplace_back("/system/etc/init");
        }
        // late_import is available only in Q and earlier release. As we don't
        // have system_ext in those versions, skip late_import for system_ext.
        parser.ParseConfig("/system_ext/etc/init");
        if (!parser.ParseConfig("/product/etc/init")) {
            late_import_paths.emplace_back("/product/etc/init");
        }
        if (!parser.ParseConfig("/odm/etc/init")) {
            late_import_paths.emplace_back("/odm/etc/init");
        }
        if (!parser.ParseConfig("/vendor/etc/init")) {
            late_import_paths.emplace_back("/vendor/etc/init");
        }
    } else {
        parser.ParseConfig(bootscript);
    }
}
//创建解析器
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser;

    parser.AddSectionParser("service", std::make_unique<ServiceParser>(
                                               &service_list, GetSubcontext(), std::nullopt));
    parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, GetSubcontext()));
    parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));

    return parser;
}

rc相关文件都在system/core/rootdir/init.rc目录下,因为这里有多个zygote文件,所以它就会通过import导入对应的zygote文件,然后再启动Zygote

[init.rc]

import /init.${ro.zygote}.rc

[init.zygote64.rc]

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks