我正在参与掘金创作者训练营第4期,点击了解活动详情,一起学习吧!
应用进程启动流程分析(服务端篇)
在上篇应用进程启动流程分析(客户端篇)中,分析到,在Process.start函数调用时,通过跟zygote对应的socket建立对应的连接,然后将参数数据通过socket通信发送给服务端,那么服务端接收到对应的参数,是如何进行处理的呢?
记得此前分析过system_server进程启动流程分析一篇中,ZygoteInit的启动中,我们分析过其main函数(通过app_process程序的main函数中反射调用ZygoteInit.main函数),在其main函数中,会fork system_server进程,但同时会初始化一个ZygoteServer对象
public static void main(String argv[]) {
ZygoteServer zygoteServer = null;
/// ......
Runnable caller;
try {
// ......
// 初始化ZygoteServer对象
zygoteServer = new ZygoteServer(isPrimaryZygote);
// ......
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
caller = zygoteServer.runSelectLoop(abiList);
}
// ......
// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if (caller != null) {
caller.run();
}
}
复制代码
在ZygoteServer对象初始化之后,会调用其runSelectLoop函数,并返回一个Runnable对象,然后运行它
在runSelectLoop函数中,会启动一个while无限循环,等待Socket连接
Runnable runSelectLoop(String abiList) {
// ......
while (true) {
// ......
int pollReturnValue;
try {
// 遍历轮询所有为pollFDs
pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
}
// .......
{
boolean usapPoolFDRead = false;
while (--pollIndex >= 0) {
// ......
// 当此时的pollIndex为0的时候,表明ZygoteServer启动后,有一个客户端来连接
if (pollIndex == 0) {
// 收到客户端连接请求,调用acceptCommandPeer函数初始化一个ZygoteConnection对象
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
socketFDs.add(newPeer.getFileDescriptor());
// 当前已经至少有一个ZygoteConnection连接建立完成
} else if (pollIndex < usapPoolEventFDIndex) {
// ......
try {
// 获取对应的ZygoteConnection对象,并调用其processOneCommand函数
ZygoteConnection connection = peers.get(pollIndex);
final Runnable command = connection.processOneCommand(this);
log("runSelectLoop : mIsForkChild = " + mIsForkChild);
// TODO (chriswailes): Is this extra check necessary?
if (mIsForkChild) {
// We're in the child. We should always have a command to run at
// this stage if processOneCommand hasn't called "exec".
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
}
}
// ......
}
}
// ......
}
// ......
}
}
复制代码
由上述代码可知,当ZygoteServer初始化后,调用runSelectLoop函数的时候,会启动一个while无限循环,当收到客户端连接请求后,此时通过调用acceptCommandPeer函数,初始化建立链路ZygoteConnection
当收到消息请求时,由于此时的peers中包含有一个ZygoteConnection链接,因此会获取该链接,并调用其processOneCommand函数,并返回一个线程,最终在ZygoteInit.main函数中调用该线程的run函数
亦即
建立一个ZygoteConnection链接
private ZygoteConnection acceptCommandPeer(String abiList) {
// ......
return createNewConnection(mZygoteSocket.accept(), abiList);
}
protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
throws IOException {
return new ZygoteConnection(socket, abiList);
}
复制代码
也就是说在ZygoteServer中初始化一个ZygoteConnection对象
运行该ZygoteConnection.processOneCommand函数
Runnable processOneCommand(ZygoteServer zygoteServer) {
String[] args;
// ......
// 读取zygote socket传递过来的参数数据
args = Zygote.readArgumentList(mSocketReader);
// ......
// 转化为能够识别的参数数组
ZygoteArguments parsedArgs = new ZygoteArguments(args);
// ...... 参数配置
// 调用Zygote的forkAndSpecialize函数
pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp,
parsedArgs.mPkgDataInfoList, parsedArgs.mWhitelistedDataInfoList,
parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs);
// ......
return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
// ......
}
复制代码
显然,这段代码,通过Zygote进程fork了一个Launcher应用进程,Zygote.forkAndSpecialize最终会调用Native层的fork函数,在内核进程中fork一个Launcher应用进程 此后经过一系列的操作后,最终会调用ZygoteConnection.handleChildProc函数
private Runnable handleChildProc(ZygoteArguments parsedArgs,
FileDescriptor pipeFd, boolean isZygote) {
// ......
// 关闭当前的SOCKET链接
closeSocket();
// 设置进程名称
Zygote.setAppProcessName(parsedArgs, TAG);
//......
// 通过ZygoteInit对象的zygoteInit函数
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mDisabledCompatChanges,
parsedArgs.mRemainingArgs, null /* classLoader */);
// ......
}
public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader) {
// ......
return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
classLoader);
}
protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader) {
// ......
return findStaticMain(args.startClass, args.startArgs, classLoader);
}
protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class<?> cl;
try {
// 找到对应的Class
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
// 查找对应Class中的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);
}
// ......
// 最后返回MethodAndArgsCaller对象
return new MethodAndArgsCaller(m, argv);
}
复制代码
从上面的流程可知,最后会初始化一个MethodAndArgsCaller对象并返回,从该对象的类图结构
classDiagram
Runnable <|-- MethodAndArgsCaller : 实现
<<interface>>Runnable
RuntimeInit *-- MethodAndArgsCaller : 内部类
返回的是一个实现Runnable接口的对象
梳理一下上述流程,
- 在ZygoteInit的main函数中,初始化了一个ZygoteServer对象,
- 然后调用其runSelectLoop函数,在这个函数中,会将主线程中实现一个while无限循环,
- 在这个无限循环中,一直等待zygote socket的客户端链接,一旦收到客户端的链接请求,则通过acceptCommandPeer函数初始化一个ZygoteConnection链路,然后调用该链路的processOneCommand函数,
- 通过JNI函数在内核空间中fork一个应用进程,,并最终通过一系列进程调度操作,调用了ZygoteConnection的handleChildProc,并最终返回一个MethodAndArgsCaller对象, MethodAndArgsCaller对象是一个实现Runnable接口的对象
运行上述得到的MethodAndArgsCaller对象
再回到ZygoteInit的main函数中可以看到,runSelectLoop函数返回的MethodAndArgsCaller不为null,则运行这个Runnable接口线程
ZygoteInit.main
if (caller != null) {
caller.run();
}
static class MethodAndArgsCaller implements Runnable {
/** method to call */
private final Method mMethod;
/** argument array */
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
public void run() {
// ......
mMethod.invoke(null, new Object[] { mArgs });
// ......
}
}
复制代码
根据此前的分析,此处的MethodAndArgsCaller的mMethod参数对应的是android.os.ActivityThread类的main函数,然后通过反射调用这个函数
public static void main(String[] args) {
// ......
Environment.initForCurrentUser();
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
// Call per-process mainline module initialization.
initializeMainlineModules();
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// ......
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
复制代码
最终在ActivityThread对象中启动对应的应用的具体Activity,这个我们等后续,再行更新