Android Zygote进程是如何fork一个APP进程的
Posted mingfeng002
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Zygote进程是如何fork一个APP进程的相关的知识,希望对你有一定的参考价值。
进程创建流程
- 不管从桌面启动应用还是应用内启动其它应用,如果这个应用所在进程不存在的话,都需要发起进程通过Binder机制告诉system server进程的AMS
- system server进程的AMS调用Process.start()方法,通过socket向zygote进程发送创建新进程的请求
- 在zygote进程的ZygoteInit.main方法中,有一个runSelectLoop循环体,通过acceptCommandPeer方法获取链接过来的客户端,再通过runOnce方法去创建进程
- 新的进程执行handleChildProc方法,最后通过反射调用ActivityThread.main()方法,这样一个新的APP进程就创建完成了
APP启动第三方应用
startActivity
当你在桌面启动一个应用或者在一个APP内启动一个应用,本质都是一样的,因为android手机桌面其实就是一个APP(这点可参考Android之Activity启动流程源码深入解析),两种方式经过层层调用之后都会走到ActivityStackSupervisor.startSpecificActivityLocked方法,判断如果对方进程不存在,就需要去创建一个进程
startService
调用startService启动一个服务,该方法经过层层调用最终会走到ActiveServices.bringUpServiceLocked方法,如果判断对方进程不存在也会去创建一个新进程
sendBroadcast
调用sendBroadcast方法去发送一个广播,经过层层调用后走到BroadcastQueue.processNextBroadcast方法,也会判断BroadcastReceiver所在进程不存在就需要去创建进程
query
在ContentProvider的处理过程中,ContentResolver.query方法经过层层调用会走到ActivityManagerService.getContentProviderImpl方法,判断ContentProvider所在的进程不存在就会创建新进程
System Server请求创建进程
以下叙述中ActivityManagerService同意简称为AMS
以下源码基于API 24
上述四种途径最终都会走到如下方法
AMS.startProcessLocked
先来看ActivityManagerService的startProcessLocked
方法,这是最开始入口
private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) { //......省略代码 Process.ProcessStartResult startResult = Process.start(entryPoint, app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet, app.info.dataDir, entryPointArgs); //......省略代码 }
代码是在太长,我们只看关键的地方,Process.start
这个方法开始进行fork,ok那来看看它的内容,代码很长,可以直接看下面关于本段代码总结
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[] zygoteArgs) { try { return startViaZygote(processClass, niceName, uid, gid, gids, debugFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); throw new RuntimeException( "Starting VM process through Zygote failed", ex); } } private static 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[] extraArgs) throws ZygoteStartFailedEx { synchronized(Process.class) { ArrayList<String> argsForZygote = new ArrayList<String>(); // --runtime-init, --setuid=, --setgid=, // and --setgroups= must go first argsForZygote.add("--runtime-init"); argsForZygote.add("--setuid=" + uid); argsForZygote.add("--setgid=" + gid); if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) { argsForZygote.add("--enable-jni-logging"); } if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) { argsForZygote.add("--enable-safemode"); } if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) { argsForZygote.add("--enable-debugger"); } if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) { argsForZygote.add("--enable-checkjni"); } if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) { argsForZygote.add("--enable-assert"); } if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER) { argsForZygote.add("--mount-external-multiuser"); } else if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL) { argsForZygote.add("--mount-external-multiuser-all"); } argsForZygote.add("--target-sdk-version=" + targetSdkVersion); //TODO optionally enable debuger //argsForZygote.add("--enable-debugger"); // --setgroups is a comma-separated list if (gids != null && gids.length > 0) { StringBuilder sb = new StringBuilder(); sb.append("--setgroups="); int sz = gids.length; for (int i = 0; i < sz; i++) { if (i != 0) { sb.append(‘,‘); } sb.append(gids[i]); } argsForZygote.add(sb.toString()); } if (niceName != null) { argsForZygote.add("--nice-name=" + niceName); } if (seInfo != null) { argsForZygote.add("--seinfo=" + seInfo); } if (instructionSet != null) { argsForZygote.add("--instruction-set=" + instructionSet); } if (appDataDir != null) { argsForZygote.add("--app-data-dir=" + appDataDir); } argsForZygote.add(processClass); if (extraArgs != null) { for (String arg : extraArgs) { argsForZygote.add(arg); } } return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote); } }
上面的startViaZygote
方法,所做的事情是:把参数最终放到一个列表中,接着调用zygoteSendArgsAndGetResult
方法,该方法中的第一个参数是调用了openZygoteSocketIfNeeded(abi)
方法,那我们先来看下这方法的内容
rivate static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx { if (primaryZygoteState == null || primaryZygoteState.isClosed()) { try { primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET); } catch (IOException ioe) { throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe); } } //......省略代码 }
ZygoteState.connect(ZYGOTE_SOCKET)
接着看下这方法
/*与ZygoteInit的server socket建立链接通信*/ public static ZygoteState connect(String socketAddress) throws IOException { DataInputStream zygoteInputStream = null; BufferedWriter zygoteWriter = null; final LocalSocket zygoteSocket = new LocalSocket(); try { zygoteSocket.connect(new LocalSocketAddress(socketAddress, LocalSocketAddress.Namespace.RESERVED)); zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream()); zygoteWriter = new BufferedWriter(new OutputStreamWriter( zygoteSocket.getOutputStream()), 256); } catch (IOException ex) { try { zygoteSocket.close(); } catch (IOException ignore) { } throw ex; } String abiListString = getAbiList(zygoteWriter, zygoteInputStream); Log.i("Zygote", "Process: zygote socket opened, supported ABIS: " + abiListString); return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter, Arrays.asList(abiListString.split(","))); }
上面的代码其实就是与ZygoteInit
类中的ServerSocket建立连接,socket连接起来了,那就可以进行通信了。现在我们在返回到zygoteSendArgsAndGetResult
方法
private static ProcessStartResult zygoteSendArgsAndGetResult( ZygoteState zygoteState, ArrayList<String> args) throws ZygoteStartFailedEx { try { /** * See com.android.internal.os.ZygoteInit.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; writer.write(Integer.toString(args.size())); writer.newLine(); int sz = args.size(); for (int i = 0; i < sz; i++) { String arg = args.get(i); if (arg.indexOf(‘\n‘) >= 0) { throw new ZygoteStartFailedEx( "embedded newlines not allowed"); } writer.write(arg); writer.newLine(); } writer.flush(); // Should there be a timeout on this? ProcessStartResult result = new ProcessStartResult(); result.pid = inputStream.readInt(); /*pid小于0代表有问题,==0代表是子进程,》0代表是父进程*/ if (result.pid < 0) { throw new ZygoteStartFailedEx("fork() failed"); } result.usingWrapper = inputStream.readBoolean(); return result; } catch (IOException ex) { zygoteState.close(); throw new ZygoteStartFailedEx(ex); } }
代码也很简单,上面提到过client与server已经建立了socket连接,那这个方法,会把所有的参数通过socket发送到ZygoteInit
的ServerSocket,发送完毕后,就等待ServerSocket把结果返回
Zygote进程处理fork请求
上一节提到过,client发送的建立socket连接最终会在ZygoteInit
中创建一个ZygoteConnection
对象,收到client发送的fork请求,会调用ZygoteConnection
对象的runOnce
方法,因此来看这方法
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { //.......省略代码 pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet, parsedArgs.appDataDir); //......省略代码 try { /*子进程执行pid==0情况,父进程执行else情况*/ if (pid == 0) { /*子进程*/ // in child IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); // should never get here, the child is expected to either // throw ZygoteInit.MethodAndArgsCaller or exec(). return true; } else { // in parent...pid of < 0 means failure IoUtils.closeQuietly(childPipeFd); childPipeFd = null; /*Process中的io流监听的pid等信息都是通过下面的代码发出去的*/ return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); } } finally { IoUtils.closeQuietly(childPipeFd); IoUtils.closeQuietly(serverPipeFd); } }
Zygote.forkAndSpecialize
这个方法会调用native方法来fork app进程,fork成功后,子进程就复制了基本上父进程所有的数据等,这在本节开始的时候科普过这个知识,子进程fork出的pid==0,因此if(pid == 0){}else{}
这段代码就特别有意思了,pid==0是子进程执行,else是父进程执行,父进程执行的代码我就不贴了,它主要是把fork成功的pid返回给client端,这时候ActivityManagerService
的startProcessLocked
就可以继续执行。我们还是来看下子进程执行的代码,最终会执行
handleChildProc
方法private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller { //......省略代码 if (parsedArgs.runtimeInit) { if (parsedArgs.invokeWith != null) { WrapperInit.execApplication(parsedArgs.invokeWith, parsedArgs.niceName, parsedArgs.targetSdkVersion, pipeFd, parsedArgs.remainingArgs); } else { RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /* classLoader */); } } else { // ......省略代码 } }
从传递过来的参数可以定位最终调用了RuntimeInit.zygoteInit
方法,那就来看下
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote"); redirectLogStreams(); commonInit(); nativeZygoteInit(); applicationInit(targetSdkVersion, argv, classLoader); }
该方法我们只关注applicationInit(targetSdkVersion, argv, classLoader)
这个方法
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { // If the application calls System.exit(), terminate the process // immediately without running any shutdown hooks. It is not possible to // shutdown an Android application gracefully. Among other things, the // Android runtime shutdown hooks close the Binder driver, which can cause // leftover running threads to crash before the process actually exits. nativeSetExitWithoutCleanup(true); // We want to be fairly aggressive about heap utilization, to avoid // holding on to a lot of memory that isn‘t needed. 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()); // let the process exit return; } // Remaining arguments are passed to the start class‘s static main invokeStaticMain(args.startClass, args.startArgs, classLoader); } private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { Class<?> cl; try { cl = Class.forName(className, true, classLoader); } 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 }); } 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. */ throw new ZygoteInit.MethodAndArgsCaller(m, argv); }
最终我们关注invokeStaticMain
这个方法,该方法最终会抛出一个ZygoteInit.MethodAndArgsCaller(m, argv)
异常,这个异常会把ActivityThread
的main
方法反射出来。
还记得上一节ZygoteInit
的main
方法吗
public static void main(String argv[]){ try{ //.....省略代码 } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; } }
main
方法最终会把MethodAndArgsCaller
异常给捕获到,捕获到后其实最终就是调用ActivityThread
的main
方法
通过抛异常的方式来进行调用,主要目的是把当前线程的堆栈信息给置空
以上是关于Android Zygote进程是如何fork一个APP进程的的主要内容,如果未能解决你的问题,请参考以下文章
Framework学习高级视频--android系统init到Zygote的fork进程篇
Android 进阶——系统启动之Android进程造物者Zygote 进程启动详解
Android 进阶——系统启动之Android进程造物者Zygote 进程启动详解