Android 9.0系统源码_系统启动(一)启动init进程

前言

Android系统最早时伴随着手机出现的,但是由于Android系统开源且系统生态成熟,近几年新兴起的智能电视、智能家居、新能源汽车等行业,基本上也都选择了Android系统作为设备软件载体,这就导致虽然Android应用开发的热度降低了,但是Android系统特别开发热度却越来越高。由于不同设备的应用场景不同,这就导致无法直接使用Android系统,而需要根据自己的业务场景来具体定制Android系统以满足自己的需求。而想要特殊化定制Android系统,基本都绕不开Framework的内容,而想要深入理解Android系统的Framework层源码,第一步自然就是理解Android系统的启动流程,本篇文章我们将会结合Android9.0系统源码来具体来分析以下Android系统的启动流程。

了解Framework的同学,可能都或多或少的知道AMS、WMS、类加载、热修复Sophix、插件化等都要涉及系统的启动流程。

一、按下Android设备电源

1、启动电源及系统,按下电源键之后,引导芯片开始将固化在ROM中的BootLoader加载至RAM中,并执行该程序。

2、加载引导程序Boot Loader到RAM,Boot Loader一般就会由厂商进行定制。

3、执行引导程序:主要作用是把系统OS拉起并运行,初始化堆栈、硬件、网络内存等操作。

4、启动Android系统的Linux内核,寻找init关键文件。

5、Kernel启动后,在用户空间启动init进程,init进程是Android系统的第一个进程,其进程号为1,该进程启动后,主要处理一些重要的初始化工作,比如创建Zygote和各种属性服务。

二、init进程的入口函数

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

int main(int argc, char** argv) {
	...
    bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
    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();//01
	...
  	//创建epoll句柄
    epoll_fd = epoll_create1(EPOLL_CLOEXEC);

   ...

	//设置子进程的信号处理函数,如果子进程(Zygote进程)异常退出,init进程会调用该函数中设定的信号函数来进行处理
    signal_handler_init();//02

	//导入默认的环境变量
    property_load_boot_defaults();
    export_oem_lock_status();
	//启动属性服务
    start_property_service();//03
    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);
    }
    ...
    while (true) {
        // By default, sleep until something happens.
        int epoll_timeout_ms = -1;

        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
            am.ExecuteOneCommand();
        }
        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
        	//重启死去的进程
            restart_processes();//05

            // If there's a process that needs restarting, wake up in time for that.
            if (process_needs_restart_at != 0) {
                epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
                if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
            }

            // If there's more work to do, wake up again immediately.
            if (am.HasMoreCommands()) epoll_timeout_ms = 0;
        }

        epoll_event ev;
        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
        if (nr == -1) {
            PLOG(ERROR) << "epoll_wait failed";
        } else if (nr == 1) {
            ((void (*)()) ev.data.ptr)();
        }
    }
    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的配置代码如下所示:


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值