parent
11891c44d1
commit
cfd23051a9
@ -0,0 +1,121 @@ |
|||||||
|
--- |
||||||
|
应用进程的启动 |
||||||
|
--- |
||||||
|
|
||||||
|
1. 了解 Linux 下进程启动的方式 |
||||||
|
2. 熟悉应用进程启动的基本流程 |
||||||
|
3. 深入理解应用进程启动的原理 |
||||||
|
|
||||||
|
#### 进程启动方式 |
||||||
|
|
||||||
|
```c |
||||||
|
if((pid = fork()) < 0){ |
||||||
|
// error |
||||||
|
}else if(pid == 0){ |
||||||
|
// child process |
||||||
|
// 子进程共享父进程的资源 |
||||||
|
}else { |
||||||
|
// parent process |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
```c |
||||||
|
if((pid = fork()) < 0){ |
||||||
|
// error |
||||||
|
}else if(pid == 0){ |
||||||
|
// child process |
||||||
|
// 子进程资源完全被 path 替换掉了,这个 path 是个二进程程序的路径 |
||||||
|
execve(path,argv,env); |
||||||
|
}else { |
||||||
|
// parent process |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
#### 应用进程启动原理 |
||||||
|
|
||||||
|
1. 什么时候触发的进程启动?谁发起的? |
||||||
|
2. 进程是谁启动的?怎么启动的? |
||||||
|
|
||||||
|
**触发进程启动** |
||||||
|
|
||||||
|
应用进程的启动是被动的,即在启动组件的时候,如果发现该组件所在的进程未被启动,那么这时候就会去启动进程。该操作是 Framework 层去做的: |
||||||
|
|
||||||
|
```java |
||||||
|
ProcessRecord app = getProcessRecordLocked(...) { |
||||||
|
// app.thread 是 IApplicationThread,是应用层的 binder 句柄 |
||||||
|
// 为了是 AMS 和应用进行双向调用 |
||||||
|
if(app != null && app.thread != null) { |
||||||
|
// 进程已经启动了,这里就可以启动组件了 |
||||||
|
return; |
||||||
|
} |
||||||
|
startProcessLocked(r.processName); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
应用进程启动后的入口函数: |
||||||
|
|
||||||
|
```java |
||||||
|
public static void main(String[] args) { |
||||||
|
Looper.prepareMainLooper(); |
||||||
|
|
||||||
|
ActivityThread thread = new ActivityThread(); |
||||||
|
thread.attach(false); |
||||||
|
|
||||||
|
Looper.loop(); |
||||||
|
throw new RuntimeException("..."); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
```java |
||||||
|
// 获取 AMS 的 binder 对象 |
||||||
|
final IActivityManager mgr = ActivityManagerNative.getDefault(); |
||||||
|
mgr.attachApplication(mAppThread); |
||||||
|
``` |
||||||
|
|
||||||
|
对于 AMS 来说,一个应用进程怎么样才算是启动完成呢? |
||||||
|
|
||||||
|
1. AMS 向 Zygote 发起启动应用进程的请求,然后 Zygote 启动并返回 pid 给 AMS |
||||||
|
2. 应用进程启动完成之后,告诉 AMS 注册 ApplicationThread |
||||||
|
|
||||||
|
#### 进程是怎么启动的? |
||||||
|
|
||||||
|
启动进程是在 AMS 里面的 startProcessLocked 函数,这个函数不会直接去启动进程,而是只是发起启动进程: |
||||||
|
|
||||||
|
1. 打开本地 socket,openZygoteSocketIfNeeded 函数 |
||||||
|
2. 通过 Socket 发送参数列表,参数包括应用进程启动之后要执行的类名,zygoteSendArgsAndGetResult 函数 |
||||||
|
3. 发送完参数列表之后等待返回创建的进程的 pid 即可 |
||||||
|
|
||||||
|
那么 Zygote 里面是如何处理 Socket 请求的? |
||||||
|
|
||||||
|
Zygote 会在一个 for 循环里面不断看有没有消息过来,如果有消息过来就执行 runOnce 函数: |
||||||
|
|
||||||
|
```java |
||||||
|
boolean runOnce() { |
||||||
|
// 读取 Zygote 发送过来的参数列表 |
||||||
|
String[] args = readArgumentList(); |
||||||
|
// 创建应用进程 |
||||||
|
int pid = Zygote.forkAndSpecialize(...); |
||||||
|
if(pid == 0) { |
||||||
|
// 子进程,执行 ActivityThread#main 函数 |
||||||
|
handleChildProc(...); |
||||||
|
return true; |
||||||
|
} else { |
||||||
|
// 父进程把 pid 通过 Socket 在写回去 |
||||||
|
return handlePArentProc(pid, ...); |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
#### 课堂作业 |
||||||
|
|
||||||
|
1. 为什么是 zygote 来创建进程,而不是 systemserver? |
||||||
|
2. AMS 和 zygote 为什么不用 binder 通信? |
||||||
|
|
||||||
|
#### 总结 |
||||||
|
|
||||||
|
应用进程是怎么启动的呢? |
||||||
|
|
||||||
|
1. 应用进程是什么时候起的? |
||||||
|
2. 由 ASM 向 zygote 发起的,通过 socket 通信 |
||||||
|
3. zygote fork 出应用进程,执行 ActivityThread#main 入口函数,这个入口函数的类名是 AMS 通过 Socket 发给 zygote 的 |
||||||
|
4. 进程启动之后要向 AMS 报告,注册 ApplicationThread,这样整个启动才算结束,因为 AMS 有了该报告,应用进程才算是可用,AMS 才能继续启用应用的各个组件 |
Loading…
Reference in new issue