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

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

  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.");
    }
...
 }

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值