Android应用进程启动流程

Launcher的源码在 packages 的目录下可以找到

Launcher也就是我们的桌面系统应用,点击一个app应用,就会调用到AMS的startActivity,进而调用AMS的 startProcessLocked 函数向 Zygote 进程发送一个创建新进程的请求

Launcher-AMP

时序图

startProcessLocked

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
//注意这里,最终会调用 ActivityThread 的main函数
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
...
if (hostingType.equals("webview_service")) {
startResult = startWebView(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, entryPointArgs);
} else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, entryPointArgs);
}
...
}

这个方法中最主要的就是调用 Process.start 来创建新进程

Process.start

Process.start会调用 zygoteProcess.start ,这个 ZygoteProcess 作用是维持与Zygote进程的通信状态,负责打开socket和启动新进程

zygoteProcess.start 函数也很简单, 直接调用 startViaZygote

startViaZygote

1
2
3
4
5
6
7
8
9
10
11
12
private Process.ProcessStartResult startViaZygote(....../*参数很多,省略*/)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<String>();

...//设置各种参数

argsForZygote.add(processClass);

synchronized(mLock) {
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}

该函数主要作用是将创建进程所需要的参数放到 argsForZygote 中,该数组保存了进程的uid、gid、groups、target-sdk、nice-name等一系列的参数,然后调用 zygoteSendArgsAndGetResult,注意他的参数中还调用了一个函数 openZygoteSocketIfNeeded

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
27
28
29
30
31
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");

if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
//向主zygote发起connect()操作 这个socket的名字为 'zygote'
primaryZygoteState = ZygoteState.connect(mSocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
}

if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}

//当主zygote没能匹配成功,则采用第二个zygote 这个socket的名字为 'zygote_secondary'
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
}

if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}

throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}

该函数主要作用就是创建一个连接到 zygote 进程的 LocalSocket 对象,它返回一个 ZygoteState,来代表与 zygote 进程通信的状态

之前在分析Zygote流程的时候,Zygote流程在启动时,会内部创建一个名称为 ‘zygote’ 的socket,这个socket与设备文件 /dev/socket/zygote绑定在一起的

ZygoteState.connect

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
public static ZygoteState connect(String socketAddress) throws IOException {
DataInputStream zygoteInputStream = null;
BufferedWriter zygoteWriter = null;
final LocalSocket zygoteSocket = new LocalSocket();

try {
zygoteSocket.connect(new LocalSocketAddress(socketAddress,
LocalSocketAddress.Namespace.RESERVED));

zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());

zygoteWriter = new BufferedWriter(new OutputStreamWriter(
zygoteSocket.getOutputStream()), 256);
} catch (IOException ex) {
try {
zygoteSocket.close();
} catch (IOException ignore) {
}

throw ex;
}

String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
Arrays.asList(abiListString.split(",")));
}

socketAddress是新建 ZygoteProcess 对象时设置的,他的字符串为 ‘zygote’
这个函数主要作用是建立socket连接,连接成功后,获得一个输入流 zygoteInputStream 传给 ZygoteState,输入流会接收zygote进程发送过来的数据,在后面的 zygoteSendArgsAndGetResult 函数中,他会读取输入流的数据

zygoteSendArgsAndGetResult

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
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
try {
int sz = args.size();
for (int i = 0; i < sz; i++) {
if (args.get(i).indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx("embedded newlines not allowed");
}
}

final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;

writer.write(Integer.toString(args.size()));
writer.newLine();

for (int i = 0; i < sz; i++) {
String arg = args.get(i);
writer.write(arg);
writer.newLine();
}

writer.flush();

// Should there be a timeout on this? 问谁呢?
Process.ProcessStartResult result = new Process.ProcessStartResult();

//等待socket服务端(即zygote)返回新创建的进程pid
result.pid = inputStream.readInt();
result.usingWrapper = inputStream.readBoolean();

if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
} catch (IOException ex) {
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}

把参数数据读取出来写入到zygoteState中,发送参数列表给 zygote 进程,zygote进程接收到数据后,会返回新进程的 pid

runSelectLoop

在Zygote流程分析中知道,Zygote进程会在一个名称为 ‘zygote’的socket等待客户端的数据,函数为 runSelectLoop

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
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
//sServerSocket是socket通信中的服务端,即zygote进程。保存到fds[0]
fds.add(sServerSocket.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) {
...
}

for (int i = pollFds.length - 1; i >= 0; --i) {
//采用I/O多路复用机制,当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行;
// 否则进入continue,跳出本次循环。
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
//即fds[0],代表的是sServerSocket,则意味着有客户端连接请求;
// 则创建ZygoteConnection对象,并添加到fds。
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor()); //添加到fds.
} else {
//i>0,则代表通过socket接收来自对端的数据,并执行相应操作
try {
ZygoteConnection connection = peers.get(i);
final Runnable command = connection.processOneCommand(this);
if (mIsForkChild) {
return command;
}
......
} catch (Exception e) {
......
}
}
}
}
}

该方法主要功能:

客户端通过openZygoteSocketIfNeeded()来跟zygote进程建立连接。zygote进程收到客户端连接请求后执行accept();然后再创建ZygoteConnection对象,并添加到fds数组列表;
processOneCommand()方法来接收客户端数据,并执行进程创建工作。

acceptCommandPeer

1
2
3
4
5
6
7
private static ZygoteConnection acceptCommandPeer(String abiList) {
try {
return new ZygoteConnection(sServerSocket.accept(), abiList);
} catch (IOException ex) {
...
}
}

接收客户端发送过来的connect()操作,Zygote作为服务端执行accept()操作。 再后面客户端调用write()写数据,Zygote进程调用read()读数据

没有连接请求时会进入休眠状态,当有创建新进程的连接请求时,唤醒Zygote进程,创建Socket通道ZygoteConnection,然后执行ZygoteConnection的runOnce()方法

processOneCommand 函数中,会解析客户端的数据,也就是那一堆的参数,然后进行 forkAndSpecialize 来fork进程,fokr之后有段逻辑是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
try {
if (pid == 0) {
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
return handleChildProc(parsedArgs, descriptors, childPipeFd);
} else {
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, descriptors, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}

fork之后,父进程就直接返回null退出了,新进程会继续执行,fork操作会返回一个值给两个不同进程,一人一个.
我们是新进程,因此进入 pid == 0,调用 handleChildProc

handleChildProc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd) {
//关闭新进程中的socket
closeSocket();
......

// End of the postFork event.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (parsedArgs.invokeWith != null) {
......
} else {
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
null /* classLoader */);
}
}

在前面的 startViaZygote 函数中有添加invokeWith属性

1
2
3
4
if (invokeWith != null) {
argsForZygote.add("--invoke-with");
argsForZygote.add(invokeWith);
}

因此,它调用 ZygoteInit.zygoteInit

zygoteInit

1
2
3
4
5
6
7
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
RuntimeInit.redirectLogStreams();

RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}

commonInit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private static final void commonInit() {
// 设置默认的未捕捉异常处理方法
Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());

// 设置市区,中国时区为"Asia/Shanghai"
TimezoneGetter.setInstance(new TimezoneGetter() {
public String getId() {
return SystemProperties.get("persist.sys.timezone");
}
});
TimeZone.setDefault(null);

//重置log配置
LogManager.getLogManager().reset();
new AndroidConfig();

// 设置默认的HTTP User-agent格式,用于 HttpURLConnection。
String userAgent = getDefaultUserAgent();
System.setProperty("http.agent", userAgent);

// 设置socket的tag,用于网络流量统计
NetworkManagementSocketTagger.install();
}

该函数主要作用是为应用程序进程设置时间和键盘等通用信息

nativeZygoteInit

native在zygote启动过程中的 startReg 中进行了注册

1
2
3
4
5
6
7
8
9
int register_com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env)
{
const JNINativeMethod methods[] = {
{ "nativeZygoteInit", "()V",
(void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
};
return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
methods, NELEM(methods));
}

对应的方法在 AndroidRuntime.cpp 中定义

1
2
3
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz) {
gCurRuntime->onZygoteInit();
}

AndroidRuntime.cpp的具体实现文件是 app_main.cpp文件

1
2
3
4
5
6
virtual void onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}

ProcessState,眼熟的东西,在分析 Binder系列 的时候分析过,它代表进程

ProcessState::self():主要工作是调用open()打开/dev/binder驱动设备,再利用mmap()映射内核的地址空间,将Binder驱动的fd赋值ProcessState对象中的变量mDriverFD,用于交互操作。startThreadPool()是创建一个新的binder线程,不断进行talkWithDriver().
startThreadPool(): 启动Binder线程池

这个函数主要作用,就是启动Binder线程池

applicationInit

1
2
3
4
5
6
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
......

return findStaticMain(args.startClass, args.startArgs, classLoader);
}
findStaticMain
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class<?> cl;
try {
cl = Class.forName(className, true, classLoader);
}
...

Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });
}
...
return new MethodAndArgsCaller(m, argv);
}

findStaticMain 函数的主要作用就是通过反射找到目标的main函数

在第一步 startProcessLocked 的分析中,设置的args.startClass为 “android.app.ActivityThread”,因此它要找的就是类 ActivityThread 的 main 函数

Zygote.main

MethodAndArgsCaller 是一个 Runnable

zygote的main函数的流程可以简化为下

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String argv[]) {
try {
caller = zygoteServer.runSelectLoop(abiList);
....
} catch (RuntimeException ex) {
closeServerSocket();
throw ex;
}
if (caller != null) {
caller.run();
}
}

::: warning
注意,之前在分析acceptCommandPeer部分的时候,父进程是直接返回null的,新进程是返回一个runnable,因此,这部分的代码在不同进程中的执行是不同的.对于父进程也就是Zygote进程,他是一直循环运行的,对于新进程,会完成启动操作后停止循环并调用目标类的main函数
:::

MethodAndArgsCaller

caller为 MethodAndArgsCaller,看看 MethodAndArgsCaller 的 run

1
2
3
4
5
6
7
8
9
10
11
12
13
static class MethodAndArgsCaller implements Runnable {
...

public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
...
} catch (InvocationTargetException ex) {
...
}
}
}

就是简单的反射调用 main 方法

MethodAndArgsCaller在之前的源码版本中是用过抛出异常的形式返回的,7.0后就修改为直接返回了,通过后续代码caller.run()的调用来实现

另外旧版本为何抛出异常的原因是因为要清空调用堆栈的,貌似新版本的处理是不需要做这些操作了还是在zygote的main函数做了处理,做个记录,后续需要再做研究

到底为止,新进程的启动工作就完全结束了,下面就进入了 ActivityThread 的 main 函数

ActivityThread.main

相信读者对 ActivityThread 并不陌生

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void main(String[] args) {
......

Looper.prepareMainLooper();

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

if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}

......

Looper.loop();

throw new RuntimeException("Main thread loop unexpectedly exited");
}
  • 创建主线程Looper
  • 主线程进入循环

可以知道,在Android系统中,每一个进程在启动完成后,都会进入一个消息循环

总结

  1. zygote的main函数中 runSelectLoop 部分不同进程的操作是不一样的,对于父进程也就是Zygote进程,他是一直循环运行的,对于新进程,会完成启动操作后停止循环并调用目标类的main函数
  2. Process.start()方法是阻塞操作,等待直到进程创建完成并返回相应的新进程pid,才完成该方法
  3. 当App第一次启动时或者启动远程Service,即AndroidManifest.xml文件中定义了process:remote属性时,都需要创建进程。比如当用户点击桌面的某个App图标,桌面本身是一个app(即Launcher App),那么Launcher所在进程便是这次创建新进程的发起进程,该通过binder发送消息给system_server进程,该进程承载着整个java framework的核心服务

进程模型图

参考博客 理解Android进程创建流程 老罗