当我们按下电源键,Android 究竟做了些什么?

qcloudcommunity · · 1831 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

**欢迎大家前往[腾讯云+社区](https://cloud.tencent.com/developer/?fromSource=waitui),获取更多腾讯海量技术实践干货哦~** > 本文由[goo](https://cloud.tencent.com/developer/user/2557878)发表于[云+社区专栏](https://cloud.tencent.com/developer/column/73035?fromSource=waitui) > 相信我们对Android系统都不陌生,而Android系统博大精深,被各种各样的智能设备承载的同时,我们会否好奇过,如此复杂的Android究竟是怎么运作起来的呢?借本文给大家分享,笔者对Android 系统启动流程的整体理解~ ![img](https://ask.qcloudimg.com/draft/2557878/bz2o8pg9te.png?imageView2/2/w/1620)hi, I'm Android ## 现在,按下电源键 下面是Android启动的核心步骤流程图,看文字的时候,记得回来对照图来理解喔,希望阅读全文后,回观流程图,会有恍然大悟的感觉,那么文章的目的就达到啦~ ![img](https://ask.qcloudimg.com/draft/2557878/5i2gmf1832.png?imageView2/2/w/1620)整体流程 ## 一、启动电源及系统启动 系统从 ROM 中开始启动,加载引导程序到 RAM ,然后执行。 ## 二、引导程序 引导程序是 Android 操作系统开始运行前的一个小程序,因此它需要针对特定主板与芯片,**并不是 Android 操作系统的一部分**。引导程序是 OEM 厂商或运行商进行**加锁、限制**的地方。 ### 1 两个阶段 1. 检测外部 RAM 以及为第二阶段加载程序 2. 设置网络、内存等,搭建内核运行环境(为了达到特殊目的时,引导程序可以根据配置参数或者输入数据来设置内核) ### 2 引导程序的加载器 Android引导程序可以在\bootable\bootloader\legacy\usbloader找到,传统的加载器包含的两个文件: 1. init.s 初始化**堆栈**,清零**BSS段**,会调用 main.c 中的 _main()函数 (**bss segment:**通常是指用来存放程序中**未初始化的全局变量**的一块内存区域;BSS - Block Started by Symbol。BSS段属于静态内存分配) 2. main.c 初始化硬件,创建 linux 标签 ## 三、内核启动 Android 内核启动方式类似桌面 linux,主要步骤: **1. 设置缓存** **2. 被保护存储器** **3. 计划列表** **4. 加载驱动** 当内核完成系统设置,接下来即将启动系统的第一个进程 -- **init 进程** ## 四、init 进程 作为 Android 系统的第一个进程,其PID为0,通过解析 **init.rc 脚本**来构建出系统初始运行形态,这一阶段中,“Android” logo 会显示出来 (系统中,**大多数系统服务程序**都是在**该脚本**中描述并被相继启动的) init.rc 由**4种类型声明**组成:**Actions、Commands、Services、Options** - **Actions:**响应某事件的过程。当“trigger”所描述的触发事件产生时,则依次执行各种“command” **源码角度:**系统会对 **init.rc** 中各**“trigger”**进行匹配,当发现符合条件的 Action,就将它加入**“命令执行队列”**尾部(除非 Action 已存在队列中),然后系统再对这些命令按顺序进行。on <trigger> ##触发条件 <command1> ##执行命令 <command2> ##可执行多个命令 ... - **Commands:**命令将在所属事件发生时被一个个执行 - **Services:**可执行程序,它们在特定选项的约束下会被 init 程序运行或者重启(Service 可以在配置中指定**是否需要退出重启**,那么,当 Service 出现异常 crash 时,可有机会复原)service <name><pathname> [<argument>]* <option> <option> - **Options:**对 service 的约束选项 ## 五和六、 ServiceManager、Zygote、SystemServer **科普:**Daemons - 守护进程 init进程通过解析 init.rc 来陆续启动其他关键的系统服务进程,其中最重要的是 **ServiceManager、Zygote 和 SystemServer** 三者,下面我们逐一解析: ### 1 ServiceManager -- Binder 机制支撑者 **概述:**ServiceManager 是 **Binder 机制**中的**支撑者**,负责某 **Binder 服务注册信息**到底层 **Binder 驱动分配的值**解析。 ServiceManager 由 init 进程解析 rc 脚本时启动,属于 **core 类**,其他同类进程包括:uenetd、console、adbd等。根据 core 组的特性,这些进程会**同时启动或停止**。另外,ServiceManager 配置含有 **critical 属性**,这意味着它是**系统关键进程**(如果进程不幸在4分钟内异常退出超过4次,设备将重启并进入还原模式)。当 ServiceManager 每次重启时,其他关键进程:zygote、media、surfaceflinger 等也会被 restart。 ### 2. Zygote -- “孕育”新线程与进程 Android 中大多数应用进程与系统进程都是通过 Zygote 来生成的。Zygote 同样由 init 解析 rc 脚本时启动,属于 **main 类**,同属 main 类的系统进程有:netd、debuggerd、rild等。Zygote并不是处于独立的程序中的,它所在程序名为**“app_process”**,观察 app_process 主函数实现知道,如果 init.rc 中指定了 --zygote选项,app_process 接下来将启动**“ZygoteInit”**,并传入**“start-system-server”**,这样,ZygoteInit 就会运行在虚拟机上(Dalvik VM)上了。 - **ZygoteInit 函数有两项重要工作** - 预装载各种系统类 - 搭建 SystemServer 环境,并启动 SystemServer(大部分的 Android 系统服务都在其中,由 Java 编写) - ZygoteInit 流程总结 ( 摘自:Gityuan -- Android 系统启动-Zygote 篇 ) 1. 解析init.zygote.rc中的参数,创建AppRuntime并调用AppRuntime.start()方法; 2. 调用AndroidRuntime的startVM()方法创建虚拟机,再调用startReg()注册JNI函数; 3. 通过JNI方式调用ZygoteInit.main(),第一次进入Java世界; 4. registerZygoteSocket()建立socket通道,zygote作为通信的服务端,用于响应客户端请求; 5. preload()预加载通用类、drawable和color资源、openGL以及共享库以及WebView,用于提高ap启动效率; 6. zygote完毕大部分工作,接下来再通过startSystemServer(),fork得力帮手system_server进程,也是上层framework的运行载体。 7. zygote功成身退,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。 ZygoteInit 结束后,开机Logo就出来了。 (注意:这里并不包括开机动画,而是开机前 “Android” Logo 出现的那个画面,开机动画出现之前还需要进行各种加载,开机动画是在“Android” Logo 出现之后才播放的) ### 3. SystemServer -- 大部分 Android 系统服务所在地 SystemServer 是 Android 进入 Launcher 前的最后准备,它提供了众多的由“Java”语言编写的**系统服务**。 如果 init.rc 中为 zygote 指定启动参数 --start-system-server,那么 ZygotyeInit 就会调用 startSystemServer 来进入 SystemServer。 - **startSystemServer函数解析:** - 首先 ZygoteInit 通过 **Zygote.forkSystemServer** 来生成一个新的线程(fork),用于承载各种**系统服务**。(源码角度:Zygote 内部由 Native 函数 **Dalvik_dalvik_system_Zygote_forkSystemServer** 来进一步实现,最终调用底层接口的 **fork 接口**来实际产生进程) - 根据fork特性,子进程与父进程将获得**相同的代码环境**。**pid为0为子进程**,否则为父进程;如果是**前者**,则进一步调用 **handleSystemServerProcess(parseArgs)** 函数来完成最核心的工作 -- **“启动各系统服务”**(源码角度:handleSystemServerProcess 方法将 startSystemServer 中的 **parsedArgs.remainingArgs** 参数传给 **RuntimeInit.zygoteInit**,后者又调用 **nativeZygoteInit 函数**) - nativeZygoteInit 调用后,接着,三个重要的 static 函数就要被执行了:**init1 - 完成本地Service(SurfaceFlinger、AudioFlinger等)启动,完成后调用 init2**、**init2 - 新建一个新的带 Looper 的线程 ServerThread来启动 Java层各 Service** ## 后语 上面对 Android 系统启动做了一个简述,意在给大家展现一个整体流程,其中每个环节涉及的知识点只是浅浅掠过,笔者也尚在学习与探索中,希望在后续再作详细分析。 ## 资源推荐 - [Gityuan - Android 开篇](http://gityuan.com/android/) - [老罗的Android之旅](http://blog.csdn.net/luoshengyang?viewmode=contents) - 《深入理解 Android 内核设计思想》 由浅入深,落实到源码层面上进行探索,知识很有深度 >**相关阅读** >[【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识](https://cloud.tencent.com/developer/edu/course-1128?fromSource=waitui) **此文已由作者授权腾讯云+社区发布,更多原文请[点击](https://cloud.tencent.com/developer/article/1360945?fromSource=waitui )** **搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包!** 海量技术实践经验,尽在[云加社区](https://cloud.tencent.com/developer?fromSource=waitui)!

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1831 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传