0%

第3章:应用程序进程启动过程

AMS启动一个应用程序首先要保证该应用程序的进程已经启动,如果应用程序进程还不存在,则请求 Zygote 进程启动进程。

从前一章内容可知,在Zygote 的Java 框架层会创建Server 端的Socket,用于等待AMS 请求Zygote 创建新的应用程序进程。Zygote 通过fork自身即可创建应用程序进程,这个进程会包含虚拟机实例,并且会创建Binder线程池和消息循环。

本章学习应用程序进程的启动,注意,是应用程序进程而不是应用程序的启动过程。

应用程序进程启动过程介绍

AMS发送启动应用程序进程请求过程的时序图

AMS 通过调用 startProcessLocked 向 Zygote 进程发送请求, 主要代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride ,String entryPoint ,String [] entryPointArgs) {
...
//获取要创建的应用程序进程的用户 ID
int uid = app.uid; //1

int [] gids = null;
if (!app.isolated) {
//2 gids创建和赋值
if (ArrayUtils isEmpty(permGids)){
gids =new int[3];
}else {
gids = new int[permGids.leng + 3] ;
System.arraycopy(permGids, 0, gids, 3, permGids.length) ;
gids[O] = UserHandle.getSharedAppGid(UserHandle.getAppid(uid));
gids[1] = UserHandle.getCacheAppGid(UserHandle .getAppid(uid)) ;
gids[2] = UserHandle.getUserGid{UserHandle.getUserid(uid));
}

...
if (entryPoint = null) entryPoint = "android.app.ActivityThread";//3

...
//启动应用程序进程,这里省略不重要的参数
startResult = Process.start(entryPoint,xxx,uid, xxx,gids,xxx,xxx);

上述代码首先得到应用程序进程的用户ID,之后创建用户组ID 并且赋值,在注释3处判断 entryPoint 为null就赋值 “android.app.ActivityThread”,这个值就是应用程序进程主线程的类名。在最终调用 Process.start 创建进程时,会将进程的用户ID和用户组ID传入。

Process.start会将实现交给 ZygoteProcess(ZygoteProcess用于保持与Zygote进程的通信状态)的start 方法处理,其中首先会执行 openZygoteSocketifNeeded 方法,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
if (primaryZygoteState == null || primaryZygoteState.isClosed ()) {
try {
//与 Zygote 进程建立 Socket 连接
primaryZygoteState = ZygoteState.connect(mSocket);//1
} catch (IOException ioe} {
throw new ZygoteStartFailedEx ("Error connecting to primary zygote", ioe)
}
//连接 Zygote 主模式返回的 ZygoteState 是否与启动应用程序进程所需要的ABI匹配
if (primaryZygotestate.matches (abi)) {//2
return primaryZygoteState;
}

//如果不匹配,则尝试连接 Zygote 辅模式
if (secondaryZygoteState ==null || secondaryZygoteState.isClosed()) {
try {
secondaryZygoteState = ZygoteState.connect(mSecondarySocket);//3
} catch (IOException ioe) {
throw new ZygoteStartFailedEx ("Error connecting to secondary zygote", ioe) ;
}

//连接 Zygote 辅模式返回的 ZygoteState 是否与启动应用程序进程所需要的 ABI 匹配
if (secondaryZygoteState.matches(abi)) {//4
return secondaryZygoteState;
}
throw new ZygoteStartFailedEx ("Unsupported zygote ABI :" + abi);

前面章节提到Zygote的main方法中会创建name为 “zygote” 的server端Socket,注释1就是与Zygote进程建立Socket 连接(name为”zygote”),并得到 ZygoteState 对象primaryZygoteState;注释2处如果primaryZygoteState 与启动应用程序所需要的 ABI 不匹配,则在注释3处连接name为 “zygote_secondary” 的Socket。如果辅模式返回的 ZygoteState 与进程所需的ABI也不匹配,就抛出异常。

通过 openZygoteSocketifNeeded 获取ZygoteState后,将其作为参数调用 ZygoteProcess的 ZygoteSendArgsAndGetResult 方法 获取Process.ProcessStartResult。

Zygote 接收请求并创建应用程序进程

执行完以上步骤后,继续执行 argsForZygote 方法即可让Zygote 收到创建新的应用程序进程的请求。Zygote 接收请求并创建应用程序进程的时序图如下:

Zygote接收请求并创建应用程序进程的时序图

由前面章节我们知道,Zygote 中的Server Socket 的runSelectLoop 方法一直在等待 AMS请求创建新的应用程序进程,runSelectLoop 中是通过 runOnce 来创建进程的,runOnce最终调用到 Zygote 的 forkAndSpecialize 方法创建应用程序进程,并返回pid。forkAndSpecialize 通过fork 当前进程来创建一个子进程。此后,便会在应用程序进程中创建 Binder 线程池,*进一步通过反射 ActivityThread 类的main方法调用,令应用程序进程进入了ActivityThread 的main方法中。此时,应用程序进程创建完毕,并且运行了主线程管理类 ActivityThread *

如果pid为0,说明当前代码运行在新创建的子进程中。

Binder 线程池启动过程

程序中会检查代码,确保Binder线程池只会被启动一次。

消息循环创建过程

通过反射方式 invok 执行 ActivityThread 的main方法时,会执行一系列主线程的工作,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//frameworks/base/core/java/android/app/ActivityThread.java 

public static void main(String[] args) {
...
//创建主线程 Looper
Looper.prepareMainLooper(); //1
ActivityThread thread= new ActivityThread(); //2
thread.attach(false) ;
if (sMainThreadHandler == null ) {//3
//创建主线程 H 类
sMainThreadHandler = thread . getHandler ();//4
if (false) {
Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER) ;
//Looper 开始工作
Looper.loop (); //5
throw new RuntimeException("Main thread loop unexpectedly exited");
}

ActivityThread类用于管理当前应用程序进程的主线程,上述代码中创建了主线程的消息循环Looper,其中的内部类 H 继承 Handler,在注释 5 处调用Looper.loop ,即使得Looper 开始处理消息,可见,系统在应用程序进程启动完成后,就会创建消息循环。

谢谢你的鼓励