Android 系统启动到App 界面完全展示终于明白(图文版)
之前文章有分析过Activity创建到View的显示过程,属于单应用层面的知识范畴,本篇将结合Android 系统启动部分知识将两者串联分析,以期达到融会贯通的目标。
通过本篇文章,你将了解到:
- Android 系统启动流程概览
- ServiceManager 进程作用
- Zygote 进程创建与fork子进程
- system_server 进程作用
- App 与 system_server 交互
- Activity 与 View的展示
- 全流程图
1. Android 系统启动流程概览
- init 是用户空间的第一个进程,它的父进程是idle进程
- init 进程通过解析init.rc 文件并fork出相应的进程
- zygote是第一个Java 虚拟机进程,通过它孵化出system_server 进程
- system_server 进程启动桌面(Launcher)App
以上为Android 系统上电到桌面启动的简略过程,我们重点关注其中几个进程:
init、servicemanger、zygote、system_server
idle 与 init 关系如下:
查看依赖关系:
init.rc 启动servicemanager、zygote 配置如下:
2. ServiceManager 进程作用
Android 进程间通信运用最广泛的是Binder机制,而ServiceManager进程与Binder息息相关。
DNS 存储着域名和ip的映射关系,类似的ServiceManager存储着Binder客户端和服务端的映射。
App1作为Binder Client端,App2 作为Binder Server端,App2 开放一个接口给App1使用(通常称为服务),此时步骤如下:
- App2 向ServiceManager注册服务,过程为:App2 获取ServiceManager的Binder引用,通过该Binder引用将App2 的Binder对象(实现了接口)添加到Binder驱动,Binder驱动记录对象与生成handle并返回给ServiceManager,ServiceManager记录关键信息(如服务名,handle)。
- App1 向ServcieManager查询服务,过程为: App1 获取ServiceManager的Binder引用,通过该Binder引用发送查询命令给Binder驱动,Binder驱动委托ServiceManager进行查询,ServiceManager根据服务名从自己的缓存链表里查出对应服务,并将该服务的handle写入驱动,进而转为App1的Binder代理。
- App1 拿到App2 的Binder代理后,App1 就可以通过Binder与App2进行IPC通信了,此时ServiceManager已经默默退居幕后,深藏功与名。
由上可知,ServiceManager进程扮演着中介的角色。
3. Zygote 进程创建与fork子进程
Zygote 进程的创建
Zygote 进程大名鼎鼎,Android 上所有的Java 进程都由Zygote孵化,Zygote名字本身也即是受精卵,当然文雅点一般称为孵化器。
Zygote 进程是由init进程fork出来的,进程启动后从入口文件(app_main.cpp)入口函数开始执行:
- 构造AppRuntime对象,并创建Java虚拟机、注册一系列的jni函数(Java和Native层关联起来)
- 从Native层切换到Java层,执行ZygoteInit.java main()函数
- fork system_server进程,预加载进程公共资源(后续fork的子进程可以复用,加快进程执行速度)
- 最后开启LocalSocket,并循环监听来自system_server创建子进程的Socket请求。
通过以上步骤,Zygote 启动完成,并等待创建进程的请求。
初始状态步骤:
- Zygote fork system_server 进程并等待Socket请求
- system_server 进程启动后会请求打开Launcher(桌面),此时通过Socket发送创建请求给Zygote,Zygote 收到请求后负责fork 出Launcher进程并执行它的入口函数
- Launcher 启动后用户就可以看到初始的界面了
用户操作:
桌面显示出来后,此时用户想打开微信,于是点击了桌面上的微信图标,背后的故事如下:
- Launcher App 收到点击请求,会执行startActivity,这个命令会通过Binder传递给system_server进程里的AMS(ActivityManagerService)模块
- AMS 发现对应的微信进程并没有启动,于是通过Socket发送创建微信进程的请求给Zygote
- Zygote 收到Socket请求后,fork 微信进程并执行对应的入口函数,之后就会显示出微信的界面了
用图表示如下:
由上可知,App进程和system_server 进程之间通信方式为Binder,而system_server和Zygote 通信方式为Socket,App进程并不直接请求Zygote做事情,而是通过system_server进行处理,system_server 记录着当前所有App 进程的状态,由它来统一管理各个App的生命周期。
Zygote 进程fork 子进程
Zygote 进程在Java层监听Socket请求,收到请求后层层调用最后切换到Native执行系统调用fork()函数,最后根据fork()返回值区分父子进程,并在子进程里执行入口函数。
4. system_server 进程作用
system_server 为所有App提供服务,可以说是系统的核心进程之一,它主要的功能如下:
可以看出,它创建并启动了许多服务,常见的AMS、PMS、WMS,我们常说系统某某服务返回了啥,往细的说这里的"系统"可以认为是system_server进程。
需要注意的是,这里所说的服务并不是Android四大组件的Service,而是某一类功能。
四大组件的交互也要依靠system_server:
实际调用流程如下:
由上图可知,不管是同一进程内的通信亦或是不同进程间的通信,都需要system_server介入。
App 和 system_server 是属于不同的进程,App进程如何找到system_server呢?
还是要借助ServiceManager进程:
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时候拿出来用即可,类似回调的功能,如下图:
再细化一下流程:
- App 进程在启动后执行ActivityThread.java里的main()方法,在该方法里调用system_server的接口,并将自己的Binder引用(mAppThread)传递给system_server
- system_server 掌管着Application和四大组件的生命周期,system_server会告诉App进程当前是需要创建Application实例还是调用到Activity某个生命周期阶段(如onCreate/onResume等),此时就是依靠mAppThread回调回来
- 此时的App进程作为Binder Server端,它是在子线程收到system_server进程的消息,因此需要通过post到主线程执行
- 最终Application/Activity 的生命周期函数将会在主线程执行,这也就是为什么四大组件不能执行耗时任务的原因,因为都会切换到主线程执行四大组件的各种重写方法
6. Activity 与 View的展示
通过上面的分析可知现在的流程已经走到App进程本身,Application、Activity 都已经创建完毕了,什么时候会显示View呢?
先看Activity.onCreate()的调用流程:
此流程结束,整个ViewTree都构建好了。
接着需要将ViewTree添加到Window里流程如下:
最后监听屏幕刷新信号,当信号到来之后遍历ViewTree进行Measure、Layout、Draw操作,最终渲染到屏幕上,此时我们的App界面就显示出来了。
7. 全流程图
附源码路径:
init.rc配置文件
ServiceManager入口
Zygote native入口
Zygote java入口
system_server入口
App入口
更多Android 源码查看方式请移步:Android-系统源码查看的几种方式
链接:https://juejin.cn/post/7157001609090695175
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。