AMS核心原理初探一:SystemServer 进程
- 本文概述:本文为AMS 原理部分的第一篇文章,旨在打通Android 启动流程与AMS 的关系。使读者对Android 底层原理具备大体认识。文章以SystemServer 进程为例,详细介绍了其创建时机、创建过程、执行时机、执行过程。
android 的启动流程回顾
前情提要:
- 本节仅牵涉Android 启动部分知识,完整流程请查阅个人往期博客:[Android 启动流程初探]:juejin.cn/post/709376…
启动流程
-
Init 初始化Linux 层,处理部分服务
-
挂载和创建系统文件
-
解析rc文件:
- rc 文件中有很多action
-
进入无限循环
-
执行action:zygote 进程就在这里启动
- for循环去解析参数,根据rc 文件中的action 执行相应操作
-
检测并重启需要的进程
-
接收子进程的SIGCHLD信号,执行响应的方法
- 防止子进程成为僵尸进程
-
-
-
zygote 层:
-
native 部分:
- 初始化android 运行时环境(ART),因为Java 代码需要运行在虚拟机中;
- 初始化 JNI ,因为native 层与 Java 层需要通信
- 执行ZygoteInit.main 方法,进入Java 部分
-
Java 部分:
- 创建 socket:实现通信
- 执行预加载:加快进程的启动速度
- 通过fork 创建 SystemServer 进程
- 进入循环:等待AMS 的通知,并根据通知创建对应的进程
-
引申问题:
- zygote 中的Java 层是如何创建出SystemServer 的?
- SystemServer 是怎么启动的?
本文正文内容
SystemServer 进程的创建时机
-
一句话描述:
-
Zygote 进程通过forkSystemServer类 调用fork(),创建其子进程;这个子进程就是SystemServer 进程
-
业务逻辑:
-
SystemServer 进程的创建过程
-
前情提要:
- 从ZygoteInit.java 中的main 方法。进入forkSystemServer类;此时,属于Zygote 进程
- 进程实际上是没有native,java之分的;我们常说Zygote 进程在native 层,SystemServer 进程在Java 层,这可看做一种约定。
-
第一步:参数赋值
- 通过字符串数组args 进行赋值:包含uid,gid,nice-name(进程名)
-
第二步:创建子进程,拿到pid
- 通过Zygote.forkSystemServer 调用fork(),创建子进程并返回pid
怎样理解Zygote 进程与SystemServer 进程的关系?
-
一句话描述:
- Zygote 进程是SystemServer 进程的父进程,两进程共用一段代码;
-
怎么理解进程号(pid) ?
-
pid 代表每个进程的进程号。但是,当pid 接收返回值时,其表示子进程的进程号。
-
pid的值:进程的唯一标识符
-
子进程是父进程fork 出来的,可以看作是拷贝。通过pid 的值区分父子进程
-
定义子进程处理逻辑
- if(pid == 0){ 业务代码 }
-
-
子进程的pid 比父进程的pid 大,是递增的
-
pid 的值可以看成是随机的,但是也不能这样说。
-
-
-
举个例子:
- 假如Zygote 的进程号为1000,SystemServer 的进程号是6000。那么,Zygote 中的pid 的返回值就是6000,也就是Zygote fork 出的子进程的进程号。而SystemServer 中的pid 的返回值为0,因为它没有子进程;
-
怎么通过代码区别父子进程?
-
前情提要:
- 父子进程共用一段代码,这段代码在父子进程中各执行一次;
-
业务需求:
-
在共用代码中,让某段代码仅在子进程中执行
if(pid == 0){//子进程域 //子进程执行逻辑 }
-
SystemServer 进程的执行时机:
-
基本环境:
- 上文中我们知道了SystemServer 进程是Zygote 进程通过forkSystemServer 调用fork() 函数后创建出来的。那么SystemServer 进程具体执行时,应当调用SystemServer.main();
-
调用时机:通过下列代码调用至forkSystemServer
- 执行条件:if(pid == 0)
- 在SystemServer进程中
//forkSystemServer return handleSystemServerProcess(parsedArags);
源码阅读细节:有个方法是搜不到的
-
问题描述:
- 在forkSystemServer 类中想查看nativeForkSystemServer() 的执行细节。
- 正常情况下,对于系统层函数在AndroidRuntime.cpp 中直接搜方法名就可以搜到具体的函数。但是,这对于nativeForkSystemServer() 是不行的。
-
解决手段:在AndroidRuntime.cpp搜com_android_internal_os_Zygote
-
找到这句代码并点击进入
extern int register_com_android_internal_os_Zygote(JNIEnv *env);
-
在这个函数返回值处,进入gMethods[];native 函数都在这里。
-
-
为什么会出现这种问题?
- 这是JNI 层代码的命名规范,但是这个函数在当初代码编写的时候,违背了主流规范才导致我们直接搜是搜不到的。
- JNI 层代码的命名规范:包名 + 具体的函数名
SystemServer 进程的执行过程:
-
前情提要:
- 业务需求:需要启动SystemServer.main()
-
代码入口:进入SystemServer 进程
if(pid == 0){//此时在SystemServer 进程中 ………… return handleSystemServerProcess(parsedArgs); }
-
handleSystemServerProcess() 通过反射启动SystemServer.main()
-
源码依据:
- 先是拿到了ClassLoader,接着调用了ZygoteInit.zygoteInit();
-
zygoteInit() 干了什么?
-
启动Binder 线程池:
- ZygoteInit.nativeZygoteInit();
-
运行SystemServer.main()
- RuntimeInit.applicationInit();
Binder 线程池是如何启动的?
-
前情提要:
-
源码入口:nativeZygoteInit()
-
对应的JNI 层代码
com_android_internal_os_ZygoteInit_nativeZygoteInit()
-
-
重要代码解析:
-
代码展示:
gCurRuntime->onZygoteInit();
-
gCurRuntime 是什么?
- 指AppRuntime,且AppRuntime 继承自AndroidRuntime;
- 因为SystemServer 是Zygote 的子进程;
- 由于代码共享,所以Zygote 有AndroidRuntime,那SystemServer 也有;并且,在Zygote 初始化的时候,会将AndroidRuntime 一同初始化。SystemServer 相当于继承了AndroidRuntime,因此具备安卓运行时环境;
-
-
onZygoteInit():在这里就启动了Binder 线程池
-
代码展示:app_main.cpp
virtual void onZygoteInit() { sp<ProcessState> proc = ProcessState::self(); ALOGV("App process: Starting thread poll.\n"); proc->startThreadPool(); }
-
-
经验总结:每个进程都是有Binder 机制的,因为SystemServer 进程执行时会开启Binder 线程池。
SystemServer.main() 执行过程
-
一句话描述:通过反射执行,在封装类中调用。
-
前情提要:
- 源码入口:RuntimeInit.applicationInit();
- 核心代码:findStaticMain();
-
通过反射执行SystemServer.main()
-
拿到类:classname 就是SystemServer
cl = Class.forName(classname,true,classLoader);
-
拿到方法:SystemServer.main()
m = cl.getMethod("main", new Class[] { String[].class });
-
先进行封装:
return new MethodAndArgsCaller(m, argv);
-
在封装类中,调用代码:
static class MethodAndArgsCaller implements Runnable {//开启子线程执行 public void run() { try { // 通过反射真正执行 SystemServer.main() mMethod.invoke(null, new Object[] { mArgs }); } }
-
-
这个run() 是什么时候执行的?
-
ZygoteInit.java中main执行的,forkSystemServer之后会返回一个r;这个r 就是MethodAndArgsCaller 这个封装类;
-
代码展示:
if(startSystemServer){ Runnable r = forkSystemServer(xxxxx); if(r != null){//如果是Zygote 进程,r 才为空; r.run(); return; } }
-
SystemServer().run() 干了什么?
-
一句话描述:SystemServer 通过标记,完成不同阶段的任务。总体来说,干了三件事。创建系统上下文,创建服务管理者,创建三类服务
-
设置标记方法:
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
-
业务流程图:
-
-
前情提要:
-
此时,我们分析的是SystemServer 进程的main() 方法;但,实际上调用的是SystemServer().run();
public static void main(String[] args) {//SystemServer.main() new SystemServer().run(); }
-
-
创建系统上下文:
createSystemContext();
-
创建系统服务管理者:
mSystemServiceManager = new SystemServiceManager(mSystemContext);
-
创建三类服务:
-
引导服务:AMS
//引导服务:AMS startBootstrapServices(t);
-
核心服务:
//核心服务:系统所需要的 startCoreServices(t);
-
其他服务:WMS
//其他服务:WMS等 startOtherServices(t);
-