安卓系统启动
揭秘安卓系统启动,今天我们来探究一下安卓系统启动整个过程,让我们系统运行有一个更好的了解。
Android 系统底层是基于 Linux 操作系统。当用户按下开机之后,安卓设备要经过 BootLoader、Linux Kernel 和安卓 SystemServer 三个阶段才能完全启动。当 Linux Kernel 启动会创建 Init 进程,该进程是所有用户空间的开始,进而会启动 ServiceManager,Zygote 进程。Zygote 进程继而创建 SystemServer 等进程。 整个系统启动的流程图如下:
Boot Rom
当用户按下开机之后,Boot ROM的代码会开始执行,并将Bootloader加载到RAM中并开始执行
Boot Loader
引导加载程序
kernel
Android 内核层,Android内核启动,会开始设置缓存,受保护的内存,调度和加载驱动程序,并开始准备启动init进程. 我们可以看一下安卓内核程序如何启动的: adb shell ps -e ..
init
先看看整个流程图:
platform/system/core/init/init.cpp.当 kernel 启动后就会调用init.cpp 里的main方法,我们分析main方法,总结下init进程主要执行了以下功能:
- 赋予一些文件权限、初始化运行环境,创建磁盘并挂载文件系统,初始化内核log系统和用户log系统以及selinux初始化等操作
- 信号处理,处理子进程的终止功能,防止子进程形成僵尸进程占用cpu资源
- 提供属性服务
- 解析并运行Init.rc文件
系统初始化
信号处理
代码路径:platform/system/core/init/sigchld_handler.cpp ,我们先了解以下安卓信号处理的作用:
采用信号处理方式可以有效防止僵尸进程的产生。在init.cpp的面函数中有signal_handler_init() 方法来初始化信号处理过程。该函数会创建一个socketpair的全双工通信管道用来读取和写入数据。socketpair()函数是Linux用于创建创建无名的相互连接的套接字可以在同一个进程中进行读写操作。每个进程在处理其他进程发送的signal信号时都需要先注册,当其子进程终止就会产生SIGCHLD信号,init进程捕捉到该信号写入signal_write_fd中,然后通过signal_read_fd可读,触发handle_signal 函数进一步调用ReapAnyOutstandingChildren()来调用ReapOneProcess函数的ServiceList::GetInstance().RemoveService(*service)来移除该进程。
属性服务
代码位置/system/core/init/propertice_service.cpp
在启动属性服务之前,init 进程会先执行property_init()方法。
属性服务执行过程如下:
- 属性初始化会先执行__system_property_area_init(),用于创建跨进程的共享内存,用于存储增加和修改的属性内容。
- 接着系统会将默认的prop文件加载到共享内存中,根据函数实现主要有以下文件的属性配置先加载到共享内存中去:
/system/build.prop;
/vendor/build.prop;
/factory/factory.prop;
/data/local.prop;
/data/property
- 开启属性服务,系统开启属性服务会先创建一个名为 property_service 的 socket ,用来监听来自进程写系统属性的请求,同时注册在该socket上,注册一个epoll事件的回调函数handle_property_set_fd,用来接收socket绑定请求,并接收发送来的数据,调用property_set 来设置属性到共享内存中去。
- 获取属性 安卓系统有两个接口访问系统属性:
解析并运行Init.rc文件
我们先来看看 rc 文件是什么东西: rc文件是脚本文件,由四种类型构成
- Action
- Commands
- Options
- Service
init 进程会执行类似的代码,进而就会去加载init.rc 文件,当然还有很多其他的rc文件,毕竟系统启动的进程有很多,这里暂时不做概述,在init.rc文件里有如下代码:
根据以上代码,可以解析出以下内容:
ServiceName:zygote
Path:/system/bin/app_process64
Arguments:-Xzygote /system/bin --zygote --start-system-server
即是启动Zygote,因为是64位系统,该进程对应的程序路径为app_process64,对应的main函数的参数有-Xzygote /system/bin --zygote --start-system-server,以下就进入Zygote的启动过程了。
我们adb shell 进入系统,切到/system/bin 就可以看到app_process64这个可执行文件了,在系统编译期间,这些代码都被编译成了elf可执行文件,对于elf文件的介绍可以参见另一篇文章elf文件.
既然zygote进程已经被启动了,我们就来看看 zygote 这个神奇的进程。
zygote
zygote 即安卓系统的孵化器,由 init 进程 fork 出来,作用也是望文生义,用来孵化进程的。孵化出了 systemserver,app 进程等。
zygote 进程启动时序
init进程通过解析rc文件来调用app_main.cpp的main函数。 Zygote整个启动过程函数调用如下:
- App_main.main()
- AndroidRuntime.start()
- startVm()
- startReg()
- ZygoteInit.main()
- registerZygotesocket()
- preload()
- startSystemServer()
- runSelectLoop()
下面来一步步解析,走入 Zygote 进程的世界:
- app_main
代码路径
/frameworks/base/cmds/app_process/App_main.cpp
根据main函数的上述代码以及rc文件解析的内容的传入参数中可以得出zygote = true 和 startSystemServer = true。zygote 会执行 runtime.start()来启动AndroidRuntime即安卓虚拟机。
-
AndroidRuntime runtime.start() -> AndroidRuntime.start(),虚拟机的启动过程可以参看另一篇文章ART虚拟机 start 函数主要流程如下:
-
初始化 JNI 环境,在启动虚拟机前,调用jni_invocation.Init(NULL)来初始化当前运行环境,获取JNI_CreateJavaVM环境等。此处逻辑并不复杂,但是代码量过大,就不贴代码了,主要就是根据环境变量获取一些系统参数,复制给虚拟机参数,虚拟机拥有的参数及其庞大,毕竟可以理解了屏蔽了硬件的操作系统了。
-
启动虚拟机 我们来看看虚拟机启动过程
-
注册 native 函数,调用 startReg(env) 注册本地函数,为 native 本地函数提供加载到虚拟机的入口。
-
通过反射执行调用 env→CallStaticVoidMethod(startClass, startMeth, strArray)找到目标函数ZygoteInit的main函数。
下面就进入 java 世界里。
ZygoteInit
代码路径/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
ZygoteInit主要完成了以下功能:
systemserver
SystemServer 的启动过程比较简单,主要通过main()函数调用run()方法,调用Looper.prepareMainLooper()创建一个主线程Looper,加载一些android——services的lib资源,处理启动System Services的相关环境配置等。 准备工作做好了,接下来就准备启动services
由上可知systemserver启动过程如下:
调用Looper.prepareMainLooper()创建一个主线程Looper
加载一些android——services的lib资源,处理启动System Services的相关环境配置等
启动startBootstrapServices()系统引导相关服务
启动startCoreServices()系统核心服务
启动startOtherServices()其他服务
至此,整个系统就已经完全启动了SystemServer将进入Looper.loop()的长循环中。
home 画面启动
home启动过程也较为复杂,具体参看home启动
总结
根据以上过程,我们可以总结一下啊安卓系统启动流程了