- A+
进程创建前
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); } }
start函数里面没有做太多的事情,直接交给了startViaZygote
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-args, --setuid=, --setgid=, // and --setgroups= must go first 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"); } if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) { argsForZygote.add("--enable-safemode"); } .... argsForZygote.add(processClass); if (extraArgs != null) { for (String arg : extraArgs) { argsForZygote.add(arg); } } return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote); } }
startViaZygote 函数前面都是对参数的整理。
后面交给了zygoteSendArgsAndGetResult。
但是这里我们需要注意的这边 openZygoteSocketIfNeeded 会打开一个socket,用于和zygote通讯,这个zygote之所以要一个abi参数因为在64位系统中有两个zygote进程。
root 264 1 1173156 127704 0 0000000000 S zygote64 root 265 1 934112 114496 0 0000000000 S zygote
就分别通讯的意思。
private static ProcessStartResult zygoteSendArgsAndGetResult( ZygoteState zygoteState, ArrayList<String> args) throws ZygoteStartFailedEx { try { int sz = args.size(); for (int i = 0; i < sz; i++) { if (args.get(i).indexOf('\n') >= 0) { throw new ZygoteStartFailedEx("embedded newlines not allowed"); } } 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(); ProcessStartResult result = new ProcessStartResult(); result.pid = inputStream.readInt(); result.usingWrapper = inputStream.readBoolean(); if (result.pid < 0) { throw new ZygoteStartFailedEx("fork() failed"); } return result; } catch (IOException ex) { zygoteState.close(); throw new ZygoteStartFailedEx(ex); } }
上一步拿到了zygoteState 现在进行通讯,首先进行的参数的校验,如果没有问题就通过一个一个参数write传输过去给zygote。
zygote拿到这些参数就会给你创建好需要的进程。
然后返回结果通过read读取出来。
那么zygote那边是怎么创建进程呢?我们来看下zygote那边的工作。
进程的创建
zygote循环
zygoteInit.main()函数是zygote启动的时候会执行的函数,关于zygote启动这里不在详细解析。
public static void main(String argv[]) { try { runSelectLoop(abiList); } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { closeServerSocket(); throw ex; } }
在main函数中会调用。runSelectLoop开启socket等待。
我们这里留意下这MethodAndArgsCaller异常。
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller { ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>(); ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); fds.add(sServerSocket.getFileDescriptor()); peers.add(null); while (true) { StructPollfd[] pollFds = new StructPollfd[fds.size()]; for (int i = 0; i < pollFds.length; ++i) { pollFds[i] = new StructPollfd(); pollFds[i].fd = fds.get(i); pollFds[i].events = (short) POLLIN; } try { Os.poll(pollFds, -1); } catch (ErrnoException ex) { throw new RuntimeException("poll failed", ex); } 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(); if (done) { peers.remove(i); fds.remove(i); } } } } }
zygote起来以后会一直在这边循环等待,等待你们连接我并把需要创建进程的参数传输给我。有连接过来了,就会执行runOnce函数。
runOnce
boolean runOnce() throws ZygoteInit.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, parsedArgs.instructionSet, parsedArgs.appDataDir); } catch (ErrnoException ex) { logAndPrintError(newStderr, "Exception creating pipe", ex); } catch (IllegalArgumentException ex) { logAndPrintError(newStderr, "Invalid zygote arguments", ex); } catch (ZygoteSecurityException ex) { logAndPrintError(newStderr, "Zygote security policy prevents request: ", ex); } try { if (pid == 0) { handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); // should never get here, the child is expected to either // throw ZygoteInit.MethodAndArgsCaller or exec(). return true; } else { return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); } } finally { IoUtils.closeQuietly(childPipeFd); IoUtils.closeQuietly(serverPipeFd); } }
这里关键的地方就是forkAndSpecialize 前面都是收集参数等待。
后forkAndSpecialize fork进程后,父进程和紫禁城分道扬镳。----这个是linux进程创建的知识了
接下来我们要分开两条不同关注点去看进程的创建了
--- forkAndSpecialize 会调用linux的fork系统调用创建进程,创建后我们关注它的一些环境的建立。
--- handleChildProc 进程创建后回去加载app的入口也就是ActivityThread。我们关注它是怎去加载的。
如果是单单看应用的启动,往应用层去理解呢,其实不太需要知道fork流程,如果想更深入了解系统的运行机制,可以一起来看下forkAndSpecialize到底做来什么东西。
进程的fork
上面讲到forkAndSpecialize 函数,我们这节的目的,看下forkAndSpecialize是怎么到底层调用linux的fork系统调用,从而开辟一个进程的。
要了解fork系统调用和运用的需要去了解linux的应用开发。这样才比较好了解进程的启动,在linux里面为什么用一个fork就创建了一个进程。
这个是需要一个基础知识的。
public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, String instructionSet, String appDataDir) { ... int pid = nativeForkAndSpecialize( uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, instructionSet, appDataDir); ... return pid; } native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int debugFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, String instructionSet, String appDataDir);
我们来看到forkAndSpecialize 什么都没有做直接交给了nativeForkAndSpecialize,而nativeForkAndSpecialize是一个jni底层的函数。
这个函数的实现在com_android_internal_os_Zygote.cpp (frameworks\base\core\jni)
static const JNINativeMethod gMethods[] = { { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I", (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
在这个com_android_internal_os_Zygote.cpp 文件里面,我们看到它的jni实现是com_android_internal_os_Zygote_nativeForkAndSpecialize
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint debug_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring se_name, jintArray fdsToClose, jstring instructionSet, jstring appDataDir) { jlong capabilities = 0; return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags, rlimits, capabilities, capabilities, mount_external, se_info, se_name, false, fdsToClose, instructionSet, appDataDir); }
com_android_internal_os_Zygote_nativeForkAndSpecialize 这个函数也没有做太多的事情,直接交给了ForkAndSpecializeCommon。
static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids, jint debug_flags, jobjectArray javaRlimits, jlong permittedCapabilities, jlong effectiveCapabilities, jint mount_external, jstring java_se_info, jstring java_se_name, bool is_system_server, jintArray fdsToClose, jstring instructionSet, jstring dataDir) { SetSigChldHandler(); ... pid_t pid = fork(); if (pid == 0) { .. if (!is_system_server) { int rc = createProcessGroup(uid, getpid()); if (rc != 0) { if (rc == -EROFS) { ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?"); } else { ALOGE("createProcessGroup(%d, %d) failed: %s", uid, pid, strerror(-rc)); } } } SetGids(env, javaGids); ... int rc = setresgid(gid, gid, gid); ... SetCapabilities(env, permittedCapabilities, effectiveCapabilities); SetSchedulerPolicy(env); ... rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str); ... if (se_info_c_str != NULL) { SetThreadName(se_name_c_str); } ... } else if (pid > 0) { ... } return pid; }
这个函数做的事情就有点多了,关键的是我们看到了fork()函数。
---在这个fork()函数之前做的是一些signal的设置
---fork()完成了以后兵分两路,子进程会去做很多gid 、scheduler 和 selinux等等的设置。
到这里我们就完整的看到了一个进程创建的过程。返回pid。
handleChildProc
现在进程出来了,我们需要一路返回,看看我们的进程会去做那些工作,是怎么走入到我们的apk代码里面的,主要是走到ActivityThread的过程。
我们回到handleChildProc,里面来。
private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller { if (parsedArgs.invokeWith != null) { WrapperInit.execApplication(parsedArgs.invokeWith, parsedArgs.niceName, parsedArgs.targetSdkVersion, VMRuntime.getCurrentInstructionSet(), pipeFd, parsedArgs.remainingArgs); } else { RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /* classLoader */); } } }
我们的进程已经创建完成来。handleChildProc是首先会调用的函数,而这个函数又调用来RuntimeInit.zygoteInit,为什么是讲这个函数而不去讲上面的函数?
我这里讲一个简单的linux知识。
linux进程创建也是一样的会直接fork,fork完成后如果你要加载代码一般是用execv系统调用去加载代码的,但是Android,使用的是java虚拟机。
所以,上面的流程是给一些本地进程走的。而java是通过Class进行类加载,来我们来一口气读完下面三个函数。
看下是怎么类加载的。
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { ... applicationInit(targetSdkVersion, argv, classLoader); } private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { ... VMRuntime.getRuntime().setTargetHeapUtilization(0.75f); VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); ... 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) { ... } Method m; try { m = cl.getMethod("main", new Class[] { String[].class }); } catch (NoSuchMethodException ex) { ... } ... throw new ZygoteInit.MethodAndArgsCaller(m, argv); }
这里我们关注下面流程:
1. 首先设置虚拟机的环境
2. 调用invokeStaticMain
3.在invokeStaticMain,我们找到这个类也就是ActivityThread类,这到这个类的Method,也就是main函数。
4.最后居然没有运行这个类而是抛出一个异常。很匪夷所思,根据反射调用的话,应该是要 m.invoke(null, arg);才对的。
那么它抛出这个异常是在哪里catch的呢?
还记得文章最前面我们说要关注的抛出的异常吗?
在前面zygote循环的时候我说要关注的异常。
public static void main(String argv[]) { try { runSelectLoop(abiList); } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { closeServerSocket(); throw ex; } }
他就是在这里catch了这个异常然后调用了这个异常的run函数。
public MethodAndArgsCaller(Method method, String[] args) { mMethod = method; mArgs = args; } public void run() { try { mMethod.invoke(null, new Object[] { mArgs }); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { ... throw new RuntimeException(ex); } }
然后再这里进行了invoke反射调用。
至于为什么要通过抛出异常的方法去做这个调用而不是直接调用,网上早有人给出了答案。这里就不多说。
到现在整个进程启动的流程就结束了。
ActivityThread类加载起来以后,会和ams交互,接下来会调用到你的activity的onCreate方法,onResume方法。
然后你的apk就完美运行了。
Android app启动流程:调用startProcessLocked的几种情况(1)
Android app启动流程:startProcessLocked函数分析(2)
Android app启动流程:Process.start(3)
Android app启动流程:startservice(4)
Android app启动流程:broadcast广播的注册(5)
Android app启动流程:广播的发送broadcastIntentLocked(6)
Android app启动流程:广播的发送scheduleBroadcastsLocked(7)
Android app启动流程:广播的发送processNextBroadcast(8)
Android app启动流程:关于FocusedStack的研究(9)
Android app启动流程:startActivityMayWait分析(10)
您可以选择一种方式赞助本站
支付宝扫一扫赞助
微信钱包扫描赞助
赏