当按下Android设备上的电源键时发生了什么?
Android的启动过程是怎样的?
什么是linux内核?
桌面系统的linux内核和Android系统的linux内核之间有什么不同?
什么是Bootloader?
什么是Zygote?
什么是x86和ARM linux?
什么是init.rc?
什么是系统服务?
当我们在思考Android启动过程的时候,脑海中总是会浮现出这么多的问题。
在这里我将为你解释Android的启动过程,希望能帮助你找到以上这些问题的答案。
Android是一个基于linux内核的开源操作系统,x86(x86是指一系列计算机微处理器指令集架构,这些指令集架构基于intel 8086 CPU)是linux内核部署最常见的系统。然而,所有的Android设备都运行在ARM处理器(ARM(来源于高级精简指令集机器,而这又来源于ARM架构))上,当然,英特尔的Xolo设备(http://xolo.in/xolo-x900-features)除外,Xolo来源于Atom 1.6GHz x86处理器。Android设备(或者嵌入式设备,又或者基于linux的ARM设备)的启动过程与桌面版本相比有一点差别。这篇文章中,我将只解释 Android设备的启动过程。关于基于linux的桌面系统的启动过程,推荐大家阅读Inside the linux boot process这篇文章。
当你按下电源开关后,Android设备执行了以下步骤
第一步:开机和系统启动
当电源按下,引导芯片代码从预定义的地方(固化在ROM)开始执行。加载Bootloader到RAM,然后执行。
第二步:Bootloader
Bootloader是在Android操作系统运行之前运行的一个小程序。Bootloader是运行的第一个程序,所以它是针对特定的主板与芯片的。设备制造商要么使用比较流行的的Bootloader,比如redboot、uboot、qi bootloader,要么开发自己的Bootloader,它不属于Android操作系统的部分。Bootloader是OEM厂商或者运营商加锁和限制的地方。
Bootloader分两个阶段执行。第一个阶段,检测外部RAM以及加载对第二阶段有用的程序,第二阶段,Bootloader设置网络、内存等等。这些对于运行内核是必要的,为了某些特定的目标,Bootloader可以向内核提供配置参数或者输入数据。
Android的Bootloader可以在<Android Source>\bootable\bootloader\legacy\usbloader目录找到。传统的加载器包含两个重要的文件,需要在这里说明:
1. init.s --- 初始化堆栈,清零BBS段,调用main.c中的_main()函数
2. main.c --- 初始化硬件(闹钟、主板、键盘、控制台),创建linux标签
要了解更多关于Android Bootloader的知识可以参考这个连接:
第三步:内核
Android内核的启动与桌面linux内核启动的方式类似。内核启动时开始设置高速缓存、内存保护机制、调度,加载驱动程序。当内核完成系统设置后,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第一个进程。
第四步:init进程
init是第一个进程,我们可以管它叫root进程或者所有进程的父进程。init进程有两个任务,1. 挂载目录,比如/sys、/dev、/proc。2. 运行init.rc脚本。
· init进程可以在<Android Source>/system/core/init找到
· init.rc文件可以在<Android Source>/system/core/rootdir/init.rc找到
· readme.txt可以在<Android Source>/system/core/init/readme.txt找到
对于init.rc文件,Android中有特定的格式和规则。在Android中,我们称之为Android初始化语言。
Android初始化语言由四大类型的声明组成,分别是:Actions(动作)、Commands(命令)、Services(服务)、以及Options(选项)。
Action(动作):Action(动作)就是一些命名的命令序列,Action(动作)有一个触发器,用来决定这个Action(动作)何时发生。
语法如下
n <trigger>
<command>
<command>
<command>
Service(服务):Service(服务)是一些由init进程启动的程序、当这些Service(服务)退出时init进程会根据情况将其重启。
语法如下
service <name> <pathname> [<argument>]*
<option>
<option>
...
Options(选项):Options(选项)是对服务的描述。它们影响init进程如何以及何时启动服务。
让我们看看默认的init.rc文件。这里我只列出了主要的事件以及服务。
Action/Service | 描述 |
on early-init | 设置init进程以及它创建的子进程的优先级。 为init进程设置安全环境。 |
on init | 设置全局环境 为cpu accounting创建cgroup(资源控制)挂载点 …… |
on fs | 挂载mtd分区 |
on post-fs | 更改系统目录的访问权限 |
on post-fs-data | 更改/data目录及其子目录的访问权限 |
on boot | 基本网络的初始化,内存管理等等 |
Service servicemanager | 启动系统的服务管理器来管理所有的本地服务,比如位置、音频、Shared preference等等 |
service zygote | 启动zygote进程 |
在这个阶段你就可以在设备的屏幕上看到“Android”logo了。
第五步:Zygote和Dalvik
在Java中,我们知道不同的虚拟机实例会为不同的应用分配不同的内存。假如Android应用应该尽可能快地启动,如果Android系统为每一个应用启动不同的Dalvik虚拟机实例,就会消耗大量的内存和时间。因此,为了克服这个问题,Android系统创造了”Zygote”。Zygote使得Dalvik虚拟机共享代码、低内存占用和最小的启动时间成为可能。Zygote是一个虚拟机进程,正如我们在前一个步骤所说,它在系统启动时启动。 Zygote预加载并且初始化核心类库。通常,这些核心类都是只读的,是Android SDK或者核心框架的一部分。在Java虚拟机中,每一个实例都有它自己的核心库类文件和堆对象的拷贝。
Zygote加载进程
1. 加载ZygoteInit类,源代码:<Android Source>/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
2. registerZygoteSocket() --- 为zygote命令连接注册一个服务器套接字
3. preloadClasses()---“preloaded-classes”是一个简单的包含一系列需要预加载类的文本文件,你可以在<Android Source>/frameworks/base找到“preloaded-classes”文件。
4. preloadResources() --- preloadResources意味着本地主题和布局以及android.R文件中包含的所有东西都会用这个方法加载。
在这个时候,你可以看到开机动画。
第六步:系统服务或服务
完成了上面几步之后,Runtime请求Zygote启动系统服务。系统服务同时使用native以及java编写,系统服务可以认为是一个进程。同一个系统服务可以以System Services的形式在Android SDK获得。系统服务包含了所有的System Services。
Zygote创建新的进程去启动系统服务。你可以在ZygoteInit类的”startSystemServer”方法中找到源代码。
核心服务:
1. 启动电源管理器
2. 创建Activity管理器
3. 启动电话注册
4. 启动包管理器
5. 设置Activity管理服务为系统进程
6. 启动上下文管理器
7. 启动系统Context Providers
8. 启动电池服务
9. 启动定时管理器
10. 启动传感服务
11. 启动窗口管理器
12. 启动蓝牙服务
13. 启动挂载服务
其他服务:
1. 启动状态栏服务
2. 启动硬件服务
3. 启动网络状态服务
4. 启动连接服务
5. 启动通知管理器
6. 启动设备存储监视服务
7. 启动定位管理器
8. 启动搜索服务
9. 启动剪切板服务
10. 启动登记服务
11. 启动壁纸服务
12. 启动音频服务
13. 启动耳机监听
14. 启动AdbSettingsObserver(处理adb命令)。
第七步:启动完成
一旦系统服务在内存中运行起来,Android就完成了启动过程。在这个时候“ACTION_BOOT_COMPLETED”广播就会发出去。
原文:In Depth : Android Boot Sequence / Process