Android FrameWork - 开机启动 & Init 进程 初探

前言

安卓启动流程

1. 启动电源,加载引导程序

接通电源并启动时,引导芯片代码从预定义的地方(固化在ROM)开始执行,加载引导程序 BootLoader 到RAM中。

2.执行引导程序BootLoader

Android系统运行前会先运行 BootLoader,它的作用是拉起并运行系统OS。这个类似与 PC 的 bios,作用是初始化硬件和驱动为最终调用系统内核做好准备。

3.启动Linux内核

在内核的启动过程中,会设置缓存、加载驱动等。当内核完成系统设置后,它会在系统文件中寻找 init.rc 文件,解析并启动 init 进程。

Init 进程

基于 Android 12 源码

Android 10 开始 ,Google 对 init 进程进行了重构,将其拆分为 两个阶段

阶段 名称 职责 运行时机
第一阶段 First Stage Init 最基础的初始化:挂载 /dev/proc/sys,准备 selinux,启动 ueventd 内核刚启动,根文件系统为 ramdisk
第二阶段 Second Stage Init 解析 init.rc、启动 zygoteservicemanager等核心服务 第一阶段完成后,通过 execv跳转

在安卓 10 之前,入口函数 int main(int argc, char** argv)/system/core/init/Init.cpp 中,在安卓 12 中main() 函数位于:/system/core/init/main.cpp

Android 12 把早期引导拆成三个阶段:① first-stage init → ② SELinux setup → ③ second-stage init

可以在 system/core/init/README.md中查看分层介绍

/system/core/init/main.cpp:

scss 复制代码
int main(int argc, char** argv) {
    
    // 调试能力,便于在开发/测试阶段发现底层内存问题
    #if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
    #endif
    
    // Boost prio which will be restored later
    // 设置当前进程(PRIO_PROCESS)的调度优先级为 -20(Linux 中优先级范围是 -20 到 19,-20 最高)
    // 启动时临时提升优先级,后续再进行降级(通常是 0)
    setpriority(PRIO_PROCESS, 0, -20);

    // 判断程序是否以 ueventd 名字被调用
    // 如果 init 被软链接为 ueventd(如 /sbin/ueventd),则进入 ueventd_main(),作为 ueventd 运行。
    // 否则继续执行 init 主流程。

    // !strcmp(argv[0], "ueventd") 这种写法就等同于 判断两个字符串是否相同。
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }

    // argc > 1 表示至少有一个参数(argv[0] 是程序名,argv[1] 是第一个参数)
    // init 的行为由参数决定,这是实现"多阶段启动"的关键。
    if (argc > 1) {

        // subcontext 子上下文
        // 相当于初始化程序运行时必要的环境,通常用于运行脚本或服务前的环境准备
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();

            return SubcontextMain(argc, argv, &function_map);
        }

        // selinux_setup 是第一阶段中专门用于 加载和设置 SELinux 策略 的子阶段
        // selinux:强制访问控制(MAC)安全模块,安全看门人,安卓保持安全的关键!
        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }

        // 第二阶段主流程
        // 这是 Android 系统"真正启动"的标志,Zygote 启动后,App 才能被创建。
        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }

    // 第一阶段,如果没有参数,或参数不匹配上述任何一种,默认进入第一阶段。
    return FirstStageMain(argc, argv);
}
  • first-stage init:最小化环境下完成"能把系统盘挂起来"的工作(含 dm-verity/AVB、动态分区、早期内核模块等)。
  • SELinux setup:组合 platform/vendor 的 sepolicy,切到 enforcing,再继续。
  • second-stage init :解析并执行 init 语言(actions/commands/services/options/imports)、启动属性服务与各类系统守护、装载 APEX 后的脚本、拉起 Zygote 等。

一句话概况就是:挂盘→上策略→跑业务。

如果不深入去看,就会发现 main 函数只执行了一次,也就是说 SetupSelinux,SecondStageMain,FirstStageMain 三个函数只会执行一个啊,那么为什么说它们是按顺序执行的?

其实不然,main()方法会被执行三次:

第一次进入 main() → 进入 FirstStageMain()

内核启动后,直接执行 /init。此时 argc == 1argv[1] 不存在(或为 null)。所以 if (argc > 1) 条件不成立,直接跳到最后一行

在 /system/core/init/first_stage_init.cpp 中,有FirstStageMain()的实现,在其最后一行中有这么几行代码:

ini 复制代码
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));
  • execv用新的程序替换当前进程的镜像 ,但保持 PID 不变(还是 1)。
  • 这里它又执行 /init,但传入了参数 "selinux_setup"

第二次进入 main() → 进入 SetupSelinux()

/system/core/init/selinux.cpp 中 的SetupSelinux() 最后同样包含了类似信息:

arduino 复制代码
const char* path = "/system/bin/init";
const char* args[] = {path, "second_stage", nullptr};
execv(path, const_cast<char**>(args));

再次 execv,传入 "second_stage" 参数。

第三次进入 main() → 进入 SecondStageMain()

开始解析 init.rc、启动 zygote 等。

流程大致如下:

scss 复制代码
内核启动
    ↓
执行 /init(main 函数入口)
    ↓
main() → 默认进入 FirstStageMain()  ← 注意:这是第一次进入 main
    ↓
FirstStageMain() 完成基础初始化
    ↓
execv("/init", "selinux_setup", ...)  ← 重新调用自己,传入 "selinux_setup"
    ↓
main() → 因为 argv[1] == "selinux_setup",进入 SetupSelinux()
    ↓
SetupSelinux() 加载 SELinux 策略
    ↓
execv("/init", "second_stage", ...)  ← 再次重新调用自己,传入 "second_stage"
    ↓
main() → 因为 argv[1] == "second_stage",进入 SecondStageMain()
    ↓
SecondStageMain() 启动 zygote、servicemanager 等核心服务
    ↓
系统启动完成

说了一大堆,其实才到关键代码的入口,Android 系统启动的核心,Android 用户空间真正"活起来"的起点。

SecondStageMain(int argc, char** argv)

位于:system/core/init/init.cpp

源码:

c++ 复制代码
int SecondStageMain(int argc, char** argv) {
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
    }

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

    trigger_shutdown = [](const std::string& command) { shutdown_state.TriggerShutdown(command); };

    SetStdioToDevNull(argv);
    // 初始化内核日志
    InitKernelLogging(argv);
    LOG(INFO) << "init second stage started!";

    // Update $PATH in the case the second stage init is newer than first stage init, where it is
    // first set.
    if (setenv("PATH", _PATH_DEFPATH, 1) != 0) {
        PLOG(FATAL) << "Could not set $PATH to '" << _PATH_DEFPATH << "' in second stage";
    }

    // Init should not crash because of a dependence on any other process, therefore we ignore
    // SIGPIPE and handle EPIPE at the call site directly.  Note that setting a signal to SIG_IGN
    // is inherited across exec, but custom signal handlers are not.  Since we do not want to
    // ignore SIGPIPE for child processes, we set a no-op function for the signal handler instead.
    {
        struct sigaction action = {.sa_flags = SA_RESTART};
        action.sa_handler = [](int) {};
        sigaction(SIGPIPE, &action, nullptr);
    }

    // Set init and its forked children's oom_adj.
    // 这行代码将 init 进程(pid=1)的 /proc/1/oom_score_adj 文件写入一个预设的值 
    // DEFAULT_OOM_SCORE_ADJUST。oom_score_adj 用于调整进程在系统内存不足
    //(OOM, Out of Memory)时被杀死的优先级。这里的目的是降低 init 进程被杀死的可能性,
    // 确保系统核心进程的稳定。
    if (auto result =
                WriteFile("/proc/1/oom_score_adj", StringPrintf("%d", DEFAULT_OOM_SCORE_ADJUST));
        !result.ok()) {
        LOG(ERROR) << "Unable to write " << DEFAULT_OOM_SCORE_ADJUST
                   << " to /proc/1/oom_score_adj: " << result.error();
    }

    // Set up a session keyring that all processes will have access to. It
    // will hold things like FBE encryption keys. No process should override
    // its session keyring.
    // 创建会话密钥环
    keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);

    // Indicate that booting is in progress to background fw loaders, etc.
    // 标记系统正在启动中。
    close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));

    // See if need to load debug props to allow adb root, when the device is unlocked.
    const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
    bool load_debug_prop = false;
    if (force_debuggable_env && AvbHandle::IsDeviceUnlocked()) {
        load_debug_prop = "true"s == force_debuggable_env;
    }
    unsetenv("INIT_FORCE_DEBUGGABLE");

    // Umount the debug ramdisk so property service doesn't read .prop files from there, when it
    // is not meant to.
    if (!load_debug_prop) {
        UmountDebugRamdisk();
    }

    // PropertyInit() 负责初始化属性服务所需的内部数据结构。
    // StartPropertyService 则真正启动这个服务。
    // 属性服务是 Android 中一个非常重要的 IPC(进程间通信)机制,其他进程可以通过读取这些
    // 属性来判断系统的状态。
    PropertyInit();
    // 此时开始可以读写系统属性(如 ro.boot.*)

    // Umount second stage resources after property service has read the .prop files.
    UmountSecondStageRes();

    // Umount the debug ramdisk after property service has read the .prop files when it means to.
    if (load_debug_prop) {
        UmountDebugRamdisk();
    }

    // Mount extra filesystems required during second stage init
    MountExtraFilesystems();

    // Now set up SELinux for second stage.
    // SELinux 上下文恢复
    SelinuxSetupKernelLogging();
    SelabelInitialize();
    SelinuxRestoreContext();

    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);

    // Set libavb version for Framework-only OTA match in Treble build.
    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();
    SetKernelVersion();

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

    if (!SetupMountNamespaces()) {
        PLOG(FATAL) << "SetupMountNamespaces failed";
    }

    InitializeSubcontext();

    // 这部分是 init 脚本执行和系统服务启动的引擎。
    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();

    // LoadBootScripts 函数会解析 /init.rc 以及其他相关的 .rc 文件。
    // 这些文件定义了 Android 启动时需要执行的 actions (动作) 和 services (服务)。
    // ActionManager 和 ServiceList 则分别是管理这些动作和服务实例的单例。
    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();

    // Make the GSI status available before scripts start running.
    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);

    // 队列化内置动作和事件触发
    // QueueBuiltinAction 将一些硬编码在 init 源码中的内置动作添加到待执行队列中
    // 例如 SetupCgroupsAction 用于设置进程控制组
    am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
    am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
    am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux");
    am.QueueEventTrigger("early-init");

    // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
    am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
    // ... so that we can start queuing up actions that require stuff from /dev.
    am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
    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");

    // Trigger all the boot actions to get us started.
    am.QueueEventTrigger("init");

    // 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 {
        am.QueueEventTrigger("late-init");
    }

    // Run all property triggers based on current state of the properties.
    am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");

    // Restore prio before main loop
    setpriority(PRIO_PROCESS, 0, 0);

    // 主循环
    while (true) {
        // By default, sleep until something happens.
        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())) {
            am.ExecuteOneCommand();
        }
        if (!IsShuttingDown()) {
            auto next_process_action_time = HandleProcessActions();

            // If there's a process that needs restarting, wake up in time for that.
            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 there's more work to do, wake up again immediately.
            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()) {
            // We always reap children before responding to the other pending functions. This is to
            // prevent a race where other daemons see that a service has exited and ask init to
            // start it again via ctl.start before init has reaped it.
            ReapAnyOutstandingChildren();
            for (const auto& function : *pending_functions) {
                (*function)();
            }
        }
        if (!IsShuttingDown()) {
            HandleControlMessages();
            SetUsbController();
        }
    }

    return 0;
}

关键代码解析:

主循环

c++ 复制代码
while (true) {
    // ...
    am.ExecuteOneCommand();
    // ...
    auto pending_functions = epoll.Wait(epoll_timeout);
    // ...
}

while (true) 循环是 init 的核心。am.ExecuteOneCommand() 每次从动作队列中取出一个命令并执行。epoll.Wait() 是一个高效的I/O多路复用函数,它让 init 进程在没有事件发生时进入休眠状态,以节省 CPU 资源。当有子进程退出、属性值改变或收到控制消息时,epoll 会被唤醒,init 进程随即处理这些事件。这个循环会一直运行,直到系统关机。

init.rc

查看 LoadBootScripts 方法可知

c++ 复制代码
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser = CreateParser(action_manager, service_list);

    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    if (bootscript.empty()) {
        // 如果没有指定自定义 init_rc,则加载默认路径
        parser.ParseConfig("/system/etc/init/hw/init.rc");  // ← 真正的主配置
        parser.ParseConfig("/system/etc/init");             // 加载 system 服务
        parser.ParseConfig("/system_ext/etc/init");         // system_ext
        parser.ParseConfig("/vendor/etc/init");             // 厂商服务
        parser.ParseConfig("/odm/etc/init");                // ODM 服务
        parser.ParseConfig("/product/etc/init");            // 产品服务
    } else {
        // 如果指定了 ro.boot.init_rc,则加载它(用于 recovery 等特殊模式)
        parser.ParseConfig(bootscript);
    }
}

默认解析的 是/system/etc/init/hw/init.rc 而不是其他文章所介绍的 位于 /system/core/rootdir/init.rc(不过这个文件仍存在),这是因为Android 8 开始,Google 把 system/vendor 分离 ,而且为了支持不同硬件,不再把 init.rc 固定在 ramdisk ,而是放到 /system/etc/init/hw/,并且支持 import 进 vendor/product/odm/system_ext 的脚本。

system/core/rootdir/init.rc,不再直接被运行,而是通过 build system 安装到 system 分区 ,运行时路径就是 /system/etc/init/hw/init.rc,这里不做过多介绍。

在 init.rc 中 有 import 导入、on 命令和 service 服务,其中:

import:模块化加载 .rc 文件,用于导入其他 .rc 配置文件,实现配置的模块化和分层管理。

c++ 复制代码
# 导入硬件相关的配置(如高通、MTK)
import /init.${ro.hardware}.rc

# 导入 USB 相关配置
import /init.usb.rc

# 导入 zygote 启动配置(根据设备类型)
import /init.${ro.zygote}.rc    # 如 init.zygote64_32.rc

on:事件触发器(Actions),on 定义动作(Action) ,当某个条件满足时,执行一系列命令。

c++ 复制代码
on early-init
    # 设置关键目录
    mkdir /dev/socket 0755

on init
    # 挂载 tmpfs
    mount tmpfs tmpfs /dev tmpfs mode=0755

on late-init
    # 触发后续阶段
    trigger early-fs
    trigger fs
    trigger post-fs
    trigger late-fs
    trigger post-fs-data
    trigger boot

on property:vold.decrypt=trigger_restart_framework
    # 当加密分区解密完成,重启 framework
    class_start main
    class_start late_start

on property:sys.boot_completed=1
    # 系统启动完成,启动 bootanim(开机动画结束)
    stop bootanim

service:定义长期运行的守护进程,service 用于声明一个系统服务init 进程会负责启动、监控和重启它。

c++ 复制代码
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 exec_background - system system -- /system/bin/vdc volume abort_fuse
    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
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

使用 CreateParser 创建一个 Parser,通过解析.rc 文件中的指令 name,来解析具体的命令。

c++ 复制代码
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;
}

关于 init.rc 更详细的介绍可以看看这篇文章:安卓11 init初始化以及init.rc的解析执行过程详解

解析器关键代码,前面的文件夹判断及其他条件判断省略:

c++ 复制代码
void Parser::ParseData(const std::string& filename, std::string* data) {
    // 在数据末尾添加换行符和空终止符,确保解析器能正确识别最后一行
    data->push_back('\n');
    data->push_back('\0');

    // 解析状态结构体,记录当前解析位置、行号、下一个 token 类型
    parse_state state;
    state.line = 0;
    state.ptr = data->data();  // 指向数据起始位置
    state.nexttoken = 0;

    SectionParser* section_parser = nullptr;  // 当前正在处理的"段"解析器(如 service、on)
    int section_start_line = -1;              // 当前段的起始行号(用于报错)
    std::vector<std::string> args;            // 存储当前行拆分出的 tokens(命令和参数)

    // 标记是否遇到了无效的段声明,用于跳过错误直到下一个有效段
    bool bad_section_found = false;

    // Lambda:结束当前段的处理
    auto end_section = [&] {
        bad_section_found = false;
        if (section_parser == nullptr) return;

        // 通知当前段解析器:本段结束,进行收尾工作(如提交 service 配置)
        if (auto result = section_parser->EndSection(); !result.ok()) {
            parse_error_count_++;
            LOG(ERROR) << filename << ": " << section_start_line << ": " << result.error();
        }

        section_parser = nullptr;
        section_start_line = -1;
    };

    // 主循环:逐 token 解析文件
    for (;;) {
        switch (next_token(&state)) {
            case T_EOF:
                // 文件结束:结束当前段,并通知所有 SectionParser 文件解析完成
                end_section();

                // 通知所有注册的 SectionParser:整个文件已解析完毕
                for (const auto& [section_name, section_parser] : section_parsers_) {
                    section_parser->EndFile();
                }
                return;

            case T_NEWLINE:
                state.line++;  // 行号递增
                if (args.empty()) break;  // 空行,跳过

                // 1. 处理特殊行前缀(如 /sys/、/dev/),用于 uevent 规则(非主流用法)
                auto line_callback = std::find_if(
                    line_callbacks_.begin(), line_callbacks_.end(),
                    [&args](const auto& c) { return android::base::StartsWith(args[0], c.first); });
                if (line_callback != line_callbacks_.end()) {
                    end_section();  // 先结束可能的旧段

                    // 执行行回调(如处理设备节点规则)
                    if (auto result = line_callback->second(std::move(args)); !result.ok()) {
                        parse_error_count_++;
                        LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
                    }

                // 2. 如果当前行是"段开始"(如 service、on、import)
                //    检查是否在 section_parsers_ 注册表中
                } else if (section_parsers_.count(args[0])) {
                    end_section();  // 结束上一个段(防止嵌套)

                    section_parser = section_parsers_[args[0]].get();
                    section_start_line = state.line;

                    // 调用该段解析器的 ParseSection(),处理段头(如 service zygote /system/bin/app_process...)
                    if (auto result = section_parser->ParseSection(std::move(args), filename, state.line);
                        !result.ok()) {
                        parse_error_count_++;
                        LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
                        section_parser = nullptr;
                        bad_section_found = true;  // 标记错误段,后续行跳过直到新段
                    }

                // 3. 如果当前处于某个段内部(如 on boot 的后续命令行)
                } else if (section_parser) {
                    // 调用该段解析器的 ParseLineSection(),处理段内行(如 start、setprop 等命令)
                    if (auto result = section_parser->ParseLineSection(std::move(args), state.line);
                        !result.ok()) {
                        parse_error_count_++;
                        LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
                    }

                // 4. 既不是段开始,也不在段内,且之前没发现错误段 → 语法错误
                } else if (!bad_section_found) {
                    parse_error_count_++;
                    LOG(ERROR) << filename << ": " << state.line
                               << ": Invalid section keyword found";
                }

                args.clear();  // 清空当前行参数,准备下一行
                break;

            case T_TEXT:
                // 读取到文本 token,加入当前行参数列表
                args.emplace_back(state.text);
                break;
        }
    }
}

再回到上面的 main()方法:

c++ 复制代码
int main(int argc, char** argv) {
    // ... 初始化
    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();

    // 1. 解析 .rc 文件 → 填充 am 和 sm
    LoadBootScripts(am, sm);

    // 2. 进入主循环,开始执行
    while (true) {
        // 执行可运行的 Actions
        am.ExecuteOneCommand();
        // 处理其他事件(epoll、属性、子进程等)
        epoll.Wait();
    }
}

init.rcParserActionManager/ServiceListEvent TriggerExecuteOneCommandfork/exec → 服务启动

对比老的安卓系统,可以看出 google 在源码上做了大量优化,虽然之前的文章可能解释不了新的源码,但是它们的核心逻辑变化不大,新的代码只是兼容性和扩展性更强了。

说真的,写到现在我还是懵的,这篇文章就算对 安卓启动的初窥门径吧,先了解个大概。

相关推荐
技术liul1 小时前
使用安卓平板,通过USB数据线(而不是Wi-Fi)来控制电脑(版本1)
android·stm32·电脑
2501_916007473 小时前
iOS App 上架实战 从内测到应用商店发布的全周期流程解析
android·ios·小程序·https·uni-app·iphone·webview
TimeFine3 小时前
Android 邮件发送日志
android
杨过过儿3 小时前
【Task02】:四步构建简单rag(第一章3节)
android·java·数据库
Wgllss4 小时前
Kotlin 享元设计模式详解 和对象池及在内存优化中的几种案例和应用场景
android·架构·android jetpack
zzywxc7876 小时前
AI 行业应用:金融、医疗、教育、制造业领域的落地案例与技术实现
android·前端·人工智能·chrome·金融·rxjava
sTone873756 小时前
android studio之外使用NDK编译生成android指定架构的动态库
android·c++
胖虎17 小时前
Android 入门到实战(三):ViewPager及ViewPager2多页面布局
android·viewpager·viewpager2
风往哪边走8 小时前
Media3在线本地视频播放器
android