0%

应用进程是如何启动的

zygote的启动

zygote 的功能

zygote 进程的主要功能有两个:

  1. 在系统启动时启动 SystemServer 进程
  2. 启动 应用进程

zygote 进程的启动过程

zygote进程的创建。

在 Android 系统开机之后,会创建 init 进程,这是 Linux 系统启动后创建的第一个进程。 init 进程有一个配置文件 init.rc 。 将需要启动的服务写入到 init.rc 中, init 进程在启动后就会创建这些进程, 比如 zygote , ServiceManager 等。

zygote 进程的 native 部分。

zygote 的c层代码入口在 /rameworks/base/cmds/app_process/app_main.cpp 中,最终主要的工作内容在 /frameworks/base/core/jni/AndroidRuntime.cpp 。主要内容如下。不详细分析了

  • 启动虚拟机。
  • 注册 JNI 函数
  • 调用 Java 类 Zygote.main 方法,进入 Java 循环 。

zygote 进程的 Java 部分

zygote 的 java 入口在 /android_aosp/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java 中

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// /android_aosp/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
...
final Runnable caller;
try {

RuntimeInit.enableDdms();

boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}

// 注册 socket
zygoteServer.registerServerSocketFromEnv(socketName);

// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
if (!enableLazyPreload) {
// 预加载类和资源
preload(bootTimingsTraceLog);
} else {
Zygote.resetNicePriority();
}

...
if (startSystemServer) {
// fork SystemServer 进程
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);

// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
// 如果 r != null ,说明是子进程 SystemServer ,r.run 应该是进入 SystemServer 的事件循环,然后直接return
r.run();
return;
}
}

// zygote 事件循环,不让zygote退出
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
throw ex;
} finally {
zygoteServer.closeServerSocket();
}

// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if (caller != null) {
caller.run();
}
}
  • 注册 Socket 服务, zygote 进程通过 socket 和 AMS 通信
  • 预加载类和资源。这样在 fork SystemServer 和 应用进程时,能够直接拷贝给子进程使用
  • fork 出 SystemServer 进程, SystemServer 进程随后又会启动 Binder ,并启动这种系统 Service ,比如 AMS ,WMS 等。
  • 进入 loop 循环,等待接收 AMS 的 Socket 消息。 收到消息后会调用 runOnce 方法,fork 出应用进程,并执行应用进程的 ActivityThread.main()

小结:

注意:zygote fork 进程时一定是单线程的

  • zygote 新 fork 出来的进程不需要再创建java虚拟机,因为 fork 出来的子进程是会继承拷贝父进程的资源的, fork 出来的进程会拥有 zygote 进程的虚拟机的拷贝
  • 为什么要设计一个 zygote 来 fork 应用进程,而不是 SystemServer :
    • 因为systemServer中运行了很多系统服务,不能被继承。应用程序启动时,除了必要的资源外,最好是干净的,所以需要单独用一个zygote来fork。
  • 为什么Zygote要使用Socket不使用binder:
    • 因为binder机制支持并发有一个线程池,如果zygote支持并发,在fork之后,会把线程池中的线程一起复制一份。 如果zygote的binder线程池处于一个等待锁的状态,fork之后的新进程依然是在等待锁的,并且不能解锁。 从而有可能造成死锁

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// /frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

fds.add(mServerSocket.getFileDescriptor());
peers.add(null);

while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
//处理轮询状态,当pollFds有事件到来则往下执行,否则阻塞在这里
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}

if (i == 0) {
// 这里没看懂。。。
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
try {
// 处理接收到的消息
ZygoteConnection connection = peers.get(i);
final Runnable command = connection.processOneCommand(this);
...
} ...
}
}
}
}
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// /frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
Runnable processOneCommand(ZygoteServer zygoteServer) {
...
pid = Zygote.forkAndSpecialize(parsedArgs.uid, ...);

try {
if (pid == 0) {
// 子进程
zygoteServer.setForkChild();

zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;

return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.startChildZygote);
} else {
// 父进程
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, descriptors, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}

private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd, boolean isZygote) {

closeSocket();
...
if (!isZygote) {
// 应用进程启动流程进入这个分支
// 从 socket 传来参数中取出 class ,并执行 main 方法
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
null /* classLoader */);
} else {
// 没看懂这个分支是做什么的。。
// 看注释的意思是提供了「跳过启动binder,直接创建进程」的方式
return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}

应用进程的启动

我们以 Activity 的启动为入口,来探讨应用进程的启动过程

AMS 发起创建进程

由 Activity 的启动寻找应用进程创建的入口

首先来看 Activity 的启动。安卓四大组件都是由AMS来管理的。 应用进程会调用 AMS 的binder 对象,实现在 ActivityManagerService.startActivity 里。

最终顺着调用栈,会走到 ActivityStackSupervisor.startSpecificActivityLocked(…)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// /frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);

if (app != null && app.thread != null) {
try {
// 进程已启动,真正开始启动 activity 了,哎,调用链太长了
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
}
}
// 进程没启动,开始启动进程了
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}

上面的逻辑里,会先判断要启动的 activity 所在应用的进程是否启动,如果已经成功启动,则开始启动 activity ;否则,启动引用进程。
注意这里应用是否启动的判断条件: if (app != null && app.thread != null)
ProcessRecord 是应用进程在 AMS 的信息记录,除了判断 app 不为空,还对 app.thread 。这个 app.thread 是一个 IApplicationThread binder 对象,这个对象很重要。

AMS 发送 Socket 给 zygote

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@GuardedBy("this")
private boolean startProcessLocked(String hostingType, String hostingNameStr, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
String seInfo, String requiredAbi, String instructionSet, String invokeWith,
long startTime) {
...
if (mConstants.FLAG_PROCESS_START_ASYNC) {
// 异步启动进程,忽略吧
...
return true;
} else {
try {
final ProcessStartResult startResult = startProcess(hostingType, entryPoint, app,
uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet,
invokeWith, startTime);
handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
startSeq, false);
} catch (RuntimeException e) {
...
}
return app.pid > 0;
}
}

AMS.startProcess 会调用 Process.start(…) 方法

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// /frameworks/base/core/java/android/os/Process.java
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
return zygoteProcess.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}

// /frameworks/base/core/java/android/os/ZygoteProcess.java
public final Process.ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
...
}
}

private Process.ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
boolean startChildZygote,
String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<String>();
... // 组装 socket 的参数
synchronized(mLock) {
// openZygoteSocketIfNeeded 会获取一个 ZygoteState ,有必要的话,会创建 socket 连接。 ZygoteState 包含了 socket 输入输出流。
// zygote fork 进程成功会返回应用进程的 pid
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}

AMS 会发送 socket 消息给 zygote ,zygote 会 fork 应用进程,并执行应用进程的 ActivityThread.main 方法

应用进程在启动之后都干了啥?

thread.attach(…)

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
27
28
// frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
Looper.prepareMainLooper();

ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);

Looper.loop();
}

private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
// 走这个分支
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...
} else {
...
}
...
}

应用整个进程的入口在 ActivityThread.main() 方法中,这个方法里没啥操作: 1. 准备 Looper 2. 实例化 ActivityThread ,并 attach 3. 开启 Looper 循环

显然, main 方法里做的事情支撑不了一个 app 的启动。 重点看 thread.attach , 它 使用 binder 调用了 AMS.attachApplication ,然后又调用了 AMS.attachApplicationLocked(…)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 伪代码。。
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {

ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
} else {
app = null;
}

thread.bindApplication(...);

// 处理一些因为应用进程还没有启动而暂存的组件
mStackSupervisor.attachApplicationLocked(app);
...
mServices.attachApplicationLocked(app, processName);
...
sendPendingBroadcastsLocked(app);
}

thread.bindApplication(…)

AMS 在 attch 进程之后又通过 binder 调用了应用进程的 bindApplication

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
String buildSerial, boolean autofillCompatibilityEnabled) {

...

AppBindData data = new AppBindData();
... // 补充 AppBindData 的参数

// 发送一个 消息到 H handler
sendMessage(H.BIND_APPLICATION, data);
}

在应用进程,发送了一个 H.BIND_APPLICATION 给 handler ,实现了线程的切换。 注意 通过 binder对象调用,是运行在 binder 线程里的,所以这个 bindApplication 也是运行在 binder 线程里的,需要切换回主线程。

handleBindApplication

1
2
3
4
5
6
7
8
// 伪代码
private void handleBindApplication(AppBindData data) {
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);

Application app = data.info.makeApplication(data.restrictedBackupMode, null);

mInstrumentation.callApplicationOnCreate(app);
}

data.info 是一个描述应用安装包信息的类。 data.info.makeApplication 一个applicaiton 类,并调用生命周期的 onCreate

1
2
3
4
5
6
7
8
// frameworks/base/core/java/android/app/LoadedApk.java
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
// 创建 application 和 context 对象,并绑定
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
}

这样,应用的启动就完成了