前语

作为一个 Android 应用开发者,是否想过当你按下 Android 电源键翻开设备,从硬件到软件会产生什么?是否会有以下疑问:

  • 当设备开机动画出现时,屏幕后面终究产生了什么?
  • 手机或者汽车等设备终究怎么加载、引导并发动 Android 操作体系?

接下来的文章将会通过图文结合的办法来探究 Android 操作体系的发动流程。

Android 发动流程

每次 Android 设备开机时都会通过一次完好的发动流程。

Android 体系开发指北(二) - 体系发动流程

大致可分为 6 大步骤:

  1. Boot ROM 代码履行
  2. Bootloader 程序履行
  3. Linux 内核发动
  4. Init 进程发动
  5. Zygote 进程 和 Dalvik VM 虚拟机发动
  6. System Servers 和 Service Manager 发动

Boot ROM 代码履行

Android 设备上电之后,首先会从 SoC 上 Boot ROM 的发动引导代码开始履行。在此阶段会产生以下两件事:

  • 初始化设备硬件并测验扫描和检测引导介质。这块代码是固写在 Boot ROM 中无法改动的,相似于计算机发动进程中的 BIOS 功用。
  • 将初始的引导程序 Bootloader 复制到内部 RAM。

Bootloader 程序履行

Bootloader 是在 Android 体系发动前运转的一个微型程序,但它并不归于 Android 操作体系。OEM 通常会在该程序中设置确定和限制。

Bootloader 程序存在于台式计算机、笔记本电脑和移动设备中,而且它们的功用相似。在 Android 设备上,引导加载程序分为两个阶段:

  1. Initial Program Load (IPL)
  2. Second Program Load (SPL)
Initial Program Load (IPL)

IPL 担任检测可以进行 SPL 的外部 RAM。一旦检测到有外部 RAM 可用,SPL 就会被复制到该 RAM 中履行。

Second Program Load (SPL)

SPL 担任加载主 Android 操作体系并提供对其他发动形式的拜访,例如fastbootrecovery。SPL 还会初始化多个硬件组件,例如显现器、键盘、文件体系、虚拟内存、控制台和其他功用。尔后,SPL 会测验查找 Linux 内核。内核会在发动介质中被找到的,然后将其复制到 RAM。尔后,SPL 会将履行转移到内核。

Linux 内核

Android 内核的发动办法与 Linux 内核相似。当内核发动时,它首先会进行一系列体系设置:缓存、受维护的内存、调度和加载驱动程序。当内核结束体系设置后,接下来就会在体系文件中查找init

然而, Android 内核与 Linux 内核也有一些差异。以下是 Android 内核中新增定制的部分:

  • Binder: Android 特有的进程间通讯机制和长途办法调用体系。
  • ASHMEM: Android 同享内存,相似于 POSIX SHM,但具有不同的行为并具有更简略的基于文件的 API。
  • PMEM: 进程内存分配器,用于办理用户空间和内核驱动程序之间同享的大型(1-16+ MB)物理连续内存区域。
  • Logger: 内核对 logcat 指令的支撑。
  • Paranoid Networking: 依据呼叫进程组限制对某些网络功用的拜访。
  • Wake locks: 应用程序在手机空闲时坚持 CPU/屏幕/其他设备处于唤醒状况以履行特定后台任务的办法。通常用于电源办理文件。
  • OOM Handling: 内存办理模块,用以检查体系是否有满足的内存可用于履行任务,验证体系何时内存不足,并终止进程以开释内存。
  • Alarm Manager: 答应用户空间在想要唤醒时与内核进行通讯。
  • Timed output / Timed GPIO: GPIO 是一种答应程序从用户空间拜访和操作 GPIO 寄存器的机制。
  • RAM Console: RAM 中在发动时保留的区域。该区域是拥有持久特点,用于在内核重新发动或溃散时存储最后的内核日志消息。此处存储的日志关于内核调试非常有用,可以在溃散或意外重启之前立即深入了解内核进程。在/proc/last_kmsg中查看。
  • USB Gadget Driver for ADB
  • yaffs2 flash filesystem
  • 等…

Init Process

Init是 Android 体系的第一个进程,又称为根进程,是一切其他进程的父进程。Init 进程主要有两个责任。

  1. 挂载目录,如/sys,/dev/proc
  2. 解析运转init.rc脚本

init进程在:/system/core/init

init.rc文件在:/system/core/rootdir/

Android 关于init.rc文件的解说和履行有一套特定规矩,会在后续文章中详细介绍。

发动流程到了这个阶段,终于可以在设备屏幕上看到 Android Logo 了。

Zygote 和 Dalvik

在 Java 中,会为每一个应用程序在内存中分配出独自的虚拟机实例。而 Android 的 Dalvik(虚拟机)有所不同,因为它需要尽可能快。这就带来了一个问题。

如果有多个应用程序发动了多个 Dalvik 实例,导致可用内存耗尽,会产生什么?

Android 通过一个名为 Zygote 的体系解决了这个问题。

Zygote 是设备发动后 init 进程最先创立的进程之一。Zygote 支撑跨 Dalvik VM 同享代码,从而实现更低的内存占用和最短的发动时间。它是一个虚拟机进程,在体系发动时发动,并测验创立多个实例来支撑每个 Android 进程。Zygote 会预加载并初始化中心库类。

Zygote 加载进程
  • Load ZygoteInitclass:加载 ZygoteInit 类。

    源码:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

  • registerZygoteSocket():为 zygote 注册一个服务器套接字,供其他客户端树立跨进程连接。

  • preloadClasses():这是一个简略的文本文件,其间包含需要预加载的类列表。

    文件位置:/frameworks/base

  • preloadResources()资源文件,包含 android.R 文件的一切内容都将运用此办法加载:

发动流程到了这个阶段,设备屏幕将会显现发动动画。

System service

Zygote 进程会先 fork 出 SystemServer 进程,然后 SystemServer 进程担任将一切 Android 中心服务发动起来。

Android 体系开发指北(二) - 体系发动流程

注:这些 Android 服务并没有各自运转在独立的进程中,它们由 SystemServer 以线程的办法创立,所以都运转在同一个进程中,即 SystemServer 进程,并由它办理。

至此体系发动流程已结束。

此时体系将发送一个名为ACTION_BOOT_COMPLETED的广播,通知一切相关进程 boot process 已结束。

设备会显现 Home 主屏幕并准备好与用户交互。

总结

Android 体系开发指北(二) - 体系发动流程