上电加载—>init进程启动可以参考 Android 最新最全面启动流程分析(含 TEE、安全验证等)

一、init程序源码和构建

在源码中init程序代码位于/system/core/init,其编译文件Android.bp: init.rc等文件都在/system/core/rootdir中.

//这里init_second_stage容易迷惑人,实际上它包含了first_stage逻辑
cc_defaults {
    name: "init_second_stage_defaults",
    stem: "init",
    defaults: ["init_defaults"],
    srcs: ["main.cpp"],
    symlinks: ["ueventd"],
}
cc_binary {
    name: "init_second_stage",
    defaults: ["init_second_stage_defaults"],
}

构建系统会将rootdir下的rc文件和init程序打包进init_boot.img镜像中,内核启动后就会加载init_boot执行其中的init程序。


二、init程序执行流程

1、init程序的入口main.cpp(/system/core/init/main.cpp)
//init进程分阶段,刚开始,可以看到有五条分支,第一次进入内核不带参数,所以进入FirstStageMain
int main(int argc, char** argv) {
    setpriority(PRIO_PROCESS, 0, -20);
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }
    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            //.....
            return SubcontextMain(argc, argv, &function_map);
        }
        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }
        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }
    return FirstStageMain(argc, argv);
}    
2、FirstStageMain 第一阶段初始化(/system/core/init/first_stage_init.cpp)
int FirstStageMain(int argc, char** argv) {
    //设置环境变量
    setenv("PATH", _PATH_DEFPATH, 1)
    //构建初始文件系统tmpfs(内存中),创建基础文件目录
    mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755")
    ...
    //获取cmdline、bootconfig
    android::base::ReadFileToString("/proc/cmdline", &cmdline);
    android::base::ReadFileToString("/proc/bootconfig", &bootconfig);
    ...
    //从cmdline、bootconfig中获取BOOT模式(充电、recovery,正常)
    BootMode boot_mode = GetBootMode(cmdline, bootconfig);
    //根据模式去加载不同内核模块
    LoadKernelModules(boot_mode, want_console,
                           want_parallel, module_count) 
    //执行第一阶段文件系统挂载,最主要是/system挂载
    fsm->DoFirstStageMount();    
    ...
    const char* path = "/system/bin/init";
    const char* args[] = {path, "selinux_setup", nullptr};
    ...
    execv(path, const_cast<char**>(args));
}

在/system挂载后,执行了/system/bin/init,其实这个init和init_boot中是同一个,只是放在了两个镜像中,本质都是同一份代码构建的,所以启动/system/bin/init,就相当于启动/init自身,execv 是一个系统调用,传入参数selinux_setup,当前进程的代码、数据、堆栈被替换,进程ID不变,可以理解为init自己调用自己。

3、执行selinux_setup (/system/core/init/main.cpp)
int main(int argc, char** argv){
    ....
    return SetupSelinux(argv);
    ...
}
SetupSelinux执行(/system/core/init/selinux.cpp)
int SetupSelinux(char** argv) {
    ...
    //加载 selinux 策略
    //1、内部先挂在其他没有挂载好的分区MountMissingSystemPartitions();
    //2、读取所有分区的策略文件 ReadPolicy(&policy);
    //3、加载策略LoadSelinuxPolicy(policy);
         //配置selinux挂载路径
         // set_selinuxmnt("/sys/fs/selinux");
         //正式加载,会调用内核
         // security_load_policy(policy.data(), policy.size()
    LoadSelinuxPolicyAndroid();
    //配置selinux为enforce模式,强制模式
    SelinuxSetEnforcement();
    //重置init执行文件的selinux上下文
    selinux_android_restorecon("/system/bin/init", 0);
    //进入second_stage
    const char* path = "/system/bin/init";
    const char* args[] = {path, "second_stage", nullptr};
    execv(path, const_cast<char**>(args));

}
4、执行second_stage (/system/core/init/main.cpp)
int main(int argc, char** argv){
    ....
    return SecondStageMain(argv);
    ...
}
SecondStageMain执行(/system/core/init/init.cpp)
int SecondStageMain(int argc, char** argv) {
    //一、selinux属性上下文初始化:PropertyInit();
    //1、配置selinux权限检查回调
    selinux_set_callback(SELINUX_CB_AUDIT, cb);
    //2、创建属性设备节点 mkdir("/dev/__properties__")
    mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
    //3、加载各分区中的selinux属性上下文
    LoadPropertyInfoFromFile("分区/etc/selinux/plat_property_contexts"
    //4、将属性上下文写入/dev/__properties__/property_info),它自身的文件上下文为u:object_r:default_prop:s0
    WriteStringToFile(serialized_contexts, "/dev/__properties__/property_info", 0444, 0, 0, false)
    ----------------------------
    //二、系统属性系统
    //初始化系统属性区域,实际调用代码/bioinc/libc/system_properties/system_properties.cpp--->SystemProperties::AreaInit
        //内部会读取上面写入的property_info
        //然后mmap申请一块匿名内存,在这块内存中创建上下文节点列表
        //创建/dev/__properties__/properties_serial
        //将properties_serial通过mmap映射到内存
    __system_property_area_init();

    //提取设备树、cmdline、bootconfig中的属性信息
    ProcessKernelDt();
    ProcessKernelCmdline();
    ProcessBootconfig();
    //配置kernelbootprop属性信息,就是给上面没获取到的关键属性赋默认值,获取到的就忽略
    ExportKernelBootProps();
    //读取从各分区的xxx.prop,加入属性列表
    PropertyLoadBootDefaults();
    //读取自定义属性,加入属性列表
    PropertyLoadDerivedDefaults();
    //以上添加属性都是通过__system_property_find先查找
    //如果存在就__system_property_update, 不存在就__system_property_add
    //实际调用/bioinc/libc/system_properties/system_properties.cpp--->SystemProperties::Update|Add
    //实际添加到mmap内存区域,也就是/dev/__properties__/properties_serial中
    ----------------
    //挂载扩展文件系统,主要是将tmpfs挂载到/apex,为后续挂载做准备
    MountExtraFilesystems();

    //selinux标签初始化,就是将所有关键目录加上selinux标签,并且恢复到policy定义的状态
    SelabelInitialize();
    SelinuxRestoreContext();

    //注册信号监听处理,处理子进程的退出,还有fork后的回调
    InstallSignalFdHandler(&epoll);
    //处理线程通知,通过eventfd(0)来处理其他线程发来的通知
    InstallInitNotifier(&epoll);

    //启动属性服务
    //调用property_service.cpp的StartPropertyService
        //1.初始化版本InitPropertySet("ro.property_service.version", "2");
        //2.开启两个线程打开socket,放入epoll监听(一个给系统用property_service_for_system,一个给普通程序用property_service)
        //3.有写入属性的请求会回调handle_property_set_fd,还是通过上面的方式写入到/dev/__properties__/properties_serial。
        //4.在epoll中还监听了init自身的socket,处理函数HandleInitSocket,用来处理PersistentProperties这种重新也生效的属性
    StartPropertyService(&property_fd);

    ----------
    //初始化init子环境,该方法会fork一个进程执行一些特权操作,这样不破坏主init进程环境
    //对应入口main.cpp---> return SubcontextMain(argc, argv, &function_map); ,子进程通过socketpair和init主进程通信
    InitializeSubcontext();

    ------------

    //创建动作管理和服务列表
    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();
    //加载启动脚本
        //创建解析器Parser parser = CreateParser(action_manager, service_list);
        //解析各个分区下 /分区/etc/init 目录中的rc文件
        //am将各种action按先后顺序入队列
    LoadBootScripts(am, sm);

    while(true){
        ....
        //处理关机命令
        HandlePowerctlMessage(*shutdown_command);
        //执行rc脚本
        am.ExecuteOneCommand()
        ....
        //epoll定时唤醒,或者有上面监听的fd写入也会唤醒
        auto epoll_result = epoll.Wait(epoll_timeout);
        if (!IsShuttingDown()) {
            //处理外部控制命令,如开启start、停止stop、重启resart 那些rc中注册的服务
            HandleControlMessages();
            //设置usb控制
            SetUsbController();
        }
    }
}
5、init..rc执行 (/system/core/rootdir/init..rc)

后面所有进程的启动就需要查看init.*.rc了。

android启动rc文件.drawio

  • import示例
#init.rc
import /init.environ.rc

#init.environ.rc
on early-init
    export ANDROID_BOOTLOGO 1
    .....
  • action示例

    其中on是固定写法,early-init为触发条件,export …为命令行

#init.environ.rc
on early-init
    export ANDROID_BOOTLOGO 1
  • service示例

    其中service固定写法, zygote名称 ,/…为程序路径,后面的是参数 第二行起就是程序的配置项

#init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
   class main
   priority -20
   user root
  • 下面枚举了绝大部分触发条件和命令,以及service相关的配置
aticon触发类型 实际条目
boot阶段触发器 on early-init- 在早期初始化阶段
on init- 在初始化阶段
on late-init- 在后期初始化阶段
on post-fs- 文件系统挂载后
on post-fs-data- 数据分区挂载后
on boot- 系统启动完成时
on charger- 充电模式启动时
​属性变化触发器 on property:<key>=<value>- 当指定属性值匹配时触发
on property:<key>=*- 当属性值发生变化时触发(不检查具体值)
设备相关触发器 on device-added-<path>- 当设备节点添加时
on device-removed-<path>- 当设备节点移除时
文件系统触发器 on fs- 文件系统挂载时
on zygote-start- Zygote进程启动时
​其他触发器​ on early-boot- 早期启动阶段
on nonencrypted- 当设备未加密时
on load_persist_props- 加载持久属性时
on load_all_props- 加载所有属性时
on firmware_mounts_complete- 固件挂载完成时
可用命令类型 实际命令
进程管理​ start <service>- 启动指定服务
stop <service>- 停止指定服务
restart <service>- 重启指定服务
exec [ <seclabel> [ <user> [ <group>\* ] ] ] -- <command> [ <argument>\* ]- 执行命令并替换当前进程
文件系统操作 mkdir <path> [mode] [owner] [group]- 创建目录
symlink <target> <path>- 创建符号链接
write <path> <content>- 向文件写入内容
copy <src> <dst>- 复制文件
chown <owner> <group> <path>- 更改文件所有者
chmod <mode> <path>- 更改文件权限
restorecon <path>- 恢复SELinux上下文
restorecon_recursive <path>- 递归恢复SELinux上下文
​属性操作 setprop <name> <value>- 设置系统属性
trigger <event>- 触发另一个事件
设备操作 insmod <path>- 加载内核模块
rmmod <name>- 移除内核模块
setrlimit <resource> <cur> <max>- 设置资源限制
系统控制 class_start <classname>- 启动指定类别的所有服务
class_stop <classname>- 停止指定类别的所有服务
class_reset <classname>- 重置指定类别的所有服务
domainname <name>- 设置域名
hostname <name>- 设置主机名
mount <type> <device> <dir> [ <flag>\* ] [<options>]- 挂载文件系统
umount <path>- 卸载文件系统
swapon_all <fstab>- 启用所有交换分区
wait <path> [ <timeout> ]- 等待文件存在
wait_for_prop <name> <value>- 等待属性值匹配
日志和调试 loglevel <level>- 设置内核日志级别
load_all_props- 加载所有属性文件
load_persist_props- 加载持久属性
​安全相关**** setcon <context>- 设置当前SELinux上下文
setenforce <0\|1>- 设置SELinux强制模式
setkey <keycode> <value>- 设置键盘映射
****电源管理​ powerctl- 电源控制命令
service配置类型 实际options
执行控制选项
disabled - 服务不随class自动启动,必须显式启动
oneshot - 服务退出后不自动重启
onrestart - 当服务重启时执行一个命令
critical - 关键服务,频繁崩溃会触发系统恢复
restart_periodic <seconds> - 周期性重启策略
shutdown <shutdown_behavior> - 设置关机行为
onrestart - 服务重启时执行的命令
用户与权限类
用户和组配置 user <username> - 运行身份(如 system, root
group <group> [附加组...] - 主组和附加组
supplementarygids <gid...> - 补充组ID(如 supplementarygids 1000 1001
capabilities <cap...> - Linux Capabilities(如 capabilities NET_ADMIN SYS_ADMIN
seclabel <SELinux上下文> - 强制SELinux标签(如 seclabel u:r:hal_bluetooth:s0
namespace <pid|mnt|net> - 进入命名空间(如 namespace net
资源限制
rlimit <resource> <cur> <max> - 设置资源限制
常见资源类型: 1. cpu - CPU时间(秒) 2. nofile - 文件描述符数量 3. memlock - 锁定内存大小 4. nproc - 最大进程数
安全配置
priority <priority> - 设置调度优先级(-20到19)
ioprio <class> <0-7> - I/O调度优先级
class类型: 0:none 1:realtime 2:best-effort(默认) 3:idle
文件与通信类
socket <名称> <类型> <权限> [user] [group] [seclabel]
类型:stream/dgram/seqpacket
示例:socket mysocket dgram 660 root system
file <路径> <r|w|rw> - 预打开文件(如 file /data/log.txt rw
writepid <文件...> - 写入PID到文件(如 writepid /dev/cpuset/foreground/tasks
环境配置
env <key> <value> - 设置环境变量
console - 允许服务使用控制台(已废弃,Android 10+移除)
logd - 重定向输出到logd(替代 console
其他重要选项
重启控制 class <name> - 指定服务类别
task_profiles <配置文件...> - 关联cgroup配置文件
override - 覆盖同名的已定义服务
memcg.swappiness <值> - 控制内存交换行为
reboot_on_failure <目标> - 自定义崩溃时重启目标(如 reboot_on_failure bootloader
class <name>
​core​​ - 核心系统服务 最基本的系统服务
通常在早期启动阶段启动
示例:ueventd(设备节点管理)、logd(日志服务)
​main​​ - 主要系统服务 系统正常运行所需的主要服务
在核心服务之后启动
示例:servicemanager(Binder IPC)、surfaceflinger(图形合成)
late_start​​ - 延迟启动服务 在系统基本功能就绪后启动
通常用于不紧急的服务或第三方服务
示例:一些厂商定制服务
****charger​​ - 充电模式服务 仅在设备处于充电模式时启动
用于显示充电界面和状态
示例:charger服务
​boot​​ - 启动类服务 与系统启动过程相关的服务
示例:bootanim(启动动画)
****post-boot​​ - 启动后服务 在系统完成主要启动后运行
用于优化或维护任务
****hal​​ - 硬件抽象层服务 与硬件交互的服务
示例:各种HIDL/ AIDL HAL服务
****apex​​ - APEX模块服务 Android APEX模块提供的服务
****vnd​​ - 供应商特定服务 设备制造商提供的专有服务
**​early_hal` - 早期HAL服务 需要在其他服务之前启动的HAL服务

 

6、核心rc文件解析 (/system/core/rootdir/init.rc)
#配置一些必要的环境变量,导入硬件驱动服务
import /init.environ.rc
import /system/etc/init/hw/init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /system/etc/init/hw/init.usb.configfs.rc
import /system/etc/init/hw/init.${ro.zygote}.rc
.....
on init 
    .....
    # 也就是上面导入的其中三个servicemanager服务,在init阶段会启动,这三个服务是binder核心管理服务
    start servicemanager
    start hwservicemanager
    start vndservicemanager

#在late-init阶段执行fs文件系统的初始化
#early-init→ init→ late-init(early-fs→ fs→ post-fs→ post-fs-data...)
on late-init
    trigger early-fs
    trigger fs
    trigger post-fs
    trigger late-fs
    trigger post-fs-data
    trigger load-bpf-programs
    trigger bpf-progs-loaded
    ##触发zygote服务
    trigger zygote-start
    trigger firmware_mounts_complete
    trigger early-boot
    trigger boot
on early-fs
    ##存储系统的基石,Volume Daemon 卷守护进程
    start vold  
on late-fs
    #启动class为early_hal的所有服务
    .....
    class_start early_hal
    .....
    #上面在late-init阶段被执行
on zygote-start
    wait_for_prop odsign.verification.done 1
    exec_start update_verifier
    start statsd
    #启动64位zygote
    start zygote
    #启动32位zygote(忽略)
    start zygote_secondary
on boot
    .....
    #启动所有class为hal服务
    class_start hal
    #启动所有class为core的服务
    class_start core

#核心服务包括ueventd,这个服务和init程序是同一个程序,只不过拷贝到了/system/bin/ueventd下,实际调用/system/core/init/main.cpp中的ueventd_main(argc,argv)分支,该守护进程负责设备节点管理,以及后面的设备热插拔管理,  它是android硬件访问的基石
service ueventd /system/bin/ueventd
    class core
    critical
    seclabel u:r:ueventd:s0
    user root
    shutdown critical   
#在late-init阶段,zygote进程被启动
#app_process64源码路径(/frameworks/base/cmds/app_process/app_main.cpp)
#传入了6个参数
#-Xzygote \                  # argv[1]:虚拟机参数
#/system/bin \               # argv[2]:父目录路径
#--zygote \                  # argv[3]:标志位(启动zygote模式)
#--start-system-server \     # argv[4]:标志位(启动系统服务)
#--socket-name=zygote        # argv[5]:指定socket名称
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main  #class类型是main
    priority -20    #优先级-20
    user root       #以root用户启动
    group root readproc reserved_disk  #以root readproc reserved_disk用户组
    socket zygote stream 660 root system #socket流的权限
    socket usap_pool_primary stream 660 root system
    #服务重启时执行vdc,并重启audioserver、cameraserver、media、netd等进程
    onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse  
    onrestart write /sys/power/state on
    onrestart write /sys/power/wake_lock zygote_kwl
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart --only-if-running media.tuner
    onrestart restart netd
    onrestart restart wificond
    #为 Zygote 进程分配高性能资源策略,确保其孵化的应用进程能获得充足的系统资源
    task_profiles ProcessCapacityHigh MaxPerformance
    #定义 Zygote 进程的崩溃监控策略,防止频繁崩溃导致系统不稳定。
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

后面就正式进入android framework了。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注