Android 系统启动到App 界面完全展示终于明白(图文版)

3,438 阅读8分钟

前言

系列文章:

Android Activity创建到View的显示过程
Android 四大组件通信核心
Android 系统启动到App 界面完全展示终于明白(图文版)

之前文章有分析过Activity创建到View的显示过程,属于单应用层面的知识范畴,本篇将结合Android 系统启动部分知识将两者串联分析,以期达到融会贯通的目标。
通过本篇文章,你将了解到:

  1. Android 系统启动流程概览
  2. ServiceManager 进程作用
  3. Zygote 进程创建与fork子进程
  4. system_server 进程作用
  5. App 与 system_server 交互
  6. Activity 与 View的展示
  7. 全流程图

1. Android 系统启动流程概览

image.png

  • init 是用户空间的第一个进程,它的父进程是idle进程
  • init 进程通过解析init.rc 文件并fork出相应的进程
  • zygote是第一个Java 虚拟机进程,通过它孵化出system_server 进程
  • system_server 进程启动桌面(Launcher)App

以上为Android 系统上电到桌面启动的简略过程,我们重点关注其中几个进程:

init、servicemanger、zygote、system_server

idle 与 init 关系如下:

image.png

查看依赖关系:

image.png

init.rc 启动servicemanager、zygote 配置如下:

image.png

image.png

2. ServiceManager 进程作用

Android 进程间通信运用最广泛的是Binder机制,而ServiceManager进程与Binder息息相关。 DNS 存储着域名和ip的映射关系,类似的ServiceManager存储着Binder客户端和服务端的映射。

image.png

App1作为Binder Client端,App2 作为Binder Server端,App2 开放一个接口给App1使用(通常称为服务),此时步骤如下:

  1. App2 向ServiceManager注册服务,过程为:App2 获取ServiceManager的Binder引用,通过该Binder引用将App2 的Binder对象(实现了接口)添加到Binder驱动,Binder驱动记录对象与生成handle并返回给ServiceManager,ServiceManager记录关键信息(如服务名,handle)。
  2. App1 向ServcieManager查询服务,过程为: App1 获取ServiceManager的Binder引用,通过该Binder引用发送查询命令给Binder驱动,Binder驱动委托ServiceManager进行查询,ServiceManager根据服务名从自己的缓存链表里查出对应服务,并将该服务的handle写入驱动,进而转为App1的Binder代理。
  3. App1 拿到App2 的Binder代理后,App1 就可以通过Binder与App2进行IPC通信了,此时ServiceManager已经默默退居幕后,深藏功与名。

由上可知,ServiceManager进程扮演着中介的角色。

3. Zygote 进程创建与fork子进程

Zygote 进程的创建

Zygote 进程大名鼎鼎,Android 上所有的Java 进程都由Zygote孵化,Zygote名字本身也即是受精卵,当然文雅点一般称为孵化器。

image.png

Zygote 进程是由init进程fork出来的,进程启动后从入口文件(app_main.cpp)入口函数开始执行:

  1. 构造AppRuntime对象,并创建Java虚拟机、注册一系列的jni函数(Java和Native层关联起来)
  2. 从Native层切换到Java层,执行ZygoteInit.java main()函数
  3. fork system_server进程,预加载进程公共资源(后续fork的子进程可以复用,加快进程执行速度)
  4. 最后开启LocalSocket,并循环监听来自system_server创建子进程的Socket请求。

通过以上步骤,Zygote 启动完成,并等待创建进程的请求。

image.png

初始状态步骤:

  1. Zygote fork system_server 进程并等待Socket请求
  2. system_server 进程启动后会请求打开Launcher(桌面),此时通过Socket发送创建请求给Zygote,Zygote 收到请求后负责fork 出Launcher进程并执行它的入口函数
  3. Launcher 启动后用户就可以看到初始的界面了

用户操作:
桌面显示出来后,此时用户想打开微信,于是点击了桌面上的微信图标,背后的故事如下:

  1. Launcher App 收到点击请求,会执行startActivity,这个命令会通过Binder传递给system_server进程里的AMS(ActivityManagerService)模块
  2. AMS 发现对应的微信进程并没有启动,于是通过Socket发送创建微信进程的请求给Zygote
  3. Zygote 收到Socket请求后,fork 微信进程并执行对应的入口函数,之后就会显示出微信的界面了

用图表示如下:

image.png

由上可知,App进程和system_server 进程之间通信方式为Binder,而system_server和Zygote 通信方式为Socket,App进程并不直接请求Zygote做事情,而是通过system_server进行处理,system_server 记录着当前所有App 进程的状态,由它来统一管理各个App的生命周期。

Zygote 进程fork 子进程

image.png

Zygote 进程在Java层监听Socket请求,收到请求后层层调用最后切换到Native执行系统调用fork()函数,最后根据fork()返回值区分父子进程,并在子进程里执行入口函数。

4. system_server 进程作用

system_server 为所有App提供服务,可以说是系统的核心进程之一,它主要的功能如下:

image.png

可以看出,它创建并启动了许多服务,常见的AMS、PMS、WMS,我们常说系统某某服务返回了啥,往细的说这里的"系统"可以认为是system_server进程。
需要注意的是,这里所说的服务并不是Android四大组件的Service,而是某一类功能。

四大组件的交互也要依靠system_server:

image.png

实际调用流程如下:

image.png

由上图可知,不管是同一进程内的通信亦或是不同进程间的通信,都需要system_server介入。

App 和 system_server 是属于不同的进程,App进程如何找到system_server呢?
还是要借助ServiceManager进程:

image.png

system_server 在启动时候不仅开启了各种服务,同时还将需要暴露的服务注册到ServiceManager里,其它进程想要使用system_server的功能时只需要从SystemManager里查询即可。

5. App 与 system_server 交互

App 想要获取系统的功能,在大部分情况下是绕不过system_server的,接着来看看App如何与system_server进行交互。

前面分析过,App想要获取system_server 服务只需要从ServiceManager里获取即可,调用形式如下:

getSystemService(Context.WINDOW_SERVICE)

那反过来呢?system_server如何主动调用App的服务呢?
既然获取服务的本质是拿到对端的Binder引用,那么也可以反过来,将App的Binder传递给system_server,等到system_server想要调用App时候拿出来用即可,类似回调的功能,如下图:

image.png

再细化一下流程:

image.png

  1. App 进程在启动后执行ActivityThread.java里的main()方法,在该方法里调用system_server的接口,并将自己的Binder引用(mAppThread)传递给system_server
  2. system_server 掌管着Application和四大组件的生命周期,system_server会告诉App进程当前是需要创建Application实例还是调用到Activity某个生命周期阶段(如onCreate/onResume等),此时就是依靠mAppThread回调回来
  3. 此时的App进程作为Binder Server端,它是在子线程收到system_server进程的消息,因此需要通过post到主线程执行
  4. 最终Application/Activity 的生命周期函数将会在主线程执行,这也就是为什么四大组件不能执行耗时任务的原因,因为都会切换到主线程执行四大组件的各种重写方法

6. Activity 与 View的展示

通过上面的分析可知现在的流程已经走到App进程本身,Application、Activity 都已经创建完毕了,什么时候会显示View呢?
先看Activity.onCreate()的调用流程:

image.png

此流程结束,整个ViewTree都构建好了。

接着需要将ViewTree添加到Window里流程如下:

image.png

最后监听屏幕刷新信号,当信号到来之后遍历ViewTree进行Measure、Layout、Draw操作,最终渲染到屏幕上,此时我们的App界面就显示出来了。

image.png

7. 全流程图

image.png

附源码路径:
init.rc配置文件
ServiceManager入口
Zygote native入口
Zygote java入口
system_server入口
App入口

更多Android 源码查看方式请移步:Android-系统源码查看的几种方式

本文基于Android 10
对源码细节有疑惑之处欢迎留言讨论,下篇将会图文分析Binder实现全流程,敬请关注。

您若喜欢,请点赞、关注、收藏,您的鼓励是我前进的动力

持续更新中,和我一起步步为营系统、深入学习Android/Kotlin

1、Android各种Context的前世今生
2、Android DecorView 必知必会
3、Window/WindowManager 不可不知之事
4、View Measure/Layout/Draw 真明白了
5、Android事件分发全套服务
6、Android invalidate/postInvalidate/requestLayout 彻底厘清
7、Android Window 如何确定大小/onMeasure()多次执行原因
8、Android事件驱动Handler-Message-Looper解析
9、Android 键盘一招搞定
10、Android 各种坐标彻底明了
11、Android Activity/Window/View 的background
12、Android Activity创建到View的显示过
13、Android IPC 系列
14、Android 存储系列
15、Java 并发系列不再疑惑
16、Java 线程池系列
17、Android Jetpack 前置基础系列
18、Android Jetpack 易学易懂系列
19、Kotlin 轻松入门系列
20、Kotlin 协程系列全面解读