这次我们来聊一聊系统相关服务,比如Zygote
启动原理,SystemServer
启动原理,如何进行添加一个系统服务等。 熟悉这些Android 底层知识更好的方便我们进行代码运行时,出现异常进行分析,每次堆栈信息都是从init进程开始,然后zygote进程,之前一直面对这些信息,都摸不着头脑,如果知晓这些相关信息,更好的让我们对整个应用的启动有了更深入理解,不再简单的停留在应用层上面。
推荐看看Android 进阶解密,从源码层讲解framework,对个人理解非常有帮助
先来说一下Zygote进行相关原理
Zygote 进程
那Zygote进程有什么作用 1. 首先启动SystemServer
(因为需要Zygote 中的一些资源比如:常用类,JNI函数,主题资源,共享库) 2. 孵化应用进程
它有个启动三段式:进程启动->准备工作->Loop
Zygote 启动流程
进程怎么启动
Init
进程->加载配置文件init.rc
,配置文件定义那些服务需要启动->通过fork
与execve
系统调用来启动Zygote进程- 启动进程 (根据
pid=0
来判断是子进程还是父进程,为0是子进程)fork+handler
fork+execve
- 启动进程 (根据
- 信号处理
(sigchid)
- 父进程通过fork来创建一个子进程,当子进程死亡父进程会收到这个信号来做一些操作,比如
Zygote
进程死亡,init进程就会收到这个信号,来重新启动Zygote进程
- 父进程通过fork来创建一个子进程,当子进程死亡父进程会收到这个信号来做一些操作,比如
进程启动之后做了什么
Zygote
的Native
世界
- 启动Android虚拟机
- 注册Android的关键
JNI
函数 - 进入Java世界
- Zygote的Java世界
- 预加载资源,孵化子进程用到的
fork
创建SystemServer
进程- 通过
socket
通信进入Loop
循坏,当有新的请求,去处理,参数列表通过AMS进行跨进程发送,在子进程进行执行ActivityThread.main()
函数
Zygote
注意细节
Zygote fork
要单线程,避免线程死锁,状态不一致Zygote
的IPC没有采用binder
(binder在应用程序进程启动之后创建的binder机制),采用的是本地Socket
通信
Zygote的IPC通信机制为什么不采用binder
zygote
比service manager
先启动;从这个意义上,他没有service manager
可以注册,所以没法用 binder- 因为他们两个都是
init
进程启动的,就算先启动service manager
,也不能保存 zygote 起来的时候service manger
就已经初始化好了(这就需要额外的同步,太麻烦) - 这个
socket
的所有者是root
,group是system
,只有系统权限的用户才能读写,这又多了一个安全保障(注意,这个socket 是 Unix 域 Socket,不是 internet 域 Socket)
Android 系统启动流程
说完Zygote 进程启动,我们在说一下Android 系统启动流程,这里面就包括了SystemServer的启动流程,就不单独的讲一下
Zygote 进程启动
init
进程通过fork
方式创建Zygote
进程- 启动虚拟机,注册
jni
函数 - 预加载系统资源
- 创建
SystemServer
进程并启动 - 进入
Socket
的Loop
循环
SystemServer 进程启动(主要用于创建系统服务,比如AMS、PMS与WM都是它创建)
SystemServer
的main
方法只调用了SystemServer
的run方法 - 创建消息Looper
- 加载动态库 liandroid_servers.so
- 创建系统context
- 启动引导服务,比如AMS、PowerManagerService与PackageManagerService
等服务 - 启动核心服务,比如DropBoxManagerService、BatteryService
等 - 启动其他服务,比如CamerManagerService、AlarmManagerService、WindowManagerService
等
- 启动
Binder
线程池,可以与其他进程通信 - 创建
SystemServiceManager
,用于对系统读物服务进程创建,启动与生命周期进程管理 - 启动各种系统服务
系统服务怎么启动
- 系统服务怎么发布,让应用程序可见
- 在
publishBinderService
方法中最终将Binder函数注册到了ServiceManager
中
- 在
- 系统服务跑在什么线程
- 工作线程
(AMS,PMS,DisplayThread显示,FgThread前台任务,ioThread耗时任务,UIThread负责Ui线程->这里是子线程)
- Binder 线程,应用跨进程调用在binder线程中
- 工作线程
ServiceManager 启动与工作原理
SystemServer进程启动创建了ServiceManager,那我们就有必要再来讨论一下ServiceManager相关知识
ServiceManager 启动流程
- 启动进程
- 启用binder机制
- 发布自己的服务
- 等待并响应请求
怎么向ServiceManager添加服务
- 获取binder对象
- 向
ServiceManager
发起一个binder调用,需要两个参数服务名称及服务实体对象
怎么从ServiceManager获取服务
- 获取
ServiceManager
的binder
对象 - 向
ServiceManager
发起一个binder调用,带service
名称就可以
系统服务
如何使用系统服务
通过getSystemService
传入一个服务名称进可以获取,内部通过hashMap
的key
值进行获取,判断缓存中是否有service,没有就创建,缓存作用是在系统启动的时候预支一些服务放进去,后面再启动的时候并没有放入缓存中
系统服务注册原理
- 通过
addService
方法进行注册,在SystemService
启动时候进行注册系统服务- 启动
binder
机制 - 启动各类系统服务
- 进入
Loop
循环
- 启动
- 独立进程系统服务
- 无论是在
SystemService
中服务,还是单独的进程系统服务,都需要在ServiceManager
中进行注册,才能够使用服务
- 无论是在
启用binder机制
- 打开binder驱动
- 映射内存,分配缓冲区
- 启动binder线程,进入
binder loop
中循环
怎么添加一个系统服务
- 为什么要添加系统服务
- 用来让别人使用
- 怎么样让别人用
- 启动binder机制就可以IPC进程通信
- 注册开发,让别人找到
- 具体哪些事要干
- 添加系统服务时机
- 跑在单独进程,
- 在init进程中修改配置,需要main入口函数
- 跑在单独进程,
- 添加系统服务时机
-
- 服务端要做的事,做服务端初始化操作
- 应用端做哪些事
- 调用方式保存一直,注册一个服务
系统服务与binder服务区别
最后我们再聊一下系统服务与binder服务区别
在启动方式上有什么区别
- 系统服务在
systemService
中启动,跑在binder线程中,做一些初始化操作,当client客户端有请求操作,在binder
线程池中分发请求给对应的binder实体对象来进行处理,处理完再发送回复给客户端 - 应用服务启动,由客户端发起,通过AMS启动
在注册方式上有什么区别
系统服务注册,都需要给binder实体对象注册到ServiceManager
中,只有系统服务才可以注册 应用服务,应用端发起调用,给AMS,判断是否注册,注册,回调binder返回给应用,没有再进行binder注册,再回调给应用
在使用方式上有什么区别
- 系统服务使用,通过
getSystemService
进行获取,内部缓存,hashmap
- 应用服务使用,通过
bindService
进行绑定,然后进行调用