Android 应用程序进程启动过程
应用程序进程简介
要想启动一个应用程序,须先确保它所需的应用程序进程已经启动。由 AMS 来检查这个进程是否存在,不存在就会请求 Zygote 进程来启动这个进程。
在 Zygote 的 Java 框架层中会创建一个 Server 端的 Socket 用来等待 Zygote 创建新的应用程序进程。
Zygote 进程通过 fock 自身创建应用程序进程,这个程序会获得 Zygote 进程在启动时创建的虚拟机实例,并且还创建了 Binder 线程池和消息循环,这样运行在应用进程中的应用程序就可以方便地使用 Binder 进行进程间通信以及处理消息了。
应用程序进程启动过程介绍
这里将其分为两部分,AMS 发送启动应用程序进程请求,和 Zygote 接收请求并创建应用程序进程。
AMS 发送启动应用程序进程请求
AMS 会通过调用 startProcessLocked() 向 Zygote 进程发送请求来启动应用程序,在 startProcessLocked() 中做了几件事:
得到创建应用程序进程的用户 ID。
1
int uid = app.uid;
对用户组 ID(gids)进行创建和赋值。
1
2
3
4
5
6
7
8
9if (ArrayUtils.isEmpty(permGids)) {
gids = new int[3];
} else {
gids = new int[permGids.length + 3];
System.arraycopy(permGids, 0, gids, 3, permGids.length);
}
gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));如果 entryPoint 为 null,则赋值为 android.app.ActivityThread,这个值为应用程序进程主线程的类名。
1
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
调用 Process 的 start 方法。
1
2
3
4
5// 将上面三步的值传入
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, entryPointArgs);
在 Process 的 start() 中只调用了 ZygoteProcess 的 start() ,ZygoteProcess 类用于保持与 Zygote 进程的通信状态,它的 start() 调用了 startViaZygote(),此方法做了如下几件事:ZygoteProcess.java
创建字符串列表 argsForZygote,并将应用程序的启动参数保存其中。
1
2
3
4
5
6
7
8
9
10
11
12ArrayList<String> argsForZygote = new ArrayList<String>();
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {
argsForZygote.add("--enable-jni-logging");
}
...
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);方法最后调用了 zygoteSendArgsAndGetResult()。
1
2
3
4// argsForZygote 是上面的字符串列表
synchronized(mLock) {
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
zygoteSendArgsAndGetResult() 的主要作用就是将传入的应用进程的启动参数 argsForZygote 写入 ZygoteState 中,ZygoteState 是 ZygoteProcess 的静态内部类,用于表示与 Zygote 进程通信的状态。ZygoteState 是由 openZygoteSocketIfNeeded() 返回的。openZygoteSocketIfNeeded() 做了如下几件事:ZygoteProcess.java(已知,在 Zygote 进程启动过程时,在 Zygote 的 main 方法中会创建 name 为 ”zygote“ 的 Service 端 Socket。)
调用 ZygoteState 的 connect 方法与名称为 ZYGOTE_SOCKET(值为 ”zygote“ ) 的 Socket 建立连接。
1
2
3
4
5
6
7
8if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
// 与 Zygote 进程建立 Socket 连接,并返回 ZygoteState 类型的 primaryZygoteState 对象。
primaryZygoteState = ZygoteState.connect(mSocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
}如果 primaryZygoteState 与启动应用程序进程所需的 ABI 不匹配,则连接 name 为 ”zygote_secondary“ 的 Socket。(已知,Zygote 的启动脚本有 4 种,如果采用的是 init_zygote32_64.rc 或者 init_zygote64_32.rc,则 name 为 ”zygote“ 的主模式,name 为 ”zygote_secondary“ 的为辅模式。)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// 连接 Zygote 主模式返回的 ZygoteState 是否与启动应用程序进程所需要的 ABI 匹配。
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
// 如果不匹配,则尝试连接 Zygote 辅模式。
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
}
// 连接 Zygote 辅模式返回的 ZygoteState 是否与启动应用程序进程所需要的 ABI 匹配。
if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}
// 如果都不匹配,则抛出异常。
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
Zygote 接收请求并创建应用程序进程
Socket 连接成功并匹配 ABI 后会返回 ZygoteState 类型对象,在 zygoteSendArgsAndGetResult() 中可以看到,会将应用程序的启动参数写入 ZygoteState 中,这样 Zygote 进程就会收到一个创建新的应用程序进程的请求,首先看 ZygoteInit 的 main 方法做了哪些事:ZygoteInit.java
通过 registerServerSocket() 创建了一个 Server 端的 Socket,这个 name 为 ”zygote“ 的 Socket 用来等待 AMS 请求 Zygote,以创建新的应用程序进程。
1
2// 创建一个 Server 端的 Socket,SocketName 的值为 ”zygote“。
zygoteServer.registerServerSocket(socketName);预加载类和资源。
1
preload(bootTimingsTraceLog);
启动 SystemServer 进程,这样系统的服务也会由 SystemServer 进程启动起来。
1 | if (startSystemServer) { |
调用 ZygoteServer 的 runSelectLoop() 来等待 AMS 请求创建新的应用程序进程。
1
zygoteServer.runSelectLoop(abiList);
在 runSelectLoop() 内部,当有 AMS 的请求数据到来时,会调用到 ZygoteConnection 的 runOnce() 来处理请求数据,runOnce() 做了如下几件事:ZygoteConnection.java
调用 readArgumentList() 获取应用程序进程的启动参数。
1
2
3
4String args[];
...
args = readArgumentList();
将 args 封装到 Arguments 类型的 parsedArgs 对象中。
1
parsedArgs = new Arguments(args);
调用 Zygote 的 forkAndSpecialize() 来创建应用程序进程,参数为 parsedArgs 中存储的应用进程启动参数,返回值为 pid。
1
2
3
4
5// 创建应用程序进程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
parsedArgs.appDataDir);
forkAndSpecialize() 主要是通过 fork 当前进程来创建一个子进程的,如果 pid 等于 0,则说明当前代码逻辑运行在新创建的子进程(应用程序进程)中,这时就会调用 handleChildProc() 来处理应用程序进程,handleChildProc() 中调用了 ZygoteInit 的 zygoteInit(),zygoteInit() 做了如下几件事:ZygoteInit.java
在新创建的应用程序进程中创建 Binder 线程池。
1
ZygoteInit.nativeZygoteInit();
调用了 RuntimeInit 的 applicationInit 方法。
1
RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
applicationInit() 内部会调用 invokeStaticMain(args.startClass, args.startArgs, classLoader);,它的第一个参数指的就是前面的 android.app.ActivityThread 参数。invokeStaticMain() 做了如下几件事:RuntimeInit.java
通过反射获得 android.app.ActivityThread 类
1
2Class<?> cl;
cl = Class.forName(className, true, classLoader);获得 ActivityThread 的 main 方法
1
2Method m;
m = cl.getMethod("main", new Class[] { String[].class });将上一步的 main 方法传入 Zygote 中的 MethodAndArgsCaller 类的构造方法中,这里抛出的 MethodAndArgsCaller 异常会被 Zygote 的 main 方法捕获。这里采用了抛出异常而不是直接调用 ActivityThread 的 main,原理和 Zygote 处理 SystemServer 进程是一样的,这种抛出异常的处理会清除所有的设置过程需要的堆栈帧,并让 ActivityThread 的 main 方法看起来像是应用程序进程的入口方法。
1
throw new Zygote.MethodAndArgsCaller(m, argv);
接下来 ZygoteInit.java 的 main 方法通过 try catch 捕获到 MethodAndArgsCaller 异常时,会调用 MethodAndArgsCaller 的 run 方法,MethodAndArgsCaller 是 Zygote.java 的静态内部类。在 run 方法中调用了 mMethod.invoke(null, new Object[] { mArgs });
,mMethod 指的就是 ActivityThread 的 main 方法,调用了 mMethod 的 invoke 方法后,ActivityThread 的 main 方法就会被动态调用,应用程序进程就进入了 ActivityThread 的 main 方法中。到这里,应用程序进程就创建完成了并且运行了主线程的管理类 ActivityThread。
Binder 线程池启动过程
当 Zygote 接收请求并创建应用程序进程,在应用程序进程创建过程中会启动 Binder 线程池,查看 ZygoteInit 类的 zygoteInit 方法,通过 ZygoteInit.nativeZygoteInit();
在新创建的应用程序进程中创建 Binder 线程池,nativeZygoteInit() 是一个 JNI 方法 private static final native void nativeZygoteInit();
,它对应的函数是在 AndroidRuntime.cpp 的 JNINativeMethod 数组中的 com_android_internal_os_ZygoteInit_nativeZygoteInit,在 AndroidRuntime.cpp 中可以看到,com_android_internal_os_ZygoteInit_nativeZygoteInit 函数如下,
1 | static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz) |
gCurRuntime 是 AndroidRuntime 类型的指针,它是在 AndroidRuntime 初始化时就创建的,如下所示,
1 | ... |
AppRuntime 继承自 AndroidRuntime,AppRuntime 创建时就会调用 AndroidRuntime 的构造函数,gCurRuntime 就会被初始化,它指向的是 AppRuntime,接下来查看 AppRuntime 的 onZygoteInit 函数,app_main.cpp
1 | virtual void onZygoteInit() |
最后一行会调用 ProcessState 的 startThreadPool 函数来启动 Binder 线程池,ProcessState.cpp
1 | void ProcessState::startThreadPool() |
支持 Binder 通信的进程中都有一个 ProcessState 类,它里面有一个 mThreadPoolStarted 变量,表示 Binder 线程池是否已经被启动过,默认值是 false。在每次调用 startThreadPool() 时都会先检查这个标记,从而确保 Binder 线程池只会被启动一次。如果 Binder 线程池未被启动,则设置 mThreadPoolStarted 为 true,并调用 spawnPooledThread() 来创建线程池中的第一个线程,也就是线程池的主线程,
1 | void ProcessState::spawnPooledThread(bool isMain) |
可以看到 Binder 线程为一个 PoolThread。并调用了它的 run 函数来启动一个新线程,接下来查看 PoolThread 类,
1 | // PoolThread 类继承了 Thread 类 |
消息循环创建过程
当 Zygote 接收请求并创建应用程序进程,在应用程序进程启动后会创建消息循环。首先回到 RuntimeInit 的 invokeStaticMain(),此方法的最后一行会抛出一个 MethodAndArgsCaller 异常,此异常会被 ZygoteInit 的 main 方法通过 try catch 捕获,并执行 MethodAndArgsCaller 的 run 方法,在 run 方法中调用了 mMethod.invoke(null, new Object[] { mArgs });
,mMethod 指的就是 ActivityThread 的 main 方法,mArgs 指的是应用程序进程的启动参数,查看 ActivityThread 的 main 方法,ActivityThread.java。ActivityThread 类用于管理当前应用程序进程的主线程。
1 | public static void main(String[] args) { |
可以看出,系统在应用程序进程启动完成后,就会创建一个消息循环,这样运行在应用程序进程中的应用程序可以方便地使用消息处理机制。
备注
注:基于 Android 8.0 源码
参考资料:
Android 进阶解密