进程是如何启动的?
Android中进程的启动是被动的,当其他进程调用其他组件(四大组件)的时候,如果发现该组件所在的进程还没有启动,就会先向Zygote进程请求启动新的进程,再进行后续组件的启动。
所以进程启动的流程是:App -> AMS -> Zygote -> 新App
image- App发起进程:当从桌面启动应用,则发起进程便是Launcher所在进程;当从某App内启动远程进程,则发送进程便是该App所在进程。发起进程先通过binder发送消息给system_server进程;
- system_server进程:调用Process.start()方法,通过socket向zygote进程发送创建新进程的请求;
- zygote进程:在执行ZygoteInit.main()后便进入runSelectLoop()循环体内,当有客户端连接时便会执行ZygoteConnection.runOnce()方法,再经过层层调用后fork出新的应用进程;
- 新进程:执行handleChildProc方法,最后调用ActivityThread.main()方法。
因为第一步发起的途径有很多startActivity、startService,这些后面单独介绍,本章先从system_server进程调用Process.start()方法开始。
Process.start()流程
1.Process.start()
public static ProcessStartResult start(@NonNull final String processClass,
@Nullable final String niceName,
int uid, int gid, @Nullable int[] gids,
... ...
) {
return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
/*useUsapPool=*/ true, zygoteArgs);
}
接着会调用到startViaZygote()方法,可知这里要和Zygote通讯了;
private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
@Nullable final String niceName,
final int uid, final int gid,
@Nullable final int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
... ...)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
argsForZygote.add("--runtime-flags=" + runtimeFlags);
if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
argsForZygote.add("--mount-external-default");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
argsForZygote.add("--mount-external-read");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
argsForZygote.add("--mount-external-write");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
argsForZygote.add("--mount-external-full");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
argsForZygote.add("--mount-external-installer");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
argsForZygote.add("--mount-external-legacy");
}
... ...
synchronized(mLock) {
// The USAP pool can not be used if the application will not use the systems graphics
// driver. If that driver is requested use the Zygote application start path.
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
useUsapPool,
argsForZygote);
}
}
该方法主要是准备参数,openZygoteSocketIfNeeded()方法会连接Zygote暴露的本地socket服务,最后调用zygoteSendArgsAndGetResult()将准备好的创建请求参数发出,最终调用attemptZygoteSendArgsAndGetResult()完成发送和读取:
private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(
ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
try {
final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
zygoteWriter.write(msgStr);
zygoteWriter.flush();
// Always read the entire result from the input stream to avoid leaving
// bytes in the stream for future process starts to accidentally stumble
// upon.
Process.ProcessStartResult result = new Process.ProcessStartResult();
result.pid = zygoteInputStream.readInt();
result.usingWrapper = zygoteInputStream.readBoolean();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
} catch (IOException ex) {
zygoteState.close();
Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
+ ex.toString());
throw new ZygoteStartFailedEx(ex);
}
}
到此Process的工作就做完了,接下来看看Zygote服务端是怎么处理的。
Zygote创建进程的流程
我们知道Zygote进程创建后会通过jni调用启动ZygoteInit.java的main()方法,在main()方法里面会做如下事情:
1.预加载:preloadClasses()和preloadResources()
2.forkSystemServer,最终会调用SystemServer.java的main()方法;
3.创建ZygoteService,进入runSelectLoop;
这里的第三步就循环监听socket请求:
Runnable runSelectLoop(String abiList) {
//循环
while (true) {
... ...
try {
//监听请求,阻塞
Os.poll(pollFDs, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
boolean usapPoolFDRead = false;
while (--pollIndex >= 0) {
if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
continue;
}
if (pollIndex == 0) {
// Zygote server socket
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
socketFDs.add(newPeer.getFileDescriptor());
} else if (pollIndex < usapPoolEventFDIndex) {
// 接收到新的请求
try {
ZygoteConnection connection = peers.get(pollIndex);
//请求处理
final Runnable command = connection.processOneCommand(this);
if (mIsForkChild) {
//fork出来的子进程处理
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
} else {
//父进程处理
if (command != null) {
throw new IllegalStateException("command != null");
}
// We don't know whether the remote side of the socket was closed or
// not until we attempt to read from it from processOneCommand. This
// shows up as a regular POLLIN event in our regular processing loop.
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(pollIndex);
socketFDs.remove(pollIndex);
}
}
} catch (Exception e) {
...
} finally {
mIsForkChild = false;
}
}
}
}
}
从以上代码可以知道,当有新的请求到达的时候,会创建ZygoteConnection,并调用processOneCommand方法来处理:
Runnable processOneCommand(ZygoteServer zygoteServer) {
String args[];
ZygoteArguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
args = Zygote.readArgumentList(mSocketReader);
// TODO (chriswailes): Remove this and add an assert.
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
throw new IllegalStateException("IOException on command socket", ex);
}
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.mTargetSdkVersion);
try {
if (pid == 0) {
// in child
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.mStartChildZygote);
} else {
// In the parent. A pid < 0 indicates a failure and will be handled in
// handleParentProc.
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, descriptors, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
可以看到会调用Zygote.forkAndSpecialize()方法进行fork操作,该方法会调用native方法进行fork,然后返回pid,根据pid分别进入不同的处理:
- pid == 0: 子进程,调用handleChildProc();
- pid > 0:父进程,调用handleParentProc();
我们先看看handleChildProc会做什么?
private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd, boolean isZygote) {
closeSocket();
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mRemainingArgs, null /* classLoader */);
}
该方法主要就是关闭socket,因为新创建的进程是不需要zygote的服务来,然后调用ZygoteInit.zygoteInit();
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit(); //环境初始化
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
这里主要有三个步骤:
- RuntimeInit.commonInit():做一些通用的初始化;
- ZygoteInit.nativeZygoteInit():调用native方法开启binder服务;
- RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader):反射调用ActivityThread.main()方法。
到这里新的App进程就创建起来了。
总结
我们总结一下一个app进程的创建主要的流程:
1.调用AMS进行组件调用(startActivity、startService);
2.如果目标组件的进程未启动,则调用Process.start()向Zygote进程请求fork进程;
3.进程fork成功后会执行ActivityThread的main()方法,之后会调用IActivityManager.attachApplication(IApplicationThread)方法来告诉AMS新的进程已经启动了;
4.AMS接收到attachApplication请求后,就会继续步骤1的操作,进行组件启动;
本章只介绍到了1,2步骤,接下来会继续分析进程创建成功之后的操作。
网友评论