详解 Android 是如何启动的

本文是 Android 系统学习系列文章中的第一章节,从大体上说明 Android 系统是如何启动的?从开机到程序启动,发生了那些步骤,这些步骤意味着什么?欢迎进入今天的「走进科学」,逃 :)。对此系列感兴趣的同学,可以收藏这个链接 Android 系统学习,也可以使用 RSS 进行订阅。


系统分区划分

Android 达人都经历过刷机的体验,如果通过 fastboot 来进行刷机的话,会在刷机界面看到如下的几个步骤。这些步骤是做什么用的?就是通过 fastboot 协议更新和烧录到 Android 手机对应的分区上。对 fastboot 感兴趣的同学,可以点击这个 链接 进行查看。

fastboot flash boot boot.img
fastboot flash system system.img
fastboot flash userdata userdata.img
fastboot flash cache cache.img
fastboot flash recovery recovery.img
fastboot reboot

从 fastboot 的烧录过程中可以看出 Android 系统的大致分区,这里我也通过 adb shell 中的 df 命令查看了小米手机中的系统分区,如下图所示。

小米系统分区

一般而言,虽然各个手机厂商在在系统上的实现不一致,Android 系统分为下面表格中的几个部分。

Android 系统分区
分区 功能
boot 系统引导分区,包含着android 内核,系统没有这个无法启动。这一部分的镜像在 boot unlocked 时,也能够被擦除,但在这个过程中,不能被打断,关机等等,否者会导致系统无法启动。
system Android 整个系统所在地,也包含预装的应用(这是预装的APP,手机厂商盈利的一种渠道),
recovery 备份分区,启动时可进入 recovery ,然后在这个模式下进行相应的 recovery 操作。
data 应用程序相关的数据,例如你安装的豌豆荚,数据就放在 /data/data/com.wandoujia.phoenix2 下面,当进行恢复出厂设置时,这部分数据会被擦除掉。
cache 用于存放缓存相关的数据。
misc 存放一些硬件配置、USB 配置等等信息,如果被擦除可能会导致某些系统设备无法正常工作。

Android 系统启动

如我们所知,Android 系统是基于 Linux 系统开发而成,在其中针对移动设备的特性进行了相应的调整,所以 Android 系统大体上可以分为 Linux 内核部分和 应用系统部分。在 Android 系统启动的时候,也会先启动 Linux 内核,然后再启动应用系统。整个启动步骤分为 6 个部分,在下面进行详细的描述。

Android 系统启动
Android 系统启动

启动电源以及系统启动

当电源按下,引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序到RAM,然后执行。

Boot Loader

Android系统是基于Linux操作系统的,所以它最初的启动过程跟Linux一样。当设备通电时,首先执行BootLoader引导装载器,BootLoader是在操作系统内核运行之前运行的一小段程序。BootLoader 的概念在各个操作系统 windows, mac, Android 中都存在。通过这段小程序初始化硬件设置,建立内存空间映射图,从而将系统的软硬件环境导入到合适的状态,以使为最终调用操作系统内核准备好正确的运行环境。

BootLoader 在任何软件之前执行,因而也没有类似于虚拟机那样的概率来屏蔽不同运行环境的差异,因而某个主板都有特定的BootLoader。另一方面,iOS 系统由于其各个版本间的稳定性,因而不同版本件的 BootLoader 差异不大。另一方面,Android OS 是开源系统,其可以运行在不同的硬件上,这些硬件千差万别,因而在 Android 上的 BootLoader 也各有不同。

一般而言 BootLoader 出于锁闭状态,毕竟厂商开发出系统后,还是希望在 ROM 上的 Android 系统保持不变。因而刷机的第一步,往往是解锁 BootLoader.

总结起来,BootLoader 完成的工作是:

  1. 初始化 RAM
  2. 初始化基础硬件,例如 WIFI
  3. 加载内核和内存空间映射图
  4. 跳转到内核中

内核模块

内核模块,负责了大部分的硬件、驱动和文件系统的初始化,这部分都在内核空间完成,不涉及用户空间的内容。内核模块的初始化是非常硬件相关的,目的就是使得 CPU 能够更快地执行 C 代码,然后在这执行完毕后,初始化各个子系统,来执行 init 进程。

Init 进程

Init 进程作为第一个执行的进程,开天辟地。这个进程主要做两件事情,挂在相应的目录(/sys,/dev 等等),另一方面是执行 init.rc 脚本,可通过 init.rc 源码 查看相应的链接。

Init 进程会启动 Runtime 运行时服务,所谓的 Runtime 服务就是将中间代码静态编译成本地代码。而 Android 所使用的 Java 动态执行,所依附的正式这个 Runtime 环境。

其后,Init 进程会启动一些本地守护进程,这些守护进程启动后,会初始化其相应的模块,在其中最特别的就是 Zygote。不过 Init 进程不会直接启动 Zygote 进程,而是使用 app_process 命令来通过 Android Runtime 来启动,Android Runtime 会启动第一个 Davlik 虚拟机,并调用 Zygote 的 main 方法。

Zygote and Dalvik

对于每一个运行的程序,Android 都会赋予其单独的虚拟机,以支持其运行,但每一次新建虚拟机的开销都不小,那么如何来缩短这个时间了?尤其是针对嵌入式设备,都希望相应速度能够达到理想的状况。Zyogte 就是用来解决这个问题的,其中文意思是受精卵。从这个名字上可以看出,其余的应用进程都是通过 fork 这个进程来实现的,他们共享相同的内存区域,这样能减少不少的内存占用开销和应用启动时间。

为了加速 App 的启动,Zygote 进程会预先加载 App 在运行时所需的资源和 Class 文件到系统 RAM 中。Zygote 会监听其 Socket (/dev/socket/zygote) 来判断是否需要启动 App。每当监听到需要创建 App 的请求时,就 fork 一个进程即可。这样的好处在于最初始的 Zygote 进程,保有所有的系统 Class 和 App 启动可能需要的资源,这样一来,就不需要启动一个 App 时,动态去加载相应的资源。

监听 /dev/socket/zygote socket.

/**
 * Registers a server socket for zygote command connections
 *
 * @throws RuntimeException when open fails
 */
private static void registerZygoteSocket(String socketName) {
    if (sServerSocket == null) {
        int fileDesc;
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
        try {
            String env = System.getenv(fullSocketName);
            fileDesc = Integer.parseInt(env);
        } catch (RuntimeException ex) {
            throw new RuntimeException(fullSocketName + " unset or invalid", ex);
        }

        try {
            sServerSocket = new LocalServerSocket(
                    createFileDescriptor(fileDesc));
        } catch (IOException ex) {
            throw new RuntimeException(
                    "Error binding to local socket '" + fileDesc + "'", ex);
        }
    }
}

为何在 Android 中 fork Zygote 进程如此高效了?Linux Kernel 采用了 Copy-On-Write 的技术,Copy-On-Write 的意思是只有在写的时候才单独复制一份,而读的时候不进行操作。 换而言之 fork zygote 实际上并未实际复制什么东西,只有在发生写操作时,才单独复制一份。而另一方面,class 和 Resource 资源文件并不需要重新写,这些文件在绝大多数时候都是只读的。最后,实际的效果就是尽管运行着多个 APP,但实际只有一份 class 和 resource 文件在 Zygote 进程中。

System Server 和 系统服务

绝大多数 App 都是通过 fork Zygote 进程来完成了,只有一个例外,那就是 System Sever。在启动 System Server 之后,其他系统服务将自己注入到 System Server 中,同时其他系统服务也完成启动。这些服务主要包括,Power Manager,Telephony Registry,Battery Service,Window Manager等等。在这其中也包括我们熟知的 Activity ManagerActivity Manager在启动完成后,会发送一个 Intent.CATEGORY_HOME 的 intent,从而我们就能看到我们熟知的桌面。

Android 桌面

由于之前对 System Server 进行过详细的讲解,这里就不在赘述,感兴趣的同学可以查看这篇文章 Android Binder 全解析(2) -- 设计详解

总结

上述章节把 Android 启动中发生的事情表述完毕,现在没有什么比下面这张图更能总结观点了。


Android 启动

参考文献


文档信息

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,050评论 25 707
  • 1:InputChannel提供函数创建底层的Pipe对象 2: 1)客户端需要新建窗口 2)new ViewRo...
    自由人是工程师阅读 5,199评论 0 18
  • 女主为全世界最大财团的继承人 从小被抛弃 自己闯荡 美貌 性格复杂 家里人找不到她 她知道家在哪里却不想回 有一身...
    羽乔毛球阅读 614评论 0 3
  • 练习内容 小球运动代码练习5遍 scan 第一章文字内容 感想 抄了4遍就可以默写了 默写出来就可以不用抄了 附件
    周偉誠阅读 129评论 0 0
  • 今天有些累,来例假,又上了三节课,下午回来,饭也不想做,就摊在床上休息了一会。 生活让我们有时清闲,有时累,只有这...
    清空妙有阅读 128评论 1 1