注册

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-系统源码查看的几种方式


作者:小鱼人爱编程
链接:https://juejin.cn/post/7157001609090695175
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册