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 在源码上做了大量优化,虽然之前的文章可能解释不了新的源码,但是它们的核心逻辑变化不大,新的代码只是兼容性和扩展性更强了。

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

相关推荐
阿巴斯甜1 天前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker1 天前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95271 天前
Andorid Google 登录接入文档
android
黄林晴1 天前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab2 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿2 天前
Android MediaPlayer 笔记
android
Jony_2 天前
Android 启动优化方案
android
阿巴斯甜2 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇2 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_2 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android