Android系统启动流程(nougat7.1.1_r6)

本文详细介绍了Android系统从启动到运行Launcher的整个过程,涵盖Linux内核启动、Init进程、Zygote进程的创建、SystemServer进程的启动以及最终Launcher的启动。文章深入探讨了Android启动过程中的关键组件,如Bootloader、Linux内核、HAL、ART、SystemServer以及应用程序框架。通过对Android源码的分析,揭示了Android系统如何逐步构建并启动到用户界面。
摘要由CSDN通过智能技术生成

一.Android启动简介

Android 是一种基于 Linux 的开放源代码软件栈,为广泛的设备和机型而创建。下图所示为 Android 平台的主要组件。
这里写图片描述

Linux 内核

Android 平台的基础是 Linux 内核。例如,Android Runtime (ART) 依靠 Linux 内核来执行底层功能,例如线程和低层内存管理。

  • 音频驱动(Audio):常用的基于ALSA的高级Linux声音体系驱动。
  • Binder IPC驱动:Android的一个特殊的驱动程序,具有单独的设备节点,提供进程间通信的功能。
  • 显示驱动(Display):基于Linux的帧缓冲(Frame Buffer)驱动。
  • 键盘驱动(KeyBoard):作为输入设备的键盘驱动。
  • 蓝牙驱动(Bluetooth Driver):基于IEEE 802.15.1标准的无线传输技术。
  • 照相机驱动(Camera Driver):常用的基于Linux的v412(Video for Linux)的驱动。
  • Flash内存驱动(Flase Memory Driver):基于MTD的Flash驱动程序。
  • WiFi驱动:基于IEEE 802.11标准的驱动程序。

HAL(Hardware Abstraction Layer)

硬件抽象层 (HAL) 提供标准界面,向更高级别的 Java API 框架显示设备硬件功能。HAL 包含多个库模块,其中每个模块都为特定类型的硬件组件实现一个界面,例如相机或蓝牙模块。当框架 API 要求访问设备硬件时,Android 系统将为该硬件组件加载库模块。

硬件抽象层 (HAL) 会定义一个标准接口以供硬件供应商实现,并允许 Android 忽略较低别的驱动程序实现。借助 HAL,可以顺利实现相关功能,而不会影响或无需更改更高级别的系统。HAL 实现会被封装成模块 (.so) 文件,并会由 Android 系统适时地加载。
这里写图片描述

标准的HAL结构中,HAL借口包含两个通用的组件:一个模块和一个设备。

  • 模块:表示被封装切存储为共享库(.so file)的实现。里面包含模块版本等元数据。
  • 设备:提取产品的实际硬件。例如,音频模块可能会包含主音频设备、USB 音频设备或蓝牙 A2DP 音频设备。

Android Runtime

Android Runtime时运行在Android 5.0(API 级别 21)或更高版本的设备上。ART 编写为通过执行 DEX 文件在低内存设备上运行多个虚拟机,DEX 文件是一种专为 Android 设计的字节码格式,经过优化,使用的内存很少。编译工具链(例如 Jack)将 Java 源代码编译为 DEX 字节码,使其可在 Android 平台上运行。
ART 的部分主要功能包括:

  • 预先 (AOT) 和即时 (JIT) 编译
  • 优化的垃圾回收 (GC)
  • 更好的调试支持,包括专用采样分析器、详细的诊断异常和崩溃报告,并且能够设置监视点以监控特定字段

原生 C/C++ 库 :

许多核心 Android 系统组件和服务(例如 ART 和 HAL)构建自原生代码,需要以 C 和 C++ 编写的原生库。Android 平台提供 Java 框架 API 以向应用显示其中部分原生库的功能。

  • OpenGl ES: Android包括支持高性能2 d和3 d图形与开放图形库。OpenGL是一个跨平台的图形API,它为3D图形处理硬件指定了一个标准的软件接口。
  • WebKit:一个开源的浏览器引擎.
  • OenMAX AL:一个多媒体应用程序的标准,基于 Khronos Group OpenMAX AL™ 1.0.1 standard,在Android4.0以上使用。
  • Libc:从BSD继承来的标准C系统函数库,专门为基于embedded linux的设备定制。

Application Framework(应用框架层)

  • View System:可用以构建应用的 UI,包括列表、网格、文本框、按钮甚至可嵌入的网络浏览器
  • Content Providers:它可以让一个应用访问另一个应用的数据,或共享它们自己的数据。
  • Resource Manager:用于访问非代码资源,例如本地化的字符串、图形和布局文件 。
  • Notification Manager:可让所有应用在状态栏中显示自定义提醒 。
  • Activity Manager:用于管理应用的生命周期,提供常见的导航返回栈
  • Window Manager:管理所有的窗口程序。
  • Package Manager:Android系统内包的程序管理。

System Apps

Android 随附一套用于电子邮件、短信、日历、互联网浏览和联系人等的核心应用。平台随附的应用与用户可以选择安装的应用一样,没有特殊状态。因此第三方应用可成为用户的默认网络浏览器、短信 Messenger 甚至默认键盘(有一些例外,例如系统的“设置”应用)。


其实分析了这张图都有什么东西,但是对于安卓系统启动流程还是很模糊的。我不打算循序渐进,先放一张图,来对我这篇文章中提到的安卓系统流程有个整体的了解。
这里写图片描述

二、Linux内核启动

开机按Power,正常启动系统,加载boot.img,boot.img包含内核,基本文件系统,用于正常启动手机。

1.引导程序Bootloader

BootLoader是在操作系统运行之前运行的一段程序,它可以将系统的软硬件环境带到一个合适状态,为运行操作系统做好准备。它比较像电脑上的BIOS,它就是要把OS拉起来运行。Bootloader有三种模式如下:
a:开机后按组合键启动到fastboot模式,即命令或SD卡烧写模式,不加载内核及文件系统,可以通过数据线与电脑连接,然后在电脑上执行一些命令,如刷系统镜像到手机上。
b:开机后按组合键启动到recovery模式,加载recovery.img,recovery.img包含内核,部分文件系统,可以读sdcard中的update.zip进行刷机,也可以清除cache和用户数据。
c:开机按Power,正常启动系统,加载boot.img,boot.img包含内核,基本文件系统,用于正常启动手机。
正常启动流程,也就是c流程。
Bootloader做的事情主要有:初始化CPU时钟,内存,串口等;设置linux启动参数;加载Linux各种各样的内核镜像到SDRAM中。

2.linux内核启动

内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第一个进程。

三、Init进程

Init进程,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。init始终是第一个进程.

1.Init入口函数

system/core/init/init.cpp

init的入口函数为main。

int main(int argc, char** argv) {
   ...
       // 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.

    //基本的系统的设置。挂载信息,创建一些文件夹。从注释中我们可以看到,它把一些其他的操作放到了rc文件下。之后会提到。
    if (is_first_stage) {
        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));
        mount("sysfs", "/sys", "sysfs", 0, NULL);
    } 
    //重定向标准输入\输出到 dev/_null_
    open_devnull_stdio();
    //初始化内核log系统
    klog_init();
    klog_set_level(KLOG_NOTICE_LEVEL);

    NOTICE("init %s started!\n", is_first_stage ? "first stage" : "second stage");
    if (!is_first_stage) {
        close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
       //初始化属性相关资源,利用ashmem共享。
        property_init();

        process_kernel_dt();
        process_kernel_cmdline();

        export_kernel_boot_props();
    }

    // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
    //设置SELinux policy策略。
    selinux_initialize(is_first_stage);
    if (is_first_stage) {
        if (restorecon("/init") == -1) {
            ERROR("restorecon failed: %s\n", strerror(errno));
            security_failure();
        }
        char* path = argv[0];
        char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
        if (execv(path, args) == -1) {
            ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));
            security_failure();
        }
    }

    NOTICE("Running restorecon...\n");
    restorecon("/dev");
    restorecon("/dev/socket");
    restorecon("/dev/__properties__");
    restorecon("/property_contexts");
    restorecon_recursive("/sys");

    //创建epoll句柄
    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    if (epoll_fd == -1) {
        ERROR("epoll_create1 failed: %s\n", strerror(errno));
        exit(1);
    }

    signal_handler_init();
    property_load_boot_defaults();
    export_oem_lock_status();
    //启动属性服务
    start_property_service();
 const BuiltinFunctionMap function_map;
    Action::set_function_map(&function_map);
    Parser& parser = Parser::GetInstance();
    parser.AddSectionParser("service",std::make_unique<ServiceParser>());
    parser.AddSectionParser("on", std::make_unique<ActionParser>());
    parser.AddSectionParser("import", std::make_unique<ImportParser>());
    //解析init.rc。
    parser.ParseConfig("/init.rc");
    //解析完成配置文件之后,会得到一系列的action动作。init和boot。
    ActionManager& am = ActionManager::GetInstance();
     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(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
    am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
    am.QueueBuiltinAction(keychord_init_action, "keychord_init");
    am.QueueBuiltinAction(console_init_action, "console_init");

    // Trigger all the boot actions to get us started.
    am.QueueEventTrigger("init");

    // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
    // wasn't ready immediately after wait_for_coldboot_done
    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");

    // Don't mount filesystems or start core system services in charger mode.
    std::string bootmode = property_get("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");

    while (true) {
    //while循环不断调用ExecuteOneCommand函数时,匹配的action。
        if (!waiting_for_exec) {
            am.ExecuteOneCommand();
            restart_processes();
        }

        int timeout = -1;
        if (process_needs_restart) {
            timeout = (process_needs_restart - gettime()) * 1000;
            if (timeout < 0)
                timeout = 0;
        }

        if (am.HasMoreCommands()) {
            timeout = 0;
        }

        bootchart_sample(&timeout);

        epoll_event ev;
        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
        if (nr == -1) {
            ERROR("epoll_wait failed: %s\n", strerror(errno));
        } else if (nr == 1) {
        //通过epoll来监听,处理属性服务相关的事情。
            ((void (*)()) ev.data.ptr)();
        }
    }

    return 0;
}

我们对上面的代码进行总结:
1.创建文件系统目录并挂载相关的文件系统。
2.初始化内核log系统。
3.初始化属性相关资源,利用ashmem共享。
4.设置SELinux policy策略

  • Android 使用 SELinux 对所有进程强制执行强制访问控制 (MAC),其中包括以 Root/超级用户权限运行的进程(也称为 Linux 功能)。SELinux 能够限制特权进程并能够自动创建安全政策,从而可提升 Android 的安全性。
  • 关于SELinux 中有详细的介绍。(https://source.android.com/security/selinux/)。需要翻墙。

5.创建epoll句柄。

  • epoll仅仅是一个异步事件的通知机制,其本身并不作任何的IO读写操作,它只负责告诉你是不是可以读或可以写了,而具体的读写操作,还要应用程序自己来完成。
  • 该函数生成一个epoll专用的文件描述符。它其实是在内核申请一空间,用来存放你想关注的fd上是否发生的事件。size就是你在这个epoll fd上能关注的最大fd数,这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值。需要注意的是,当创建好epoll句柄后,它就会占用一个fd值,在Linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。

6.启动属性服务。

//system/core/init/property_service.cpp
void start_property_service() {
    property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                    0666, 0, 0, NULL);
    if (property_set_fd == -1) {
        ERROR("start_property_service socket creation failed: %s\n", strerror(errno));
        exit(1);
    }

    listen(property_set_fd, 8);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值