Android应用程序启动流程(一)

一、前言

要想启动一个应用程序,首先要保证这个应用程序所需要的应用程序进程已经启动。Activity Manager Service(AMS)在启动应用程序时会检查这个应用程序所需要的应用进程是否存在,不存在就会请求Zygote进程启动所需要的应用程序进程。当应用程序进程启动完后,就会接着启动应用程序,也就是启动根Activity,这部分将在下一篇文章中分析。本篇文章就先来分析一下应用程序进程的启动流程。

二、应用程序进程启动流程

2.1 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
//路径:/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
......
try {
//设置各个参数的值,如uid、gids、debugFlags、entryPoint等
......

ProcessStartResult startResult;
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);
}
......
} catch (RuntimeException e) {
......
}
}

该方法先对所需要的参数进行初始化,其中entryPoint我们得知是android.app.ActivityThread,后文会再次提到它。然后判断hostingType(是个啥嘞?)是否是webview_service,如果是则调用startWebView方法,否则调用Process.start方法启动应用程序进程。该方法如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//路径:/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 debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
return zygoteProcess.start(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}

该方法并没有实现功能,而是调用了zygoteProcess.start方法来实现,zygoteProcess用来保持与Zygote进程的通信状态。该方法如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//路径:/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 debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}

好,还是个代理函数,该方法调用了startViaZygote来实现功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//路径:/frameworks/base/core/java/android/os/ZygoteProcess.java
/*
*Starts a new process via the zygote mechanism.
*/
private Process.ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] extraArgs)
throws ZygoteStartFailedEx {
//创建argsForZygote字符串数组,将应用进程的启动参数保存在其中
......

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

该方法将应用进程的启动参数转成字符串数组,然后调用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
32
33
34
35
36
37
38
39
//路径:/frameworks/base/core/java/android/os/ZygoteProcess.java
/**
* Tries to open socket to Zygote process if not already open. If
* already open, does nothing. May block and retry. Requires that mLock be held.
*/
@GuardedBy("mLock")
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
//检查当前线程是否持有mLock锁,没有则抛异常
Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");

if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
//通过Socket与主Zygote进程建立连接
primaryZygoteState = ZygoteState.connect(mSocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
}
//检查主Zygote进程的状态是否与给定的abi(应用二进制接口)匹配,匹配则返回主Zygote进程的状态
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}

// 主Zygote进程的状态与abi不匹配,尝试与辅Zygote进程建立连接
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
//通过Socket与辅Zygote进程建立连接
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);
}

该方法先检查当前线程是否上mLock锁,然后尝试与主Zygote连接,如果主Zygote状态与启动应用程序进程所需的ABI不匹配,则尝试连接辅Zygote,如果仍不匹配,则抛出异常。

Zygote的启动脚本有4中,其中init.zygote32_64.rcinit.zygote64_32.rc分主辅Zygote(谁在前谁主),主辅Zygote的区别在于所支持程序的位数(32位、64位)。

接下来看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
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/ZygoteProcess.java
/**
* Sends an argument list to the zygote process, which starts a new child
* and returns the child's pid. Please note: the present implementation
* replaces newlines in the argument list with spaces.
*
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
@GuardedBy("mLock")
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
try {
// 检查args数组中的参数
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");
}
}

/**
* See com.android.internal.os.SystemZygoteInit.readArgumentList()
* Presently the wire format to the zygote process is:
* a) a count of arguments (argc, in essence)
* b) a number of newline-separated argument strings equal to count
*
* After the zygote process reads these it will write the pid of
* the child or -1 on failure, followed by boolean to
* indicate whether a wrapper process was used.
*/
final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;
//将参数写入zygoteState中
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();


Process.ProcessStartResult result = new Process.ProcessStartResult();
//等待socket服务端(即zygote)返回新创建的进程pid、usingWrapper;

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进程进行Socket通信,等待socket服务端发送回来新创建的进程pid。如果pid>=0则进程创建成功,返回ProcessStartResult对象(包含pidusingWrapper),否则关闭ZygoteSocket并抛出异常。

接下来就是Zygote进程接收请求并创建应用程序进程了。

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

在分析[Android系统启动流程](Android系统启动流程 - gla2xy’s blog (gal2xy.github.io))中,ZygoteInit.javamain函数中,Zygote创建Socket服务端后,会通过runSelectLoop方法等待AMS的请求来创建新的应用程序进程。那我们就来分析一下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
50
51
52
53
54
55
56
57
58
//路径:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
//创建文件描述符的数组和zygoteConnection对象的数组
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
//mServerSocket是zygote进程的Socket,保存到fds[0]
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);

while (true) {
//创建一个 StructPollfd 数组 pollFds,用于存储待轮询的文件描述符
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 {
//使用 Os.poll() 方法对文件描述符进行轮询,等待有数据可读的文件描述符。该方法会阻塞直到有事件发生
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
//遍历 pollFds 数组,判断每个文件描述符是否有可读事件发生
for (int i = pollFds.length - 1; i >= 0; --i) {
//判断每个文件描述符是否有可读事件发生
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
//如果文件描述符索引为 0,表示有新的连接请求到达
if (i == 0) {
//调用 acceptCommandPeer() 方法接受连接,并将新的连接对象添加到 peers 和对应的文件描述符添加到 fds。
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
//如果文件描述符索引不为 0,则表示已有连接的数据可读,调用对应连接对象的 runOnce() 方法
boolean done = peers.get(i).runOnce(this);
//处理完后移除该文件描述符和连接对象
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
}



private ZygoteConnection acceptCommandPeer(String abiList) {
try {
return createNewConnection(mServerSocket.accept(), abiList);
} catch (IOException ex) {
throw new RuntimeException(
"IOException during accept()", ex);
}
}

整个runSelectLoop方法主要是通过死循环来轮询可读事件发生的文件描述符,找到后接受连接并创建连接对象并调用runOnce方法进行处理。该方法如下所示:

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
//路径:/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
/**
* Reads one start command from the command socket. If successful,
* a child is forked and a {@link Zygote.MethodAndArgsCaller}
* exception is thrown in that child while in the parent process,
* the method returns normally. On failure, the child is not
* spawned and messages are printed to the log and stderr. Returns
* a boolean status value indicating whether an end-of-file on the command
* socket has been encountered.
*
* @return false if command socket should continue to be read from, or
* true if an end-of-file has been encountered.
* @throws Zygote.MethodAndArgsCaller trampoline to invoke main()
* method in child process
*/
boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {

String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;

//获取启动参数和文件描述符
try {
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
Log.w(TAG, "IOException on command socket " + ex.getMessage());
closeSocket();
return true;
}

......

try {
//将binder客户端传递过来的参数,解析成Arguments对象格式
parsedArgs = new Arguments(args);

//根据参数做相应处理
......
//创建应用程序进程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
parsedArgs.appDataDir);
} catch (ErrnoException ex) {
......
}

try {

if (pid == 0) {
//当前代码运行在子进程中
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);//关闭文件描述符
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
return true;
} else {
//当前代码运行在父进程中
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}

该方法先获取启动参数和文件描述符,对其做处理后,调用Zygote.forkAndSpecialize方法创建应用程序进程,然后通过pid判断当前代码运行在哪个进程中,正常流程是创建成功,pid=0进入handleChildProc方法。

2.3 应用程序进程的初始化

handleChildProc方法如下所示:

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
//路径:/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
/**
* Handles post-fork setup of child proc, closing sockets as appropriate,
* reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
* if successful or returning if failed.
*
* @throws Zygote.MethodAndArgsCaller on success to
* trampoline to code that invokes static main.
*/
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws Zygote.MethodAndArgsCaller {

// 关闭从zygote继承过来的Socket通信
closeSocket();
//重定向std_xxx到descriptors数组中对应的文件描述符,然后关闭descriptors数组中的文件描述符
if (descriptors != null) {
try {
Os.dup2(descriptors[0], STDIN_FILENO);
Os.dup2(descriptors[1], STDOUT_FILENO);
Os.dup2(descriptors[2], STDERR_FILENO);

for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
newStderr = System.err;
} catch (ErrnoException ex) {
Log.e(TAG, "Error reopening stdio", ex);
}
}
//设置进程的命令行参数argv0为parsedArgs.niceName
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}

//关闭Trace事件,表示不再跟踪当前的活动管理器事件
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//invokeWith可能是一个用于指定子进程启动方式的参数
if (parsedArgs.invokeWith != null) {
//通过 WrapperInit.execApplication() 方法以另一个进程来执行应用程序进程
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
} else {
ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}

该方法主要用于配置子进程的初始环境,包括关闭父进程的通信管道、重定向标准输入输出和错误输出、设置子进程名称等。在完成这些操作后,根据不同的情况来启动子进程。

其中execApplication方法如下所示:

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
//路径:/frameworks/base/core/java/com/android/internal/os/WrapperInit.java
/**
* Executes a runtime application with a wrapper command.
* This method never returns.
*
* @param invokeWith The wrapper command.
* @param niceName The nice name for the application, or null if none.
* @param targetSdkVersion The target SDK version for the app.
* @param pipeFd The pipe to which the application's pid should be written, or null if none.
* @param args Arguments for {@link RuntimeInit#main}.
*/
public static void execApplication(String invokeWith, String niceName,
int targetSdkVersion, String instructionSet, FileDescriptor pipeFd,
String[] args) {
//创建指令字符串并构造指令
StringBuilder command = new StringBuilder(invokeWith);

final String appProcess;
//根据目标设备指令集选择相应的app_process可执行文件
if (VMRuntime.is64BitInstructionSet(instructionSet)) {
appProcess = "/system/bin/app_process64";
} else {
appProcess = "/system/bin/app_process32";
}
command.append(' ');
command.append(appProcess);
//指定--application参数来表示要执行的是应用程序
command.append(" /system/bin --application");
//添加 --nice-name= 参数
if (niceName != null) {
command.append(" '--nice-name=").append(niceName).append("'");
}
//使用 com.android.internal.os.WrapperInit 作为应用程序的入口点类
command.append(" com.android.internal.os.WrapperInit ");
//将 pipeFd 转换为整数并添加到命令字符串中。该整数用于在应用程序启动后向父进程写入应用程序的PID
command.append(pipeFd != null ? pipeFd.getInt$() : 0);
command.append(' ');
command.append(targetSdkVersion);
Zygote.appendQuotedShellArgs(command, args);
preserveCapabilities();
//调用 Zygote.execShell() 方法执行构建好的命令
Zygote.execShell(command.toString());
}

该方法通过构造命令来执行应用程序进程,其中/system/bin/app_process32这串字符有点眼熟啊!是在解析init.rc文件中出现过,也就是下面这个命令

1
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server

好了,这部分点到为止。

查阅了网上的博客,都认为在handleChildProc方法之后,进入分支zygoteInit方法,该方法如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//路径:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static final void zygoteInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
// 原生添加名为“ZygoteInit ”的systrace tag以标识进程初始化流程
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();//重定向log输出

RuntimeInit.commonInit();// 通用的一些初始化
ZygoteInit.nativeZygoteInit();//nativeZygoteInit函数中JNI调用启动进程的binder线程池
RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}

该方法的主要工作是标识进程初始化流程,重定向log输出,通用初始化处理,启动Binder线程池,然后调用applicationInit方法。该方法如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//路径:/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws Zygote.MethodAndArgsCaller {
//true代表应用程序退出时不调用AppRuntime.onExit(),否则会在退出前调用
nativeSetExitWithoutCleanup(true);

//设置虚拟机的内存利用率参数值为0.75和SDK版本
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

final Arguments args;
try {
args = new Arguments(argv);
} catch (IllegalArgumentException ex) {
Slog.e(TAG, ex.getMessage());
return;
}

// 结束ZygoteInit的systrace tag
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

invokeStaticMain(args.startClass, args.startArgs, classLoader);
}

关键的是invokeStaticMain方法,需要注意的是第一个参数args.startClass,就是文章开头提到的entryPoint参数,其值为android.app.ActivityThread。接下来我们查看invokeStaticMain方法,如下所示:

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
//路径:/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws Zygote.MethodAndArgsCaller {
Class<?> cl;

try {
//获取android.app.ActivityThread的类
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}

Method m;
try {
//获得android.app.ActivityThread中的main方法
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);
}

/*
* This throw gets caught in ZygoteInit.main(), which responds
* by invoking the exception's run() method. This arrangement
* clears up all the stack frames that were required in setting
* up the process.
*/
//通过抛出异常启动main方法
throw new Zygote.MethodAndArgsCaller(m, argv);
}

这部分的代码同系统启动流程中SystemService阶段的后一部分一致(其实从zygoteInit方法开始就一样了),这里就不再分析MethodAndArgsCaller方法,详细请见链接。接下来分析ActivityThreadmain方法。

2.4 应用程序进程的运行

ActivityThreadmain方法如下所示:

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
//路径:/frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
//开始跟踪,标记为"ActivityThreadMain"
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

//启动采样分析器集成,用于性能分析
SamplingProfilerIntegration.start();

//关闭CloseGuard,默认情况下它是启用的,但在此处将其禁用。CloseGuard用于检测资源没有正确关闭的情况
CloseGuard.setEnabled(false);

//初始化当前用户的环境变量
Environment.initForCurrentUser();

//设置事件日志的报告器,用于在libcore中记录事件日志
EventLogger.setReporter(new EventLoggingReporter());

//寻找CA证书的存储位置并设置为默认的CA证书存储位置
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);

//设置当前进程的argv[0]值为"<pre-initialized>"
Process.setArgV0("<pre-initialized>");

//创建并启动主线程的loop消息循环
Looper.prepareMainLooper();

//创建线程并将当前线程附加到ActivityThread,参数false表示不使用新线程
ActivityThread thread = new ActivityThread();
thread.attach(false);

//如果sMainThreadHandler为空,则将其设置为ActivityThread的Handler。
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}

//永假,可忽略
if (false) {
Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
}

//结束跟踪
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

//开始主线程的消息循环
Looper.loop();

throw new RuntimeException("Main thread loop unexpectedly exited");
}

该方法初始化一些环境变量和设置,并且创建了一个ActivityThread对象,然后进入主线程的消息循环。其中Handler是一个消息机制,用于同进程的线程间通信。

至此,应用程序进程就创建完成了并且运行了主线程的管理类ActivityThread

三、小结

应用程序进程启动过程主要可以分为以下几部分:

  1. AMS发送启动应用程序进程请求:AMS首先会调用startProcessLocked方法,最终通过openZygoteSocketIfNeeded方法与Zygote 的Socket建立连接,并通过zygoteSendArgsAndGetResult与进程进行通信,发送请求。
  2. Zygote进程接收请求并创建应用程序进程:Zygote通过runSelectLoop方法接收到AMS的请求,然后调用runOnce方法,通过forkAndSpecialize方法创建应用程序进程。
  3. 应用程序进程初始化和运行:应用程序进程创建完成后,首先会通过handleParentProc开始进行初始化工作,启动Binder线程池,最后通过抛出异常的方式调用MethodAndArgsCaller来启动应用程序进程,即进入到ActivityThreadmain方法,创建并启动主线程的消息循环,进入阻塞状态。

整个主线流程可用下面这张图概括(来自刘望舒博客的图片):


参考:

Android 应用启动全流程分析(源码深度剖析和 Systrace 展示)- 上篇 - 知乎 (zhihu.com)

理解Android进程创建流程 - Gityuan博客 | 袁辉辉的技术博客

Android应用程序进程启动过程(前篇) | BATcoder - 刘望舒 (liuwangshu.cn)


Android应用程序启动流程(一)
http://example.com/2023/07/17/Android安全/Android应用程序启动流程(一)/
作者
gla2xy
发布于
2023年7月17日
许可协议