Android 源码学习之init进程

Boot ROM - Boot Read-Only-Memory

在AOSP源码中,system/core/init/main.cpp 里的 main 函数是整个Android用户空间的起点 。它是在Linux内核启动完成后,由内核直接调用的第一个也是唯一一个用户空间进程

具体时机和调用链条如下:

graph TB subgraph A["Linux 内核启动流程 (kernel/init/main.c)"] A1["start_kernel()"] --> A2["arch_call_rest_init()"] A2 --> A3["rest_init()"] A3 --> A4["kernel_init()"] end subgraph B["关键函数说明"] A1 --> B1["内核主入口点<br/>完成核心子系统初始化<br/>内存管理、调度器、中断等"] A2 --> B2["体系结构相关的<br/>rest_init调用点"] A3 --> B3["创建关键内核线程<br/>- 启动kernel_init(PID=1)<br/>- 启动kthreadd(PID=2)<br/>- 进入idle循环"] A4 --> B4["内核初始化线程<br/>准备用户空间环境<br/>最终执行用户空间init进程"] end subgraph C["与Android的关系"] A4 --> C1["通过execve执行<br/>/system/bin/init"] C1 --> C2["Android init进程<br/>system/core/init/main.cpp"] C2 --> C3["main()"] C3 --> C4["FirstStageMain()"] end subgraph D["关键函数说明"] C3 --> D1["init进程代码入口"] end style A fill:#e1f5fe style B fill:#f3e5f5 style C fill:#e8f5e8 style A1 fill:#ffeb3b style A4 fill:#ff9800

调用时机

  1. Linux内核启动:设备上电后,Bootloader会加载Linux内核到内存并启动它。
  2. 内核初始化:内核进行自身的一系列初始化工作,包括驱动、内存管理等。
  3. 挂载根文件系统 :内核挂载初始RAM磁盘(initramfs)或者(在Android中常见的)直接挂载系统分区作为根文件系统。
  4. 启动第一个用户空间进程 :内核在完成所有核心初始化后,会尝试执行一个名为 init 的程序。这个程序的路径是在内核编译时指定的,通常就是根文件系统下的 /init

调用过程

这个调用过程是由内核代码直接写死的,其逻辑大致如下:

  1. 内核入口点 :在内核源码的 init/main.c 中,kernel_init 函数负责启动第一个用户空间进程。
  2. 尝试执行 :内核会尝试执行 /sbin/init/etc/init/bin/init 等路径。
  3. 回退方案 :如果上述路径都失败了,内核会尝试执行 /bin/sh 作为回退。
  4. 在Android中的情况 :在AOSP编译后,生成的 init 可执行文件被直接放置在了根文件系统的根目录下,即 /init。因此,内核会成功找到并执行它。

这个 /init 程序,就是由 system/core/init/ 目录下的源码编译而成的。

main.cpp 中的 main 函数

所以,main 函数的调用时机非常明确:在Linux内核完成自身初始化,并准备将控制权交给用户空间的那一刻,由内核直接调用。

它的执行流程可以简化为:

cpp 复制代码
// system/core/init/main.cpp

int main(int argc, char** argv) {
    // 1. 处理内核命令行参数,例如 `androidboot.selinux=permissive`
    // 2. 创建必要的目录并挂载文件系统 (如 /dev, /proc, /sys 等)
    // 3. 初始化 Kernel Logging (kmsg)
    // 4. 进行第一次阶段初始化 (First Stage Mount) - 主要在 recovery 或 ramdisk 环境中
    // 5. 如果不是在 First Stage,则执行核心的 init 逻辑
    return FirstStageMain(argc, argv); // 或者 SecondStageMain(argv)
}

在现代Android系统中(尤其是使用了动态分区和A/B更新的设备),init的启动被分成了多个阶段:

  • First Stage Init :在内核还挂载着初始 rootfs 时运行,主要负责挂载真正的系统分区、vendor分区等,并为第二阶段的init设置好环境。
  • Second Stage Init :在必要的分区被挂载后,系统会 execv 重新执行位于新系统分区上的 /system/bin/init,进入第二阶段。这个阶段会建立完整的Android运行环境,包括启动属性服务、解析init.rc脚本、启动守护进程、Zygote等。

总结

项目 说明
调用者 Linux 内核
调用时机 内核完成所有内部初始化之后,准备切换到用户空间时
调用方式 内核通过execve 系统调用执行根文件系统中的 /init 程序
程序路径 在设备根文件系统中为/init,在AOSP源码中位于 system/core/init/

因此,init 进程的PID永远是1,它是所有其他用户空间进程的祖先进程。它的 main 函数是Android系统用户空间的绝对起点。

---- 后续讲解FirstStageMain()相关流程----

相关推荐
敲代码的瓦龙21 分钟前
Jetpack?ViewModel!!!
android·开发语言·kotlin·android-studio
白远山25 分钟前
智慧场馆解决方案软件开发实战:从架构设计到落地部署指南
java·开发语言·架构·需求分析
m0_5873830040 分钟前
折扣卡CPS软件开发实战:从系统架构设计到上线指南
java·小程序·架构·需求分析
Dawson Zhu1 小时前
基于 OKF 知识图谱的 Text2SQL 领域知识注入实践——半导体晶圆厂数据资产知识库 MVP 剖析
人工智能·语言模型·架构·aigc·agi
Godikov1 小时前
Android 工控终端实战:从秒级卡顿到毫秒响应,SQLite/LitePal 性能优化全记录
android
晚安日记wanna1 小时前
批量请求失败只弹一个 Toast面试官想听五层
前端·面试·架构
大模型码小白1 小时前
告别造假数据,直接连数据库查真实时序数据喂给 TimechoAI 大模型
java·数据库·人工智能·microsoft·架构
晚安日记wanna1 小时前
大表 DDL 面试翻车现场Online DDL 为什么还会锁死业务
数据库·面试·架构
晚安日记wanna1 小时前
MySQL 主从延迟别只答并行复制
数据库·面试·架构
狼与自由2 小时前
MCP协议理解
人工智能·架构