应用程序的进程启动java
当咱们打开android手机的时候,不知道你是否想过app是如何启动的呢?android
接下来,我将从源码角度进行解析,固然,本文做为上篇,是介绍应用程序的进程启动过程,而不是应用程序的启动过程,他们的区别就是煮饭前要准备锅具,没有锅具就没法煮饭,本文就是准备锅具的,可是也不简单哦。c++
文章将从两个方面介绍,一个AMS发送请求,一个是Zygote接受请求。web
AMS就是Activity Manager System,管理Activity的,而Zygote就是建立进程的一个进程,因此AMS要想建立进程必须从Zygote那里进行申请,一系列的故事,就此展开。微信
从图中能够简略看出,首先AMS本身调用了本身的startProcessLocked
方法,会建立相应的用户id,用户id组,以及对应的应用程序进程的主线程名——android.app.ActivityThread
。app
private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
...
try {
int uid = app.uid;
int[] gids = null;
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
if (!app.isolated) {
int[] permGids = null;
if (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));
}
String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
if (requiredAbi == null) {
requiredAbi = Build.SUPPORTED_ABIS[0];
}
...
if (entryPoint == null) entryPoint = "android.app.ActivitThread";
...
if (hostingType.equals("webview_service")) {
...
} else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, entryPointArgs);
}
...
}
复制代码
这里面的start中有一个参数名为requireAbi
,在下面会改为abi
起到比对的重要做用。socket
startProcessLocked
方法内部会调用Process的start
方法,而这个start方法只干了一件事,就是调用ZygoteProcess
的start
方法。ide
ZygoteProcess
的做用在于保持与Zygote通讯的状态,在其start
方法中,会调用StartViaZygote
方法,这里的出现了下面很重要的abi。函数
public final Process.ProcessStartResult start(final String processClass, final String niceName, int uid, int gid, int[] gids, ... String abi, ... String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
...
}
复制代码
StartViaZygote
方法会维护一个名为argsForZygote
的列表,顾名思义,全部可以启动应用程序的进程的参数,都会保存在这里。而后这个列表做为一个参数,被传入到ZygoteSendArgsAndGetResult
方法中,这个方法也是在StartViaZygote
方法中被调用.另外要注意的是,openZygoteSocketIfNeeded
方法也是做为参数传入了ZygoteSendArgsAndGetResult
方法中。oop
private Process.ProcessStartResult startViaZygote(final String processClass, final String niceName, final int uid, final int gid, final int[] gids, ... String abi, ...) throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<String>();
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
...
synchronized(mLock) {
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
复制代码
ZygoteSendArgsAndGetResult
方法做用是将传入的参数,也就是argsForZygote
中保存的数据写入到ZygoteState
中,从图中咱们虽然将ZygoteState
和ZygoteProcess
作了并列处理,可是ZygoteState
是ZygoteProcess
的一个静态内部类,上面提到的ZygoteProcess
的做用在于保持与Zygote通讯的状态,其功能的完成就是在ZygoteState
中。
private static Process.ProcessStartResult zygoteSendArgsAndGetResult( ZygoteState zygoteState, ArrayList<String> args) throws ZygoteStartFailedEx {
try {
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();
...
result.pid = inputStream.readInt();
result.usingWrapper = inputStream.readBoolean();
...
}
复制代码
从上面的方法看出,ZygoteSendArgsAndGetResult
方法的第一个参数变成了ZygoteState
,也就是说,openZygoteSocketIfNeeded
方法的返回值是ZygoteState
。
openZygoteSocketIfNeeded
方法也处于ZygoteProcess
中,就写在StartViaZygote
下面,能够看到,在第6行与Zygote进程创建了链接。
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedE Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
primaryZygoteState = ZygoteState.connect(mSocket);//创建链接
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
}
//这里primaryZygoteState是链接主模式后返回的ZygoteState,比对其是否与须要的abi匹配
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
//若是主模式不成功,链接辅模式
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
}
//匹配辅模式的abi
if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
复制代码
为何第6行能够链接Zygote呢?由于Zygote是最早建立的进程,若是没有Zygote,咱们的应用程序的进程也无从谈起,而Zygote为了建立其余进程,他会设置一个Socket监听,就是经过这个Socket,完成与Zygote的链接。
而对于主模式和辅助模式,这里不细讲,就是有两次链接并匹配abi
的机会。
要匹配abi
的缘由在于,Zygote虽然能够fork本身不断建立进程,可是毕竟是有限的,并且须要资源,只有启动某个应用程序所必须的进程才有被建立的意义,这时候就在一开始的AMS中给设置一个abi
,若是与后来的Zygote匹配,证实是须要被建立的。
当匹配完成时,就会返回一个primaryZygoteState
,此时AMS发送请求这一流程就结束了,接下来,就是Zygote如何接受请求并建立应用程序的进程的过程了。
依然是时序图,甚至说,有了时序图,根本就不须要看后面的文章啦。
看起来比上一个图稍微复杂些,不过能够发现仍是颇有规律的,Zygote先到ZygoteServer
再回来,再到ZygoteConnection
,再回来……
因此,后面几个方法都在ZygoteInit
中被调用,并且时间前后就是图中所示。
在AMS发送请求完成后,Zygote会链接到一个ZygoteState
,而这个ZygoteState
在以前的ZygoteSendArgsAndGetResult
方法中被写入了argsForZygote
所保存的数据,这些数据就是请求的具体参数。
如今Zygote将会收到这些参数,并在ZygoteInit
中进行相应操做。
ZygoteInit
首先会执行其main方法。
public static void main(String argv[]) {
...
try {
...
//设置Socket监听
zygoteServer.registerServerSocket(socketName);
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
...
if (startSystemServer) {
startSystemServer(abiList, socketName, zygoteServer);//启动SystemServer进程
}
Log.i(TAG, "Accepting command socket connections");
zygoteServer.runSelectLoop(abiList);//等待AMS请求
zygoteServer.closeServerSocket();
...
}
复制代码
这里最后一个注释,就是一切都准备好了,只等AMS发来请求,如今咱们看看RunSelectLoop
方法是如何作的,猜想既然是等待,那确定有一个死循环while,这个函数就在ZygoteServer
之中。
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
...
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
//一个链接一个链接的运行
boolean done = peers.get(i).runOnce(this);
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
}
复制代码
果真有一个while(true),哈哈,奖励本身晚上早睡十分钟。
能够看到这里维护了一个ZygoteConnection
型的列表,每当链接不够时,就会增长,而后一个一个链接的进行执行,执行玩一个链接,就移除一个。
runOnce
方法的做用就是读取argsForZygote
所保存的数据,完成交接,这个方法显然,在ZygoteConnection
中。
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 {
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);
}
...
try {
if (pid == 0) {//当前逻辑运行在子程序中
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
return true;
}
...
}
}
复制代码
若是在18行处的pid返回值为0,那么恭喜,此时的子进程已经建立完成,各类id和参数都传进去了,此时就会调用handleChildProc
方法来处理出现的应用程序的进程(仍是要提醒,本文建立的是应用程序的进程,而非应用程序自己)。
handleChildProc
方法回调了ZygoteInit
中的zygoteInit
方法,注意,这里的z是小写!
private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) throws Zygote.MethodAndArgsCaller {
...
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
} else {
ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
复制代码
如今咱们回到ZygoteInit
中,看看zygoteInit
是怎么写的。
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");
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
复制代码
注意到这个方法是一个静态的final方法,在12行代码处,会执行RuntimeInit
的applicationInit
方法。
protected static void applicationInit(int targetSdkVersion, String[] throws Zygote.MethodAndArgsCaller { ... final Arguments args; try { args = new Arguments(argv);
} catch (IllegalArgumentException ex) {
Slog.e(TAG, ex.getMessage());
// let the process exit
return;
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}
复制代码
一样在最后一行,调用了invokeStaticMain
方法,这里传入了三个参数,第一个参数args.startClass
就是本文一开始说的那个主线程的名字android.app.MainThread
。
终于咱们到了最后一站!如今咱们进入invokeStaticMain
方法。
private static void invokeStaticMain(String className, String[] argv, ClassLoader throws Zygote.MethodAndArgsCaller { Class<?> cl; try { cl = Class.forName(className, true, classLoader);//反射获取MainThread
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });//得到main
} 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);
...
throw new Zygote.MethodAndArgsCaller(m, argv);
}
复制代码
这里的className就是咱们刚刚提到的args.startClass
,也就是主线程名字,经过第6行的反射获取到对应的类,命名为c1,而后再经过15行代码获取主方法main,并将main传入到MethodAndArgsCaller
方法中,当作异常抛出。
为何这里要用抛出异常的方法呢?
联想到这是最后一步,抛出异常的方式将会清除设置过程当中须要的堆栈帧,仅仅留下一个main方法,使得main方法看起来像一个入口方法,毕竟,前面那么多的工做,那么多类的流血牺牲,最后都是为了成就他。当他出现时,前面的东西,也就没有必要存在了。
如今异常抛出了,谁来接受呢?固然,是main了,main位于ZygoteInit
中。
public static void main(String argv[]) {
...
zygoteServer.closeServerSocket();
} catch (Zygote.MethodAndArgsCaller caller) {
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
zygoteServer.closeServerSocket();
throw ex;
}
}
复制代码
能够看到,当出现了一个MethodAndArgsCaller
型的异常的时候,main会捕捉到,而且执行他的run方法,这个run方法在MethodAndArgsCaller
中,他是一个静态类。
public static class MethodAndArgsCaller extends Exception implements Runnable {
...
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
...
}
}
}
复制代码
调用了invoke
方法后,ActivityThread里面的main方法就会被动态调用,应用程序的进程就进入了这一main方法中。
通过上面的种种操做,咱们建立了应用程序的进程而且运行了ActivityThread。
简单来讲就是要想建立应用程序的进程,须要AMS发送请求,传入主线程名,这一请求必须符合Zygote的abi
,而且将请求参数写在ZygoteState
中。
而后Zygote读取参数,fork自身去生成新的进程,若是返回的pid为0,那么就完成了应用程序的进程的建立。
而后经过反射将主线程名转换为主线程的类,得到其main方法,经过抛出一个异常清除掉以前的堆栈帧,在main方法里面接受这个异常,并执行run方法以激活main方法,使得应用程序的进程进入到main方法中得以运行。
写了一早上,呼~,准备吃饭啦,还有什么不懂的能够评论区提问哦。
本文取材自《Android进阶解密》,资源在微信公众号【小松漫步】,一块儿交流学习吧。