【系统之音】Android进程的创建及启动简述
Android系统中的进程(这里不包括init等底层的进程)都是通过Zygote fork而来的,那这些进程的启动流程都是怎样的呢?
这里将Android进程分为两个部分:
(1)系统框架进程SystemServer进程。它是Zygote创建的第一个进程,是在系统启动过程中,Zygote进程启动时直接fork而来的。
(2)应用程序进程。比如Launcher、SystemUI,其它应用程序等的进程。这些应用程序进程的启动大致包含两个步骤:
1)AMS向Zygote进程发送创建进程的请求;
2)Zygote接受请求,创建并启动应用程序进程。
本文将围绕上述几点,基于Android P(API28)的源码,来梳理Android进程的创建与启动过程。内容的主要对象是应用开发者,所以力求简洁和完整,内容大体如下:
1、Zygote进程启动简述
在理解这一部分前,建议先阅读【系统之音】Android系统启动篇。
系统在启动时,会启动一个名为“init”的系统进程,然后该进程会创建并启动Zygote进程。创建和启动Zygote进程的过程,先后从Nativie层跨入Java层,在Native层会创建虚拟机实例(即ART实例),然后通过JNI的方式调用ZygoteInit类的main方法。Native层的代码咱们不深究,这里看看main方法:
//(代码1.1)=========ZygoteInit.java=====
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
......
String socketName = "zygote";
......
//创建一个名为“zygote”的Server端Socket,在后续会一直监听AMS发起的创建新进程的请求。
zygoteServer.registerServerSocketFromEnv(socketName);
......
//①通过fork方式创建SystemServer进程并启动
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);//fork创建SystemServer进程
......
if (r != null) {
r.run();//启动SystemServer进程
return;
}
}
//②该方法中使用了一个while(true)的无限循环来实现一直监听AMS的请求
caller = zygoteServer.runSelectLoop(abiList);
......
//③这里是会执行子进程(应用程序进程)的ActivityThread的main方法,后文会讲到
if (caller != null) {
caller.run();
}
}
我抽取了关键的代码,主要是关注Zygote启动期间所做的主要工作,这里先给出结论(有必要牢记于心):
(1)创建虚拟机实例;
(2)创建一个名为“zygote”的Server端Socket,用于后续监听AMS的请求;
(3)通过fork的方式创建SystemServer进程并启动它,该过程会启动各种系统服务,AMS就是在这个阶段启动的;
(4)在runSelectLoop方法中通过一个while(true)无限循环来实现对AMS的监听;
(5)启动非SystemServer进程。
2、Zygote创建与启动SystemServer
实际上SystemServer是Zygote创建出的第一个进程,我们从代码1.1中的注释②处的forkSystemServer方法来深入了解:
//代码2.1==========ZygoteInit.java=======
private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) {
......
int pid;
......
//fork的过程发生在Native层
pid = Zygote.forkSystemServer(...);
......
//④pid为0表示子进程(即SystemServer进程)创建成功,逻辑进入到子进程中。下面的逻辑会启动SystemServer进程
if (pid == 0) {
......
return handleSystemServerProcess(parsedArgs);
}
} public static int forkSystemServer(...){
......
int pid = nativeForkSystemServer(...);
......
} native private static int nativeForkSystemServer(...)
可见,forkSystemServer进程是发生在Native层的,接着继续从注释④处看看SystemServer进程的启动:
//代码2.2 =========ZygoteInit.java========
private static Runnable handleSystemServerProcess(...){
......
return ZygoteInit.zygoteInit(...);
} public static final Runnable zygoteInit(...) {
......
//该处用于创建Binder线程池,此后SystemServer进程就可以使用Binder来实现IPC了。该过程也是在Native层实现,Binder在ServiceManager中进行注册。
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
} private static final native void nativeZygoteInit(); //==========RuntimeInit.java=======
protected static Runnable applicationInit(...){
......
//通过上下文可以得知这里的args.startClass值为“com.android.server.SystemServer”
return findStaticMain(args.startClass, args.startArgs, classLoader);
} /**
* Invokes a static "main(argv[]) method on class "className".
* ......
*/
protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class<?> cl;
try {
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
}
int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
}
...... //毫无疑问,这里的m就是SystemServer类的main方法了
return new MethodAndArgsCaller(m, argv);
} static class MethodAndArgsCaller implements Runnable {
/** method to call */
private final Method mMethod;
/** argument array */
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
}
......
}
}
一步步跟进时,我们会发现该过程中主线都是返回的Runnable类型的对象,回到代码1.1的注释②处的第12行,这里的 r 就是MethodAndArgsCaller对象,第13行r.run()执行,就是调用的上述代码第67行,跟踪上下文可知这里就是执行的SystemServer.main方法。紧接着第14行是return,Zygote就完成了创建和启动SystemServer进程。此时你是否会有疑问:这里就return了,那后面监听AMS请求和启动非SystemServer进程的逻辑又如何实现呢?这里我们需要理解“fork”,后面我们会详细介绍。
这里进一步看看SystemServer进程中都做了些什么:
//=========SystemServer.java===========
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
......
//创建消息Looper
Looper.prepareMainLooper();
// 加载动态库libandroid_servers.so,初始化native服务
System.loadLibrary("android_servers");
......
//初始化系统context
createSystemContext();
//创建SystemServiceManager
mSystemServiceManager = new SystemServiceManager(mSystemContext);
......
//启动引导服务,如AMS等
startBootstrapServices();
//启动核心服务
startCoreServices();
//启动其它服务,如WMS,SystemUI等
startOtherServices();
....
// Loop forever.
Looper.loop();
}
到这里Zygote就创建并启动了SystemServe进程,总结一下这个过程中主要做了些什么工作:
(1)通过fork得到一个虚拟机实例副本;
(2)创建Binder线程池,SystemServer可以通过Binder来实现IPC(跨进程通信);
(3)启动系统服务,比如AMS,WMS等;
(4)创建消息循环,Looper.loop()中是一个无限循环,SystemServer将持续运行。
3、fork简介
在前文中提到了使用fork的方式来创建进程,也提到了一个疑问:
“此时你是否会有疑问:这里就return了,那后面监听AMS请求和启动非SystemServer进程的逻辑又如何实现呢?”
这里先看看百度百科的介绍:
“复刻(英语:fork,又译作派生、分支)是UNIX或类UNIX中的分叉函数,fork函数将运行着的程序分成2个(几乎)完全一样的进程,
每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。
fork系统调用用于创建一个新进程,称为子进程,它与进程(称为系统调用fork的进程)同时运行,此进程称为父进程。创建新的子进程后,
两个进程将执行fork()系统调用之后的下一条指令。子进程使用相同的pc(程序计数器),相同的CPU寄存器,在父进程中使用的相同打开文件。”
所以,在代码1.1中forkSystemServer时,Zygote进程会分化为两个一模一样的进程来,其中一个是父进程,另外一个是子进程,它是主进程的副本。当SystemServer fork成功后其流程就进入到了子进程中,即代码1.1中的第15、16行是在子进程中执行的。而与此同时,父进程还会继续往下执行,不断监听AMS的请求以及启动新的进程。
要更好地理解fork后Zygote进程和子进程的工作,可以参考阅读:https://www.cnblogs.com/jiangzhaowei/p/11023098.html。
4、Zygote监听AMS的请求
在代码1.1中注释②处,会通过调用runSelectLoop方法来监听AMS的请求,我们看看该方法的实现:
//代码4.1======ZygoteServer.java======
Runnable runSelectLoop(String abiList) {
......
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
......
while (true) {
......
//⑤当监听到AMS请求的数据时会执行这里
ZygoteConnection connection = peers.get(i);
final Runnable command = connection.processOneCommand(this);
......
return command;
}
}
这其中包含了一个while(true)的无限循环,以此来一直监听AMS的请求,直到注释⑤处监听到了AMS的请求,fork出新的子进程(应用程序进程),随后在子进程中return,结束监听。和fork SystemServer一样,父进程Zygote仍然继续监听着,继续相应AMS新的请求,fork出新的子进程。
5、AMS向Zygote进程发起创建进程的请求
要启动一个程序时,系统首先会判断该程序所在的进程是否存在,如果不存在就需要先创建并启动目标程序对应的进程。这一点在四大组件组件启动流程的源码中都有体现,当发现目标进程还不存在时,AMS都会向Zygote进程申请创建目标进程。这个过程分为两步:(1)AMS向Zygote进程发起创建进程的请求;(2)Zygote收到请求,创建并启动进程。这一节我们先看看第(1)步:
1 //==============ActivityManagerService.java============
2 private final boolean startProcessLocked(ProcessRecord app, String hostingType,
3 String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {
4 ......
5 final String entryPoint = "android.app.ActivityThread";
6 return startProcessLocked(hostingType, hostingNameStr, entryPoint...);
7 }
8
9 private boolean startProcessLocked(...String entryPoint...) {
10 ......
11 final ProcessStartResult startResult = startProcess(...entryPoint...);
12 }
13
14 private ProcessStartResult startProcess(...String entryPoint...){
15 ......
16 final ProcessStartResult startResult;
17 ......
18 startResult = Process.start(entryPoint,
19 app.processName, uid, uid, gids, runtimeFlags, mountExternal,
20 app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
21 app.info.dataDir, invokeWith,
22 new String[] {PROC_START_SEQ_IDENT + app.startSeq});
23 ......
24 }
25
26 //================Process.java==============
27 public static final ZygoteProcess zygoteProcess = new ZygoteProcess(ZYGOTE_SOCKET, SECONDARY_ZYGOTE_SOCKET);
28 public static final ProcessStartResult start(final String processClass,...) {
29 return zygoteProcess.start(processClass, ...);
30 }
31
32 //==============ZygoteProcess.java==========
33 public final Process.ProcessStartResult start(final String processClass...) {
34 try {
35 return startViaZygote(processClass...);
36 }......
37 }
38
39 private Process.ProcessStartResult startViaZygote(final String processClass...){40 argsForZygote.add(processClass);
41 ......
42 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
43 }
44
45 private ZygoteState primaryZygoteState;
46 ......
47 private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
48 ......
49 //追踪代码,容易得知mSocket值为"zygote",这里的作用是连接名为“zygote”的Socket
50 primaryZygoteState = ZygoteState.connect(mSocket);
51 ......
52 }
从上述代码可以看出,该过程的逻辑其实挺简单,通过层层调用后走到第50行。这一行的作用就是和名为“zygote”的Socket服务端建立连接,这样就向Zygote进程发起了请求。这里的ZygoteState类中的
6、Zygote收到AMS的请求,创建并启动进程
在代码4.1中,我们讲过,其中while(true)循环一直监听AMS的请求,直到收到请求。
//===========ZygoteConnection.java=======
Runnable processOneCommand(ZygoteServer zygoteServer) {
......
//⑥fork方式创建应用程序进程
pid = Zygote.forkAndSpecialize(...);
......
//pid为0表示当前的代码逻辑运行在新创建的子进程(即应用程序进程)中
if (pid == 0) {
// in child
......
//处理应用程序进程
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.startChildZygote);
} else {
......
}
} private Runnable handleChildProc(...){
......
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,null /* classLoader */);
}
//=====ZygoteInit.java========
public static final Runnable zygoteInit(...) {
......
//创建Binder线程池,此后新的子进程就能够使用Binder进行IPC了
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
} //============Zygote.java==========(补充注释⑥处)
public static int forkAndSpecialize(...) {
........
int pid = nativeForkAndSpecialize(...);
......
return pid;
}
native private static int nativeForkAndSpecialize(...);
流程走到第26行就比较清晰了,和代码2.2中启动SystemServer进程一致了,只不过这里启动的是ActivityThread的main方法。
//=======ActivityThread.java=====
static volatile Handler sMainThreadHandler; public static void main(String[] args) {
......
Looper.prepareMainLooper();
......
ActivityThread thread = new ActivityThread();
......
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
......
Looper.loop();
} final Handler getHandler() {
return mH;
} final H mH = new H(); class H extends Handler {
......
}
ActivityThread类是主线程的管理类,其main方法中会创建消息循环,其中Looper.loop()方法中通过无限循环的方式,保持主线程一直运行。同时还会创建主线程的H类,这是一个包含主线程looper的Handler,四大组件启动过程中都需要通过这个H类对象来从Binder线程中切换到主线程中。
这里总结一下普通应用程序进程创建时的关键工作:
(1)通过fork得到一个虚拟机实例副本;
(2)创建Binder线程池,应用程序进程就可以通过Binder来实现IPC;
(3)创建消息循环,创建主线程的H类。
7、疑问
(1)为什么AMS(SystemServer进程)与Zygote进程通讯采用Socket而不是Binder?
答:因为fork不允许存在多线程,而Binder通信偏偏就是多线程。(不知道该答案是否准确,目前还没找到权威答案)。
可以参考:https://blog.csdn.net/qq_39037047/article/details/88066589
参考及推荐阅读:
https://www.cnblogs.com/andy-songwei/p/11429421.html
https://www.cnblogs.com/jiangzhaowei/p/11023098.html
https://www.jianshu.com/p/ab9b83a77af6
https://blog.csdn.net/qq_39037047/article/details/88066589
刘望舒《Android进阶解密》
【系统之音】Android进程的创建及启动简述的更多相关文章
- Linux系统编程之--守护进程的创建和详解【转】
本文转载自:http://www.cnblogs.com/mickole/p/3188321.html 一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终 ...
- Linux系统基于fork()新进程的创建
作者:严哲璟 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 fork属于系 ...
- 简单播放系统提示音 android
//Uri alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM); //alert = RingtoneManager.g ...
- Android进程机制
以下资料摘录整理自老罗的Android之旅博客,是对老罗的博客关于Android底层原理的一个抽象的知识概括总结(如有错误欢迎指出)(侵删):http://blog.csdn.net/luosheng ...
- 【转】Android进程机制
以下资料摘录整理自老罗的Android之旅博客,是对老罗的博客关于Android底层原理的一个抽象的知识概括总结(如有错误欢迎指出)(侵删):http://blog.csdn.net/luosheng ...
- 理解Android进程创建流程(转)
/frameworks/base/core/java/com/android/internal/os/ - ZygoteInit.java - ZygoteConnection.java - Runt ...
- Android 系统回收资源时进程被杀的优先级
http://developer.android.com/guide/components/processes-and-threads.html#Processes Android 操作系统的内存回收 ...
- linux系统编程:守护进程详解及创建,daemon()使用
一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.它不需要用户输入就能运行而且提供某种服务,不是对整个 ...
- 【系统之音】WindowManager工作机制详解
前言 目光所及,皆有Window!Window,顾名思义,窗口,它是应用与用户交互的一个窗口,我们所见到视图,都对应着一个Window.比如屏幕上方的状态栏.下方的导航栏.按音量键调出来音量控制栏.充 ...
随机推荐
- python中操作csv文件
python中操作csv文件 读取csv improt csv f = csv.reader(open("文件路径","r")) for i in f: pri ...
- 【Leetcode 做题学算法周刊】第八期
首发于微信公众号<前端成长记>,写于 2020.05.07 背景 本文记录刷题过程中的整个思考过程,以供参考.主要内容涵盖: 题目分析设想 编写代码验证 查阅他人解法 思考总结 目录 15 ...
- requests模块使用
一.python环境下安装requests Windows下使用win+r打开cmd命令提示符,输入pip install requests,回车. 二.requests模块导入 import req ...
- 【算法•日更•第五十期】二分图(km算法)
▎前言 戳开这个链接看看,惊不惊喜,意不意外?传送门. 没想到我的博客竟然被别人据为己有了,还没办法投诉. 这年头写个博客太难了~~~ 之前小编写过了二分图的一些基础知识和匈牙利算法,今天来讲一讲km ...
- linux驱动之模块化编程
今天刚开始学习linux驱动的编写.在网上开了许多网友的博客,感觉比较好的摘抄下来,以便以后忘记可以随时查看.下面是摘抄文章的地址,非常感谢他们. http://blog.chinaunix.net/ ...
- Vscode配置C++环境
(终于申请博客了qaq) 之前用了那么久Dev-C++,总算换了一个编辑器,Visual Studio Code (Vscode). 界面可比以前的舒适多了. Vscode作为一款功能极其丰富的开发工 ...
- HTTP基础--请求
请求,由客户端向服务器端发出,可以分为4部分:请求方法(Request Method),请求的网址(Request URL),请求头(Request Headers),请求体(Request Body ...
- Java 实例 - 查看当前工作目录
package guyu.day0820; /** * @Author: Fred * @Date: 2020/8/20 14:25 */ public class Demo03 { public s ...
- 牛客网PAT练习场-到底买不买
题目地址:https://www.nowcoder.com/pat/6/problem/4065 题意:用数组统计好字符,最后进行相减,最后进行统计 /** * *作者:Ycute *时间:2019- ...
- Myeclipse maven 配置有问题 改之后重启还是不好用
在配置maven项目的时候我一大意选错了maven服务,然后回来改配置文件的时候发现改完之后重启并没有效果,重新清了好几次编译也不好用,最后发现最好是手动去更新一下maven服务的配置文件 位置如下: ...