Android 8.0系统启动流程_init(一)

本系列主要介绍Android8.0系统启动过程中涉及到的init、Zygote、 SystemServerLauncher

  1. init启动前准备
  2. init函数分析
  3. init函数解析
  4. init启动Zygote

一、init启动前准备

init进程是Android系统的第一个进程,其进程号为1,该进程启动后,主要处理一些重要的初始化工作,比如创建Zygote和各种属性服务。在电源按键,按下后,经历如下几个步骤后,便开始引入init进程:

1. 启动电源及系统:电源按下后,引导芯片开始将固化在ROM中的BootLoader加载至RAM中,并执行该程序; 2. 引导程序BootLoader :引导程序BootLoader是在Android操作系统开始运行前,执行的一个小程序,其主要作用是把系统OS拉起来并运行; 3. Linux内核启动 :内核启动时,设置缓存、被保护存储器、计划列表和加载驱动等,完成设置后,开始加载init.rc文件; 4. init进程启动 :开始初始化和启动属性服务,创建Zygote进程。

二、 init函数分析

在Linux内核加载完成后,开始查找init.rc文件,并启动init进程,其主要代码如下:

system/core/init/init.cpp
int main(int argc, char** argv) {
   ...

    if (is_first_stage) {
        boot_clock::time_point start_time = boot_clock::now();

        // 清理 umask.
        umask(0);

        // 创建和挂载所需的文件
        mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
        mkdir("/dev/pts", 0755);
        mkdir("/dev/socket", 0755);
        mount("devpts", "/dev/pts", "devpts", 0, NULL);
        #define MAKE_STR(x) __STRING(x)
        mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
        // Don't expose the raw commandline to unprivileged processes.
        chmod("/proc/cmdline", 0440);
        gid_t groups[] = { AID_READPROC };
        setgroups(arraysize(groups), groups);
        mount("sysfs", "/sys", "sysfs", 0, NULL);
        mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
        mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
        mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
        mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));

        // 初始化Kernel日志
        InitKernelLogging(argv);
		...
    }

   ...
	//属性服务初始化
    property_init();

    ...
	
	//创建epoll句柄
    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
	
   ...
   
	//设置子进程的处理函数
    signal_handler_init();

	//导入默认的环境变量
    property_load_boot_defaults();
    export_oem_lock_status();
	//启动属性服务
    start_property_service();
    set_usb_controller();

    ...
	
    if (bootscript.empty()) {
    //解析init.rc文件
        parser.ParseConfig("/init.rc");
        parser.set_is_system_etc_init_loaded(
                parser.ParseConfig("/system/etc/init"));
        parser.set_is_vendor_etc_init_loaded(
                parser.ParseConfig("/vendor/etc/init"));
        parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
    } else {
        parser.ParseConfig(bootscript);
        parser.set_is_system_etc_init_loaded(true);
        parser.set_is_vendor_etc_init_loaded(true);
        parser.set_is_odm_etc_init_loaded(true);
    }

    ...

    return 0;
}
复制代码

该流程分析如下:

1. 挂载文件:通过设置umask值,屏蔽一些权限后,开始挂载和创建所需的文件; 2. 属性服务 :通过property_init()属性服务初始化,调用start_property_service()启动属性服务; 3. 子进程的处理函数 : signal_handler_init()主要作用是防止出现僵尸进程,子进程在暂停和终止后,会发出SIGCHLD的信号,signal_handler_init()接收到该信号后,会对该进程进行回收处理,防止占用系统进程资源; 4. 解析init.rc配置 :在8.0中对init.rc文件进行了拆分,可查看system\core\rootdir目录,包括: init.zygote32.rc:Zygote对应的执行程序是app_process(纯32位模式); init.zygote64.rc:Zygote对应的执行程序是app_process64(纯64位模式); init.zygote32_64.rc:启动两个Zygote进程( zygote 和 zygote_secondary),对应的执行程序是app_process32(主模式)和app_process64; init.zygote64_32.rc:启动两个Zygote进程( zygote 和 zygote_secondary),对应的执行程序是app_process64(主模式)和app_process32。

三、 init函数解析

\system\core\rootdir\init.rc

init.rc配置文件,是由Android初始化语言(Android Init Language)编写的脚本,主要包括5种语言类型:Action、Command、Service、Option和Import。 同时,需要注意init.rc仅仅是配置文件,类似于xml,没有解析的顺序而言(不是自上而下运行),是通过程序调用,获取相应的配置信息,真正加载运行的程序是在上部分提到的init.cpp文件。

import:指令是用于类似于java语言,主要用于扩展配置,格式如下:

import <filename>一个init配置文件,扩展当前配置
复制代码

filename一般是init.XXX.rc的形式,源码中例如:

import /init.environ.rc
复制代码

Action:一系列命令的开始,其格式如下:

on <trgger> [&& <trigger>]*
   <command1>
   <command2>
   <command3>
   ...
复制代码

每个Action都至少有一个触发器(trgger),该触发器决定何时执行该Action,即后面的command...指令,其要通过ActionParser解析,其实现代码在\system\core\init\action.cpp,其格式如下:

# Indicate to fw loaders that the relevant mounts are up.
on firmware_mounts_complete
    rm /dev/.booting
复制代码

Service:以service开头,由init进程启动的,一般运行于init的子进程中,在启动该service前需要判断对应的可执行文件是否存在,并通过fork方式生成子进程。其主要通过ServiceParser解析,其实现代码在\system\core\init\service.cpp,其格式如下:

service <name> <pathname> [ <argument> ]*
    <option>
    <option>
    ...
复制代码

其中name:服务的名称,pathname:当前服务对应程序的位置,option:当前服务设置的选项,argument:可选参数。例如:

service ueventd /sbin/ueventd
    class core
    critical
    seclabel u:r:ueventd:s0
    shutdown critical
复制代码

四 、init启动Zygote

\system\core\rootdir\init.rc \system\core\init\init.cpp \system\core\init\builtins.cpp \ frameworks\base\cmds\app_process\app_main.cpp

在init.rc中,关于Zygote的启动在如下部分:

\system\core\rootdir\init.rc
on nonencrypted
    class_start main
    class_start late_start
复制代码

其中 main指的就是Zygote的服务名称,其中class_start函数是指builtins.cpp中的函数:

\system\core\init\builtins.cpp
static int do_class_start(const std::vector<std::string>& args) {
    ServiceManager::GetInstance().
        ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
    return 0;
}
复制代码

其中ForEachServiceInClass函数会遍历Service链表,查找classname为main的Zygote,并执行service.cpp中的StartIfNotDisabled函数,如下所示:

\system\core\init\service.cpp
bool Service::StartIfNotDisabled() {
    if (!(flags_ & SVC_DISABLED)) {
        return Start();
    } else {
        flags_ |= SVC_DISABLED_START;
    }
    return true;
}

复制代码

如果该service没有在其对应的rc文件中设置disable选项,则会执行Start()方法,启动该Service,在init.zygote64.rc中没有设置disable选项,因此可以正常启动该Service。

\system\core\init\builtins.cpp
bool Service::Start() {
    ..
	//是否正在运行
    if (flags_ & SVC_RUNNING) {
        return false;
    }

   ...
   //启动的路径是否存在
    struct stat sb;
    if (stat(args_[0].c_str(), &sb) == -1) {
        PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'";
        flags_ |= SVC_DISABLED;
        return false;
    }

    std::string scon;
    if (!seclabel_.empty()) {
        scon = seclabel_;
    } else {
        scon = ComputeContextFromExecutable(name_, args_[0]);
        if (scon == "") {
            return false;
        }
    }

   //如果该进程未启动,调用fork启动该进程
    pid_t pid = -1;
    if (namespace_flags_) {
        pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
    } else {
        pid = fork();
    }

    if (pid == 0) {
        umask(077);

      ...
    }

    if (pid < 0) {
        PLOG(ERROR) << "failed to fork for '" << name_ << "'";
        pid_ = 0;
        return false;
    }

    ....
	//启动该进程
    SetProcessAttributes();

        if (!ExpandArgsAndExecve(args_)) {
            PLOG(ERROR) << "cannot execve('" << args_[0] << "')";
        }

        _exit(127);
    NotifyStateChange("running");
    return true;
}


复制代码

其主要流程如下:

  • 是否正在运行,如正在运行,直接返回;
  • 子进程是否启动,如未启动,调用fork并返回pid值;
  • 如果以上正常,则调用ExpandArgsAndExecve启动该进程,完成Zygote的启动。

启动Zygote进程真正执行的路径为frameworks\base\cmds\app_process\app_main.cpp下的main函数,如下所示:

\ frameworks\base\cmds\app_process\app_main.cpp
int main(int argc, char* const argv[])
{
...
 if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);//启动Zygote进程
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
...
 }

复制代码
我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章