当前位置: 首页 > news >正文

system\core\init\init.cpp----LoadBootScripts()解析init.rc(1)

关于 Android 中 init.rc 文件的位置

这是一个非常重要的问题。如果 /system/etc/init/hw/init.rc 目录或文件不存在,Android 系统会按照特定的优先级和回退机制在其他位置查找 init.rc 文件。

标准查找顺序

根据 Android 系统设计,init 进程会按以下顺序查找 init.rc 文件:

  1. 首选位置/system/etc/init/hw/init.rc

    • 这是现代 Android 版本(约 Android 7.0+)的标准位置

    • 对应 AOSP 源码中的 system/core/rootdir/init.rc

  2. 传统位置/init.rc(根目录下的 init.rc)

    • 这是更早期 Android 版本使用的传统位置

    • 在某些定制 ROM 或嵌入式设备中可能仍然使用

好的,这是一段来自 Android 系统初始化进程 init 的代码,主要负责在系统启动时加载和解析各种初始化脚本(.rc 文件)。下面我将用中文为你逐部分详细解释。

函数概述

c++

static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list)
  • 函数名: LoadBootScripts (加载启动脚本)

  • 作用: 这是 Android 启动过程中非常关键的一步,它负责读取系统各个分区中的 .rc 配置文件,并将这些文件中定义的动作 (Actions) 和服务 (Services) 注册到管理器中,后续 init 进程会根据这些配置来执行命令、启动守护进程和服务。

  • 参数

    • action_manager: 动作管理器的引用,解析到的动作(例如:on booton early-init)会添加到这里。

    • service_list: 服务列表的引用,解析到的服务(例如:service zygote /system/bin/app_process ...)会添加到这里。


代码逐行详解

1. 创建解析器 (Parser)

c++

Parser parser = CreateParser(action_manager, service_list);
  • 这行代码调用 CreateParser 函数创建了一个配置解析器 (parser)。

  • 这个解析器内部预先定义好了如何解析 init.rc 语言的语法(如 onserviceimporttrigger 等关键字),并将解析结果直接填充到传入的 action_manager 和 service_list 中。

2. 检查自定义启动脚本属性

c++

std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {// 正常启动流程...
} else {parser.ParseConfig(bootscript);
}
  • ro.boot.init_rc 是一个 Android 系统属性,通常由 bootloader 在启动内核时通过命令行 (cmdline) 传入。

  • 这段代码的逻辑是

    • 如果该属性为空:走正常的、默认的启动脚本加载流程(即后面的 if 块)。

    • 如果该属性不为空:意味着提供了一个自定义的启动脚本路径,系统将只解析这个指定的脚本,而跳过所有默认的配置。这在调试特殊启动模式下非常有用。

3. 默认启动流程 (if 块内的内容)

当没有自定义脚本时,执行默认加载顺序。

c++

parser.ParseConfig("/system/etc/init/hw/init.rc");
  • 这是最核心、最基础的启动脚本。它定义了整个 Android 系统启动最根本的步骤和服务,例如 zygote(Android 应用进程的孵化器)、servicemanager(Binder 通信的核心服务)等通常都在这里定义。

c++

if (!parser.ParseConfig("/system/etc/init")) {late_import_paths.emplace_back("/system/etc/init");
}
  • 这行代码尝试解析 /system/etc/init/ 目录下的所有 .rc 文件。

  • if (!parser.ParseConfig(...)) 的逻辑:

    • 如果解析成功(目录存在且有文件),函数返回 true!true 为 false,条件不成立。

    • 如果解析失败(例如目录不存在或没有文件),函数返回 false!false 为 true,条件成立。

  • 条件成立后会执行late_import_paths.emplace_back("/system/etc/init");

    • 这意味着将 /system/etc/init 这个路径加入到一个叫 late_import_paths(延迟导入路径)的列表中。

    • 为什么需要延迟导入? 这是因为在 Android 启动的早期阶段,/system 分区可能还没有被挂载为可写(rw),导致无法读取其中的配置。系统会先继续执行其他操作,等到合适的时机(例如 fs 触发器)再回过头来尝试加载这些之前失败路径下的配置。

接下来的几行代码逻辑完全相同,只是针对不同的分区:

c++

parser.ParseConfig("/system_ext/etc/init");
  • 解析 System Extension 分区的配置。OEM/厂商可以在这里放置一些扩展功能配置,这些配置介于 AOSP 通用系统和自家定制功能之间。

c++

if (!parser.ParseConfig("/product/etc/init")) {late_import_paths.emplace_back("/product/etc/init");
}
  • 解析 Product 分区的配置。用于配置与特定产品型号相关的功能。

c++

if (!parser.ParseConfig("/odm/etc/init")) {late_import_paths.emplace_back("/odm/etc/init");
}
  • 解析 ODM 分区的配置。ODM 是为不同 OEM 提供硬件适配的厂商,这里存放与特定硬件板级相关的配置。

c++

if (!parser.ParseConfig("/vendor/etc/init")) {late_import_paths.emplace_back("/vendor/etc/init");
}
  • 解析 Vendor 分区的配置。这是 OEM/厂商放置其私有定制、硬件相关服务和功能的主要地方。

4. 关于延迟导入 (late_import) 的注释

c++

// 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.
  • 这段注释说明:late_import 这个机制只在 Android Q (10) 及更早的版本中有效。

  • 因为在 Android Q 时还没有 system_ext 分区,所以代码里对 system_ext 的解析 (parser.ParseConfig("/system_ext/etc/init");) 没有使用延迟导入逻辑,直接解析,能成则成,不成就算了。

总结

这段代码清晰地展示了 Android 启动脚本的加载策略和优先级

  1. 最高优先级: 由 ro.boot.init_rc 属性指定的自定义脚本(用于调试和特殊模式)。

  2. 默认优先级(从高到低)

    1. 核心: /system/etc/init/hw/init.rc (必选)

    2. 系统: /system/etc/init/ (可延迟)

    3. 系统扩展: /system_ext/etc/init/ (直接解析,不延迟)

    4. 产品: /product/etc/init/ (可延迟)

    5. 硬件适配: /odm/etc/init/ (可延迟)

    6. 厂商: /vendor/etc/init/ (可延迟)

这种分层结构使得 AOSP、芯片厂商(ODM)、设备制造商(OEM)都可以在不修改核心文件 init.rc 的前提下,在自己的分区添加和修改启动行为,实现了高度的模块化和可定制性。延迟导入机制则保证了即使某些分区尚未准备好,也不会阻塞启动流程。

http://www.dtcms.com/a/342101.html

相关文章:

  • STM32之串口详解
  • 学习Linux嵌入式(正点原子imx课程)开发到底是在学什么
  • Spring Cloud Netflix学习笔记06-Zuul
  • Kafka消息持久化机制全解析:存储原理与实战场景
  • Kafka集成Flume
  • 人工智能 -- 循环神经网络day1 -- 自然语言基础、NLP基础概率、NLP基本流程、NLP特征工程、NLP特征输入
  • 算法 之 拓 扑 排 序
  • LeetCode 回文链表
  • 桥梁设计模式
  • RabbitMQ事务消息原理是什么
  • RabbitMQ:延时消息(死信交换机、延迟消息插件)
  • 领域专用AI模型训练指南:医疗、法律、金融三大垂直领域微调效果对比
  • 28、工业网络资产漏洞扫描与风险评估 (模拟) - /安全与维护组件/industrial-network-scanner
  • 深度解析Atlassian 团队协作套件(Jira、Confluence、Loom、Rovo)如何赋能全球分布式团队协作
  • Whisk for Mac 网页编辑器 PHP开发
  • 牛客:链表的回文结构详解
  • NewsNow搭建喂饭级教程
  • SQL中对视图的操作命令汇总
  • STM32H750 CoreMark跑分测试
  • [最新]Dify v1.7.2版本更新:工作流可视化和节点搜索
  • 2025 年 8 月《GPT-5 家族 SQL 能力评测报告》发布
  • SQL视图、存储过程和触发器
  • OBCP第四章 OceanBase SQL 调优学习笔记:通俗解读与实践指南
  • CentOS 7安装FFmpeg
  • QT QProcess, WinExec, ShellExecute中文路径带空格程序或者脚本执行并带参数
  • Qt实现TabWidget通过addTab函数添加的页,页内控件自适应窗口大小
  • Qt文件压缩工具项目开发教程
  • 【Bug】CentOS 7 使用vim命令报错vim: command not found
  • 开源 C++ QT Widget 开发(四)文件--二进制文件查看编辑
  • Elasticsearch官方文档学习-未完待续