启动概述

Android的第一个启动进程,init的PID为1,这个进程会解析init.rc来建构出系统的初始运作型态,其他的系统才会相继启动

  • 启动电源&系统启动
    当电源启动后,会从预定的地方(PC读取ROM),开始加载程序(BootLoader)到RAM中,并开始执行
  • 引导程序BootLoader
    引导程序BootLoader是在Android系统开始运行前的一个小程序,主要功能是把系统OS拉起并运行
  • Linux 内核启动
    当内核启动时,设定缓存、保护储存器、计划列表、加载驱动…在内核完成系统设置后,它会在系统中找init.rc文件,并启动init进程
  • init进程启动
    该进程主要是作初始化&启动系统属性服务,也用来启动Zygote进程
  • Launcher App应用(桌面应用程序)

init 进程概述

init作为Android系统启动的第一个进程,通过解析init.rc来陆续启动关键的系统服务进程,其有三个重点服务进程

  • ServiceManager(类似DNS功能,用来查找SystemServer中的服务句柄)
  • Zygote(初始进程,加载必要Anroid resource、启动虚拟机…等等)
  • SystemServer(启动系统级别服务,像是AMS、WMS…服务)

init进程会启动Zygote、SystemServer两个进程,而Zygote使用Socket监听AMS、ServiceManager使用Binder通信
创建、挂载启动所需要的文件目录
初始化、启动性服务
解析init.rc配置文件并启动Zygote进程

init 进程 - main.cpp 分析

// /init/main.cpp

#include "builtins.h"
#include "first_stage_init.h"
#include "init.h"
#include "selinux.h"
#include "subcontext.h"
#include "ueventd.h"

using namespace android::init;

... 省略部分

int main(int argc, char** argv) {    
    ... 省略部分

    // Boost prio which will be restored later
    setpriority(PRIO_PROCESS, 0, -20);


    if (!strcmp(basename(argv[0]), "ueventd")) {    // ueventd 负责创建设备节点、权限、匿名共享內存... 等等
        return ueventd_main(argc, argv);
    }

    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            // 初始化 Logger
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
            return SubcontextMain(argc, argv, &function_map);
        }
        // Selinux 安全相关
        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }

        // init 进程 (第二阶段)
        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }

    // 启动 init 进程 (第一阶段)
    return FirstStageMain(argc, argv);
}

init进程第一阶段- first_stage_init#FirstStageMain文件挂载

第一阶段主要在1.创建并挂载相关的文件,这里列出几个较为重要的文件系统,详细功能可看注释、2.设定传入参数、3执行execv函数(再次加载main.cpp,但带入不同参数)
挂载的文件都在內存中(RAM),并实体文件

使用指令挂载目录/文件名、档案管理特性说明
mounttmpfs存在 RAM 中,并不持久 (tmp 的取名)虚拟内存文件系统,它将所有的 文件存在虚拟内存中,将 tmpfs 卸载后,内部的资料就会全部消失
mount/dev/devpts动态挂载 devpts为伪终端提供了一个标准,只要pty的主复合设备 /dev/ptmx 被开启,就会去 /dev/pts 下动态创建一个新的pty设备文件
mountproc可在运行时修改内核参数虚拟文件系统,可以看做内核内部数据结构的接口~
mountsysfsLinux 2.6内核引入(主要针对 硬件相关参数,这就有关于devpts设备虚拟文件系统,通常被挂载在/sys目录下
// first_stage_init.cpp

int FirstStageMain(int argc, char** argv) {

    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();    // init 错误,重启 Boot Loader
    }

    // 记录启动时间
    boot_clock::time_point start_time = boot_clock::now();
    // 记错错误
    std::vector<std::pair<std::string, int>> errors;

    
#define CHECKCALL(x) \
    if ((x) != 0) errors.emplace_back(#x " failed", errno);

    // 清除 umask,之后创建的文件、文件夹拥有全部权限
    umask(0);
    CHECKCALL(clearenv());
    CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));
    // Get the basic filesystem setup we need put together in the initramdisk
    // on / and then we'll let the rc file figure out the rest.
    // mount 挂载 tmpfs 文件系统
    CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));

    // 创建文件夹,赋予权限
    CHECKCALL(mkdir("/dev/pts", 0755));
    CHECKCALL(mkdir("/dev/socket", 0755));
    CHECKCALL(mkdir("/dev/dm-user", 0755));

    CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));

#define MAKE_STR(x) __STRING(x)
    // 挂载进程信息
    CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
#undef MAKE_STR
    // Don't expose the raw commandline to unprivileged processes.
    CHECKCALL(chmod("/proc/cmdline", 0440));
    std::string cmdline;
    android::base::ReadFileToString("/proc/cmdline", &cmdline);
    // Don't expose the raw bootconfig to unprivileged processes.
    chmod("/proc/bootconfig", 0440);
    std::string bootconfig;
    android::base::ReadFileToString("/proc/bootconfig", &bootconfig);

    // 8.0 增加了用户群组
    gid_t groups[] = {AID_READPROC};
    // 将群组加入到目前进程的设备中
    CHECKCALL(setgroups(arraysize(groups), groups));
    
    // 挂载 sys,使用 sysfs 管理档案
    CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
    CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));

    // 创建节点 (mknod) 用于输出 Log
    CHECKCALL(mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11)));
    if constexpr (WORLD_WRITABLE_KMSG) {
        CHECKCALL(mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11)));
    }
    CHECKCALL(mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8)));
    CHECKCALL(mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9)));
    // This is needed for log wrapper, which gets called before ueventd runs.
    CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2)));
    CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3)));
    
    // See storage config details athttp://source.android.com/devices/storage/
    // 挂载 /mnt/{vendor,product},使用 tmpfs 管理
    CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                    "mode=0755,uid=0,gid=1000"));
    
    // /mnt/vendor 用于挂载特定供应商的分区
    CHECKCALL(mkdir("/mnt/vendor", 0755));
    // /mnt/product is used to mount product-specific partitions that can not be
    // part of the product partition, e.g. because they are mounted read-write.
    CHECKCALL(mkdir("/mnt/product", 0755));
    // /debug_ramdisk is used to preserve additional files from the debug ramdisk
    CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                    "mode=0755,uid=0,gid=0"));
    // /second_stage_resources is used to preserve files from first to second
    // stage init
    CHECKCALL(mount("tmpfs", kSecondStageRes, "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                    "mode=0755,uid=0,gid=0"))
#undef CHECKCALL
    SetStdioToDevNull(argv);
    
    InitKernelLogging(argv);

    if (!errors.empty()) {
        for (const auto& [error_string, error_errno] : errors) {
            LOG(ERROR) << error_string << " " << strerror(error_errno);
        }
        LOG(FATAL) << "Init encountered errors starting first stage, aborting";
    }

    ... 省略部分

    return 1;
}

挂载特定分区设备

// first_stage_init.cpp

int FirstStageMain(int argc, char** argv) {
    
    ... 省略部分
        
    if (!DoFirstStageMount(!created_devices)) {
        LOG(FATAL) << "Failed to mount required partitions early ...";
    }
    
    ... 省略部分
}

SELinux 相关工作

// first_stage_init.cpp

int FirstStageMain(int argc, char** argv) {

    ... 省略部分

    struct stat new_root_info;
    if (stat("/", &new_root_info) != 0) {
        PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
        old_root_dir.reset();
    }
    if (old_root_dir && old_root_info.st_dev != new_root_info.st_dev) {
        FreeRamdisk(old_root_dir.get(), old_root_info.st_dev);
    }
    
    // 初始化安全框架: Android Verified Boot & AVB 主要用于防止系统文件被篡改
    // 防止系统回滚
    SetInitAvbVersionInRecovery();
    setenv(kEnvFirstStageStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(),
           1);

    ... 省略部分


}

透过execv启动init进程的SecondStageMain方法

// first_stage_init.cpp

int FirstStageMain(int argc, char** argv) {

    ... 省略部分

    // 设定参数
    const char* path = "/system/bin/init";
    const char* args[] = {path, "selinux_setup", nullptr};
    // Binder open (log 訊息)
    auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);
    close(fd);

    // 启动 init 进程,传输参数 "selinux_setup"
    execv(path, const_cast<char**>(args));       


}

init 进程插曲 SE - selinux.cpp#SetupSelinux

在第二阶段之前会先进行SE设定
在经过first_stage_init#FirstStageMain文件挂载后,会通过execv函数再次启动main.cpp行程,再次进入main.cpp#main方法

// /init/main.cpp 档案

#include "builtins.h"
#include "first_stage_init.h"
#include "init.h"
#include "selinux.h"
#include "subcontext.h"
#include "ueventd.h"

using namespace android::init;

... 省略部分

// 再次进入后,argv 就是带 selinux_setup 字串
int main(int argc, char** argv) {    
    ... 省略部分

    // Boost prio which will be restored later
    setpriority(PRIO_PROCESS, 0, -20);

    // 判断参数
    if (!strcmp(basename(argv[0]), "ueventd")) {    
        return ueventd_main(argc, argv);
    }

    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            // 初始化 Log
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
            return SubcontextMain(argc, argv, &function_map);
        }
        // Selinux 
        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }

        // init 进程 (第二阶段)
        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }

    // 启动 init 进程 (第一阶段)
    return FirstStageMain(argc, argv);
}

SetupSelinux主要是在加载SE策略,加载SE完成后,就会设定新参数,再次透过execv启动main.cpp(如上一小节说明)

// /init/selinux.cpp

int SetupSelinux(char** argv) {

    SetStdioToDevNull(argv);

    // 1. 初始化核心的 Log
    InitKernelLogging(argv);
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
    }
    boot_clock::time_point start_time = boot_clock::now();

    // 2. 挂载遗矢的系统区块
    MountMissingSystemPartitions();
    SelinuxSetupKernelLogging();
    LOG(INFO) << "Opening SELinux policy";
    PrepareApexSepolicy();

    // Read the policy before potentially killing snapuserd.
    std::string policy;
    // 读取策略
    ReadPolicy(&policy);

    CleanupApexSepolicy();
    auto snapuserd_helper = SnapuserdSelinuxHelper::CreateIfNeeded();
    if (snapuserd_helper) {
        // Kill the old snapused to avoid audit messages. After this we cannot
        // read from /system (or other dynamic partitions) until we call
        // FinishTransition().
        snapuserd_helper->StartTransition();
    }

    //载入 SE 策略
    LoadSelinuxPolicy(policy);

    ... 省略部分

    const char* path = "/system/bin/init";
    const char* args[] = {path, "second_stage", nullptr};

    // 再次启动该进程
    execv(path, const_cast<char**>(args));

    return 1;
}

init 进程第二阶段 - init.cpp#SecondStageMain 解析 init.rc

经过first_stage_init的初始化挂载设备后,就会执行到main.cpp类的SecondStageMain函数(可以看做init进城的第二阶段)

// /init/main.cpp 档案

#include "builtins.h"
#include "first_stage_init.h"
#include "init.h"
#include "selinux.h"
#include "subcontext.h"
#include "ueventd.h"

using namespace android::init;

... 省略部分

int main(int argc, char** argv) {    
    ... 省略部分

    // Boost prio which will be restored later
    setpriority(PRIO_PROCESS, 0, -20);

    if (!strcmp(basename(argv[0]), "ueventd")) {   
        return ueventd_main(argc, argv);
    }

    
    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            // 初始化 Log
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
            return SubcontextMain(argc, argv, &function_map);
        }
        // Selinux 
        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }

       
        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }

    
    return FirstStageMain(argc, argv);
}

开始分析init.cpp#SecondStageMain,分为10个阶段,详细请看注释
初始化属性域,主要就是做PropertyInit函数

// init/init.cpp

int SecondStageMain(int argc, char** argv) {
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();        // init 失败 重启 Boot Loader
    }


    // 启动时间
    boot_clock::time_point start_time = boot_clock::now();

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

  
    SetStdioToDevNull(argv);

    // 初始化 kernel log 系统
    InitKernelLogging(argv);
    
    // 初始化系統 $PATH 路径
    if (setenv("PATH", _PATH_DEFPATH, 1) != 0) {
        PLOG(FATAL) << "Could not set $PATH to '" << _PATH_DEFPATH << "' in second stage";
    }


    {
       
        struct sigaction action = {.sa_flags = SA_RESTART};
        action.sa_handler = [](int) {};
 
        sigaction(SIGPIPE, &action, nullptr);   
    }
    // Set init and its forked children's oom_adj.
    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));

    ... 省略部分

    PropertyInit();       

    ... 省略部分

    return 0;
}

清空环境变量:清除之前写到系统属性中的环境变数

// /init/init.cpp

int SecondStageMain(int argc, char** argv) {
    ... 省略部分

    // Clean up our environment.
    unsetenv("INIT_AVB_VERSION");
    unsetenv("INIT_FORCE_DEBUGGABLE");

    ... 省略部分
}

SELinux 相关工作

// /init/init.cpp

int SecondStageMain(int argc, char** argv) {
    ... 省略部分

    // Now set up SELinux for second stage.
    SelinuxSetupKernelLogging();        // 完成第二阶段的 selinux 工作
    SelabelInitialize();                // 注册部分处理器
    SelinuxRestoreContext();            // SELinux 的 Context

    ... 省略部分
}

创建 epoll 事件通知

// /init/init.cpp

int SecondStageMain(int argc, char** argv) {

    ... 省略部分

    Epoll epoll;
    // epoll.Open() 
    if (auto result = epoll.Open(); !result.ok()) {
        PLOG(FATAL) << result.error();
    }

    ... 省略部分

}

装载子进程信号处理器:init是一个守护进程(可理解为守护线程),以该进程为主,若该init进程结束,其他子进程都会结束

// /init/init.cpp

int SecondStageMain(int argc, char** argv) {

    ... 省略部分

    // 创建handler处理子进程终止信号,注册一个信号到epoll监听(若有改变就会对epoll)
    // epoll会先收到通知,再用socket读取数据
        
    //为了防止init进程的子进程变成僵尸进程
    InstallSignalFdHandler(&epoll);
    InstallInitNotifier(&epoll);

    ... 省略部分

}

启动属性服务:主要函数StartPropertyService,启动一个socket监听属性更改

// /init/init.cpp
static int property_fd = -1;

int SecondStageMain(int argc, char** argv) {

    ... 省略部分

    // 启动其他属性服务
    StartPropertyService(&property_fd);

    unsetenv("INIT_AVB_VERSION");    
    fs_mgr_vendor_overlay_mount_all();
    export_oem_lock_status();        

    MountHandler mount_handler(&epoll);

 
    SetUsbController();

    ... 省略部分
}

匹配命令&函数之间对应关系:Cmd & Function Map,从这可以看出系统支持哪些cmd指令,还有指令实际运作的方法

// /init/init.cpp

int SecondStageMain(int argc, char** argv) {

    ... 省略部分

    // 创建 Function & Cmd 的 Map
    const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();

    // 在 Action 中保存 function_map 对象
    // Action::set_function_map,`::` 相当于 static Function
    Action::set_function_map(&function_map);
    if (!SetupMountNamespaces()) {
        PLOG(FATAL) << "SetupMountNamespaces failed";
    }

    ... 省略部分
}

LoadBootScripts:解析init.rc档案

// /init/init.cpp

int SecondStageMain(int argc, char** argv) {

    ... 省略部分
    
   
    ActionManager& am = ActionManager::GetInstance();    
    ServiceList& sm = ServiceList::GetInstance();

    // 解析脚本
    LoadBootScripts(am, sm);

    ... 省略部分

}

// 解析 .rc 脚本
static void LoadBootScripts(ActionManager& action_manager, 
                            ServiceList& service_list) {
    // 创建解析器
    Parser parser = CreateParser(action_manager, service_list);

    // 预设解析 ro.boot.init_rc
    std::string bootscript = GetProperty("ro.boot.init_rc", "");

    if (bootscript.empty()) {
        // 解析指定 init.rc 档案
        parser.ParseConfig("/system/etc/init/hw/init.rc");

        if (!parser.ParseConfig("/system/etc/init")) {
            late_import_paths.emplace_back("/system/etc/init");
        }

        parser.ParseConfig("/system_ext/etc/init");
        if (!parser.ParseConfig("/vendor/etc/init")) {
            late_import_paths.emplace_back("/vendor/etc/init");
        }
        if (!parser.ParseConfig("/odm/etc/init")) {
            late_import_paths.emplace_back("/odm/etc/init");
        }
        if (!parser.ParseConfig("/product/etc/init")) {
            late_import_paths.emplace_back("/product/etc/init");
        }
    } else {
        parser.ParseConfig(bootscript);
    }
}

添加触发事件:这边可以看到rc档的一些设定,其中常见的指令包括,1 early-init、2 init、3 late-init

// /init/init.cpp

int SecondStageMain(int argc, char** argv) {

    ... 省略部分

    // ActionManager 解析完成
    am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
    am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
    am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux");
    am.QueueBuiltinAction(ConnectEarlyStageSnapuserdAction, "ConnectEarlyStageSnapuserd");
    
    // 触发标签 early-init
    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");

    ... 省略部分
}

进入循环:不断处理接收到的命令&执行Service

// /init/init.cpp

int SecondStageMain(int argc, char** argv) {

    ... 省略部分

    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) {
            HandlePowerctlMessage(*shutdown_command);
            shutdown_state.set_do_shutdown(false);
        }

        ... 省略部分

        // 不必等待 && Service 没有正在 running || Service 是运行完毕
        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
            am.ExecuteOneCommand();    // 执行一个cmd
        }

        ... 省略部分
    }

}