从按下电源键到android桌面启动到底发生了什么?

What happened between power button pushed and the desktop began

Posted by Roger on August 14, 2015

最近研究了一下andorid的启动过程,记录一点心得.

学习资料主要为这两篇博客: Android Framework启动流程分析 Android启动过程深入解析,感谢博主.

总流程可以用一张图说明:

image

此处图片中step2中的一个单词拼写错了,Boot Loaeder应该为Boot Loader

我们知道android是基于Linux系统的,那么按下电源键首先启动的自然是linux系统内核.

第一步,启动电源执行引导程序

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

引导程序是在Android操作系统开始运行前的一个小程序。引导程序是运行的第一个程序,因此它是针对特定的主板与芯片的。设备制造商要么使用很受欢迎的引导程序比如redboot、uboot、qi bootloader或者开发自己的引导程序,它不是Android操作系统的一部分。引导程序是OEM厂商或者运营商加锁和限制的地方。

引导程序分两个阶段执行。第一个阶段,检测外部的RAM以及加载对第二阶段有用的程序;第二阶段,引导程序设置网络、内存等等。这些对于运行内核是必要的,为了达到特殊的目标,引导程序可以根据配置参数或者输入数据设置内核。

Android引导程序可以在\bootable\bootloader\legacy\usbloader找到。

传统的加载器包含的个文件,需要在这里说明:

init.s初始化堆栈,清零BBS段,调用main.c的_main()函数;

main.c初始化硬件(闹钟、主板、键盘、控制台),创建linux标签

第二步,Linux系统内核

Linux内核加载主要包括初始化kernel核心(内存初始化,打开中断,初始化进程表等)、初始化驱动、启动内核后台(daemons)线程、安装根(root)文件系统等。

Linux加载的最后阶段启动执行第一个用户级进程init(内核引导参数上一般都会设置“init=/init”,由kernel自动执行,PID为1,是所有进程的父进程)。由此进入Android框架的启动阶段。

第三步,init进程

进入android框架启动阶段可以用一张图说明:

image

init是第一个进程,我们可以说它是root进程或者说有进程的父进程.init进程有两个责任,一是挂载目录,比如/sys、/dev、/proc,二是运行init.rc脚本.

init.rc文件是Android系统的重要配置文件,位于/system/core/rootdir/目录中.主要功能是定义了系统启动时需要执行的一系列action及service:执行特定动作、设置环境变量和属性和执行特定的service.该脚本在init进程的init.c:main函数中解析并启动.

重点说明的是init.rc脚本文件配置了一些重要的服务,init进程通过创建子进程启动这些服务,这里创建的service都属于native服务,运行在Linux空间,通过socket向上层提供特定的服务,并以守护进程的方式运行在后台.

通过init.rc脚本系统启动了以下几个重要的服务:

1)servicemanager:启动binder IPC,管理所有的Android系统服务

2)mountd:设备安装Daemon,负责设备安装及状态通知

3)debuggerd:启动debug system,处理调试进程的请求

4)rild:启动radio interface layer daemon服务,处理电话相关的事件和请求

5)mediaserver:启动AudioFlinger,MediaPlayerService and CameraService,负责多媒体播放相关的功能,包括音视频解码、显示输出

6)zygote:进程孵化器,启动Android Java VMRuntime和启动systemserver,负责Android应用进程的孵化工作

在这个阶段你可以在设备的屏幕上看到“Android”logo了.

第四步,zygote服务启动

在Java中,我们知道不同的虚拟机实例会为不同的应用分配不同的内存。假如Android应用应该尽可能快地启动,但如果Android系统为每一个应用启动不同的Dalvik虚拟机实例,就会消耗大量的内存以及时间。因此,为了克服这个问题,Android系统创造了”Zygote”。Zygote让Dalvik虚拟机共享代码、低内存占用以及最小的启动时间成为可能。Zygote是一个虚拟器进程,正如我们在前一个步骤所说的在系统引导的时候启动。Zygote预加载以及初始化核心库类。通常,这些核心类一般是只读的,也是Android SDK或者核心框架的一部分。在Java虚拟机中,每一个实例都有它自己的核心库类文件和堆对象的拷贝。

zygote进程孵化了所有的Android应用进程,是Android Framework的基础,该进程的启动也标志着Framework框架初始化启动的开始。zygote服务进程的主要功能:

1)注册底层功能的JNI函数到虚拟机

2)预加载java类和资源

3)fork并启动System Server核心进程

4)作为守护进程监听处理“孵化新进程”的请求

虚拟机启动后执行的第一个Java类是ZygoteInit.java,并进入ZygoteInit.java:main()函数中。在main函数中实现了以下逻辑:

1)启动服务端Socket端口:

调用registerZygoteSocket()实现,主要用于接受处理创建新进程的请求。

2)预加载指定的java类和资源:

调用preloadClasses()预加载指定的java类,调用preloadResources()预加载指定的Resources。特别说明的是孵化器进程会把这些预先加载的类和资源共享给所有APK应用进程,这样有效的解决了Framework类和资源共享的问题。

3)启动System Server进程:

调用startSystemServer()创建(fork)SystemServer进程。该函数的关键代码有三处:

—设定启动进程的相关信息:比如进程名称、启动后装载的第一个java类

—调用forkSystemServer()从当前的zygote进程孵化出新的进程

—调用函数hanldeSystemServerProcess()关闭从Zygote进程继承过来的Socket,调用RuntimeInit.zygoteInit()启动SystemServer.java:main()函数

4)循环监听孵化新Dalvik进程的请求:

调用runSelectLoopMode()进入无限循环:监听客户端socket连接,根据请求孵化新的应用进程。Process类中保存了客户端socket,并由ActivityManagerService管理该客户端。每当需要启动新的Dalvik应用进程时,ActivityManagerService都会通过该socket客户端与Zygote进程的socket服务端进行通信,请求Zygote孵化出新的进程。

至此,启动zygote服务工作完成,需要说明的是zygote进程即为app_process可执行程序所在进程。      在这个阶段,你可以看到启动动画.

第五步,System Server进程启动

SystemServer进程在Android的运行环境中扮演了“神经中枢”的作用,Android应用能够直接交互的大部分系统服务都在该进程中运行,如WindowManagerServer、ActivityManagerSystemService、PackageManagerServer等,这些系统服务都是以独立线程的方式存在于SystemServer进程中。System Server进程的主要功能:

1)加载android servers底层函数库

2)启动android系统中的native服务

3)创建、注册并启动Android的系统服务,在独立线程中运行

4)创建Looper消息循环,处理System Server进程中的事件消息

在zygote进程中调用函数startSystemServer()创建和启动Server进程,进程首先执行的函数是SystemServer.java:main()。该函数函数实现的主要逻辑为:

1)加载android_servers函数库

2)启动native服务:

调用本地函数init1()实现,该函数的源码位于文件frameworks/base/services/jni/com_android_server_systemService.cpp中,涉及的函数system_init()实现在文件frameworks/base/cmds/system_server/library/system_init.cpp中。

3)启动Android系统的各种系统服务:

调用函数init2()实现,该函数首先创建了一个ServerThread对象,该对象是一个线程,然后直接运行该线程.

从ServerThread的run()方法内部开始真正启动各种服务线程。

—创建Android系统服务对象,并注册到ServiceManager

—在SystemServer进程中建立Looper消息循环:通过Looper.prepare和Looper.loop来实现

—系统就绪通知:调用systemReady()通知各个服务

System Server进程启动过程中最核心的一步是“启动Android系统的各种系统服务”,这些系统服务构成了整个Android框架的基础(如图所示),通过Binder IPC为上层应用提供各种功能。

1)ActivityManagerService

Activity管理服务,主要功能包括:

—统一管理和调度各应用程序的Activity,维护系统中运行的所有应用Task和Activity

—内存管理:应用程序关闭时对应进程还在运行,当系统内存不足时根据策略kill掉优先级较低进程

—进程管理:维护和管理系统中运行的所有进程,并提供了查询进程信息的API

—Provider、Service和Broadcast管理和调度

2)WindowManagerService

窗口管理服务,主要功能包括为应用程序分配窗口,并管理这些窗口。包括分配窗口的大小、调节各窗口的叠放次序、隐藏或者显示窗口,程序退出时删除窗口。

3)PackageManagerService

程序包管理服务,主要功能为:

—根据intent查找匹配的Activity、Provider以及Service

—进行权限检查,即当应用程序调用某个需要一定权限的函数时,系统能够判断调用者是否具备该权限

—提供安装、删除应用程序的API

4)NotificationManagerService

通知管理服务,负责管理和通知后台事件的发生等,这个和statusbar服务结合在一起,一般会在statusbar上添加响应图标。用户可以通过这知道系统后台发生了什么事情。

5)AudioService

音频管理服务,AudioFlinger的上层管理封装,主要是音量、音效、声道及铃声等的管理。

6)TelephonyRegistry

电话服务管理,用于监听和上报电话状态,包括来电、通话、信号变化等。

到这里,Android Framework的启动已经完成,框架中提供的各种服务也已经就绪,可以正常运行并响应处理应用的各种操作请求。

第六步,Home应用启动

在ServerThread:run()函数的最后调用了ActivityManagerService.self().systemReady方法,该方法实现了如下代码用于启动第一个Activity:

mMainStack.resumeTopActivityLocked(null);

由于系统刚启动时没有任何Activity对象,代码会调用ActivityManagerService:startHomeActivityLocked函数启动Home应用:

  1. Intent intent = new Intent(
  2.     mTopAction,
  3.     mTopData != null ? Uri.parse(mTopData) : null);
  4. intent.setComponent(mTopComponent);
  5. if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
  6.     intent.addCategory(Intent.CATEGORY_HOME);
  7. }

至此桌面应用已经完全启动!以上都是一些学习笔记,许多都是复制粘贴做一些记录~还请大家多多参研原博哈~