3.2.4启动Android系统服务——startSystemServer()

接下来就是启动Android的重头戏了,此时ZygoteInit的main()函数会调用startSystemServer(),该函数用于启动整个Android系统的系统服务。其大体做法是先fork一个子进程,然后在子进程中做一些初始化动作,继而执行SystemServer类的main()静态函数。需要注意的是,startSystemServer()并不是在函数体内直接调用Java类的main()函数的,而是通过抛异常的方式,在startSystemServer()之外加以处理的。

startSystemServer()的代码如下:

  1. private static boolean startSystemServer()
  2. throws MethodAndArgsCaller, RuntimeException
  3. {
  4. . . . . . .
  5. /* Hardcoded command line to start the system server */
  6. String args[] = {
  7. "--setuid=1000",
  8. "--setgid=1000",
  9. "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,
  10. 3001,3002,3003,3006,3007",
  11. "--capabilities=" + capabilities + "," + capabilities,
  12. "--runtime-init",
  13. "--nice-name=system_server",
  14. "com.android.server.SystemServer",
  15. };
  16. ZygoteConnection.Arguments parsedArgs = null;
  17. int pid;
  18. try {
  19. parsedArgs = new ZygoteConnection.Arguments(args);
  20. ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
  21. ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
  22. // fork出系统服务对应的进程
  23. pid = Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,
  24. parsedArgs.gids, parsedArgs.debugFlags, null,
  25. parsedArgs.permittedCapabilities,
  26. parsedArgs.effectiveCapabilities);
  27. } catch (IllegalArgumentException ex) {
  28. throw new RuntimeException(ex);
  29. }
  30. // 对新fork出的系统进程,执行handleSystemServerProcess()
  31. if (pid == 0) {
  32. handleSystemServerProcess(parsedArgs);
  33. }
  34. return true;
  35. }
 
 args[]中的字符串  对应
 "--setuid=1000"  parsedArgs.uid
 "--setgid=1000"  parsedArgs.gid

"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,
1009,1010,1018,1021,1032,3001,3002,3003,3006,3007"

 parsedArgs.gids
 "--capabilities=" + capabilities + "," + capabilities  capabilitiesSpecified = true;
permittedCapabilities = Long.decode(capStrings[0]);
effectiveCapabilites = Long.decode(capString[1]);
 "--runtime-init"  parsedArgs.runtimeInit设为true
 "--nice-name=system_server"  parsedArgs.niceName
 "com.android.server.SystemServer"  parsedArgs.remainingArgs

3.2.4.1Zygote.forkSystemServer()

Zygote.forkSystemServer()的代码如下:
【libcore/dalvik/src/main/java/dalvik/system/Zygote.java】

  1. public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
  2. int[][] rlimits, long permittedCapabilities, long effectiveCapabilities)
  3. {
  4. preFork();
  5. int pid = nativeForkSystemServer(uid, gid, gids, debugFlags, rlimits,
  6. permittedCapabilities, effectiveCapabilities);
  7. postFork();
  8. return pid;
  9. }
其中的nativeForkSystemServer()是个native成员函数,其对应的C++层函数为Dalvik_dalvik_system_Zygote_forkSystemServer()。

【dalvik/vm/native/dalvik_system_Zygote.cpp】

  1. const DalvikNativeMethod dvm_dalvik_system_Zygote[] = {
  2. { "nativeFork", "()I",
  3. Dalvik_dalvik_system_Zygote_fork },
  4. { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;)I",
  5. Dalvik_dalvik_system_Zygote_forkAndSpecialize },
  6. { "nativeForkSystemServer", "(II[II[[IJJ)I",
  7. Dalvik_dalvik_system_Zygote_forkSystemServer },
  8. { NULL, NULL, NULL },
  9. };
 
  1. static void Dalvik_dalvik_system_Zygote_forkSystemServer(
  2. const u4* args, JValue* pResult)
  3. {
  4. pid_t pid;
  5. pid = forkAndSpecializeCommon(args, true);
  6. if (pid > 0) {
  7. int status;
  8. ALOGI("System server process %d has been created", pid);
  9. gDvm.systemServerPid = pid;
  10. if (waitpid(pid, &status, WNOHANG) == pid) {
  11. ALOGE("System server process %d has died. Restarting Zygote!", pid);
  12. kill(getpid(), SIGKILL);
  13. }
  14. }
  15. RETURN_INT(pid);
  16. }
forkAndSpecializeCommon()内部其实会调用fork(),而后设置gid、uid等信息。

3.2.4.2SystemServer的handleSystemServerProgress()函数

接着,startSystemServer()会在新fork出的子进程中调用handleSystemServerProgress(),让这个新进程成为真正的系统进程(SystemServer进程)。

  1. // 对新fork出的系统进程,执行handleSystemServerProcess()
  2. if (pid == 0) {
  3. handleSystemServerProcess(parsedArgs);
  4. }
注意,调用handleSystemServerProcess()时,程序是运行在新fork出的进程中的。handleSystemServerProcess()的代码如下:

【frameworks/base/core/java/com/android/internal/os/ZygoteInit.java】

  1. private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs)
  2. throws ZygoteInit.MethodAndArgsCaller
  3. {
  4. closeServerSocket();
  5. Libcore.os.umask(S_IRWXG | S_IRWXO);
  6. if (parsedArgs.niceName != null) {
  7. Process.setArgV0(parsedArgs.niceName);  // niceName就是”system_server”
  8. }
  9. if (parsedArgs.invokeWith != null) {
  10. WrapperInit.execApplication(parsedArgs.invokeWith,
  11. parsedArgs.niceName, parsedArgs.targetSdkVersion,
  12. null, parsedArgs.remainingArgs);
  13. } else {
  14. // 此时的remainingArgs就是”com.android.server.SystemServer”
  15. RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
  16. }
  17. }
 
3.2.4.2.1closeServerSocket()

因为当前已经不是运行在zygote进程里了,所以zygote里的那个监听socket就应该关闭了。这就是closeServerSocket()的意义,其代码如下:

  1. static void closeServerSocket()
  2. {
  3. try {
  4. if (sServerSocket != null) {
  5. FileDescriptor fd = sServerSocket.getFileDescriptor();
  6. sServerSocket.close();
  7. if (fd != null) {
  8. Libcore.os.close(fd);
  9. }
  10. }
  11. } catch (IOException ex) {
  12. Log.e(TAG, "Zygote:  error closing sockets", ex);
  13. } catch (libcore.io.ErrnoException ex) {
  14. Log.e(TAG, "Zygote:  error closing descriptor", ex);
  15. }
  16. sServerSocket = null;
  17. }
在handleSystemServerProcess()函数里,parsedArgs.niceName就是“system_server”,而且因为parsedArgs.invokeWith没有指定,所以其值为null,于是程序会走到RuntimeInit.zygoteInit()。
3.2.4.2.2RuntimeInit.zygoteInit()

RuntimeInit.zygoteInit()的代码如下:
【frameworks/base/core/java/com/android/internal/os/RuntimeInit.java】

  1. public static final void zygoteInit(int targetSdkVersion, String[] argv)
  2. throws ZygoteInit.MethodAndArgsCaller
  3. {
  4. if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
  5. redirectLogStreams();
  6. commonInit();
  7. nativeZygoteInit();
  8. applicationInit(targetSdkVersion, argv);
  9. }
 
3.2.4.2.2.1.调用redirectLogStreams()

首先,在新fork出的系统进程里,需要重新定向系统输出流。

  1. public static void redirectLogStreams()
  2. {
  3. System.out.close();
  4. System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
  5. System.err.close();
  6. System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));
  7. }
 
3.2.4.2.2.2.调用commonInit()
  1. private static final void commonInit()
  2. {
  3. . . . . . .
  4. Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
  5. TimezoneGetter.setInstance(new TimezoneGetter()
  6. . . . . . .
  7. . . . . . .
  8. String trace = SystemProperties.get("ro.kernel.android.tracing");
  9. . . . . . .
  10. initialized = true;
  11. }
当前正处于系统进程的主线程中,可以调用Thread.setDefaultUncaughtExceptionHandler()来设置一个默认的异常处理器,处理程序中的未捕获异常。其他的初始化动作,我们暂不深究。
3.2.4.2.2.3.调用nativeZygoteInit()

接下来调用的nativeZygoteInit()是个JNI函数,在AndroidRuntime.cpp文件中可以看到:
【frameworks/base/core/jni/AndroidRuntime.cpp】

  1. static JNINativeMethod gMethods[] = {
  2. { "nativeFinishInit", "()V",
  3. (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
  4. { "nativeZygoteInit", "()V",
  5. (void*) com_android_internal_os_RuntimeInit_nativeZygoteInit },
  6. { "nativeSetExitWithoutCleanup", "(Z)V",
  7. (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
  8. };
nativeZygoteInit()对应的本地函数为com_android_internal_os_RuntimeInit_nativeZygoteInit()。
  1. static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
  2. {
  3. gCurRuntime->onZygoteInit();
  4. }
gCurRuntime是C++层的AndroidRuntime类的静态变量。在AndroidRuntime构造之时,

gCurRuntime = this。不过实际调用的onZygoteInit()应该是AndroidRuntime的子类AppRuntime的:
【frameworks/base/cmds/app_process/App_main.cpp】

  1. class AppRuntime : public AndroidRuntime
  2. {
  3. . . . . . .
  4. virtual void onZygoteInit()
  5. {
  6. // Re-enable tracing now that we're no longer in Zygote.
  7. atrace_set_tracing_enabled(true);
  8. sp<ProcessState> proc = ProcessState::self();
  9. ALOGV("App process: starting thread pool.\n");
  10. proc->startThreadPool();
  11. }
里面构造了进程的ProcessState全局对象,而且启动了线程池。

ProcessState对象是典型的单例模式,它的self()函数如下:

  1. sp<ProcessState> ProcessState::self()
  2. {
  3. Mutex::Autolock _l(gProcessMutex);
  4. if (gProcess != NULL) {
  5. return gProcess;
  6. }
  7. gProcess = new ProcessState;
  8. return gProcess;
  9. }
ProcessState对于Binder通信机制而言非常重要,现在system server进程的PrecessState算是初始化完毕了。

我们整理一下思路,画一张startSystemServer()的调用关系图:

接下来我们来讲上图中zygoteInit()调用的最后一行:applicationInit()。

3.2.4.2.2.4.调用applicationInit()

applicationInit()函数的代码如下:
【frameworks/base/core/java/com/android/internal/os/RuntimeInit.java】

  1. private static void applicationInit(int targetSdkVersion, String[] argv)
  2. throws ZygoteInit.MethodAndArgsCaller
  3. {
  4. nativeSetExitWithoutCleanup(true);
  5. VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
  6. VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
  7. final Arguments args;
  8. try {
  9. args = new Arguments(argv);
  10. } catch (IllegalArgumentException ex) {
  11. Slog.e(TAG, ex.getMessage());
  12. return;
  13. }
  14. invokeStaticMain(args.startClass, args.startArgs);
  15. }

其中的invokeStaticMain()一句最为关键,它承担向外抛出“特殊异常”的作用。我们先画一张startSystemServer()的调用关系图:

看到了吧,最后一步抛出了异常。这相当于一个“特殊的goto语句”!上面的cl = Class.forName(className)一句,其实加载的就是SystemServer类。这个类名是从前文的parsedArgs.remainingArgs得来的,其值就是“com.android.server.SystemServer”。此处抛出的异常,会被本进程的catch语句接住,在那里才会执行SystemServer类的main()函数。示意图如下:

如上图所示,新fork出的SystemServer子进程直接跳过了中间那句runSelectLoop(),径直跳转到caller.run()一步了。

当然,父进程Zygote在fork动作后,会退出startSystemServer()函数,并走到runSelectLoop(),从而进入一种循环监听状态,每当Activity Manager Service向它发出“启动新应用进程”的命令时,它又会fork一个子进程,并在子进程里抛出一个异常,这样子进程还是会跳转到catch一句。

我们可以把上面的示意图再丰富一下:

还有一点需要说明一下,fork出的SystemServer进程在跳转到catch语句后,会执行SystemServer类的main()函数,而其他情况下,fork出的应用进程在跳转的catch语句后,则会执行ActivityThread类的main()函数。这个ActivityThread对于应用程序而言非常重要,但因为和本篇主题关系不大,我们就不在这里展开讲了。

3.2.4.3 SystemServer的main()函数

前文我们已经看到了,startSystemServer()创建的新进程在执行完applicationInit()之后,会抛出一个异常,并由新fork出的SystemServer子进程的catch语句接住,继而执行SystemServer类的main()函数。

那么SystemServer的main()函数又在做什么事情呢?其调用关系图如下:

在Android4.4版本中,ServerThread已经不再继承于Thread了,它现在只是个辅助类,其命名还残留有旧代码的味道。在以前的Android版本中,ServerThread的确继承于Thread,而且在线程的run()成员函数里,做着类似addService、systemReady的工作。

因为本文主要是阐述zygote进程的,所以我们就不在这里继续细说system server进程啦,有兴趣的同学可以继续研究。我们还是回过头继续说zygote里的动作吧。

3.2.5监听zygote socket

3.2.5.1runSelectLoop()

ZygoteInit的main()函数在调用完startSystemServer()之后,会进一步走到runSelectLoop()。runSelectInit()的代码如下:
【frameworks/base/core/java/com/android/internal/os/ZygoteInit.java】

  1. private static void runSelectLoop() throws MethodAndArgsCaller
  2. {
  3. ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
  4. ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
  5. FileDescriptor[] fdArray = new FileDescriptor[4];
  6. fds.add(sServerSocket.getFileDescriptor());
  7. peers.add(null);
  8. int loopCount = GC_LOOP_COUNT;
  9. while (true) {
  10. int index;
  11. if (loopCount <= 0) {
  12. gc();
  13. loopCount = GC_LOOP_COUNT;
  14. } else {
  15. loopCount--;
  16. }
  17. try {
  18. fdArray = fds.toArray(fdArray);
  19. index = selectReadable(fdArray);
  20. } catch (IOException ex) {
  21. throw new RuntimeException("Error in select()", ex);
  22. }
  23. if (index < 0) {
  24. throw new RuntimeException("Error in select()");
  25. } else if (index == 0) {
  26. ZygoteConnection newPeer = acceptCommandPeer();
  27. peers.add(newPeer);
  28. fds.add(newPeer.getFileDesciptor());
  29. } else {
  30. boolean done;
  31. done = peers.get(index).runOnce();
  32. if (done) {
  33. peers.remove(index);
  34. fds.remove(index);
  35. }
  36. }
  37. }
  38. }
在一个while循环中,不断调用selectReadable()。该函数是个native函数,对应C++层的com_android_internal_os_ZygoteInit_selectReadable()。

【frameworks/base/core/jni/com_android_internal_os_ZygoteInit.cpp】

  1. static jint com_android_internal_os_ZygoteInit_selectReadable (JNIEnv *env, jobject clazz,
  2. jobjectArray fds)
  3. {
  4. . . . . . .
  5. int err;
  6. do {
  7. err = select (nfds, &fdset, NULL, NULL, NULL);
  8. } while (err < 0 && errno == EINTR);
  9. . . . . . .
  10. for (jsize i = 0; i < length; i++) {
  11. jobject fdObj = env->GetObjectArrayElement(fds, i);
  12. . . . . . .
  13. int fd = jniGetFDFromFileDescriptor(env, fdObj);
  14. . . . . . .
  15. if (FD_ISSET(fd, &fdset)) {
  16. return (jint)i;
  17. }
  18. }
  19. return -1;
  20. }

可以看到,主要就是调用select()而已。在Linux的socket编程中,select()负责监视若干文件描述符的变化情况,我们常见的变化情况有:读、写、异常等等。在zygote中,

err = select (nfds, &fdset, NULL, NULL, NULL);一句的最后三个参数都为NULL,表示该select()操作只打算监视文件描述符的“读变化”,而且如果没有可读的文件,select()就维持阻塞状态。

在被监视的文件描述符数组(fds)中,第一个文件描述符对应着“zygote接收其他进程连接申请的那个socket(及sServerSocket)”,一旦它发生了变化,我们就尝试建立一个ZygoteConnection。

  1. // (index == 0)的情况
  2. ZygoteConnection newPeer = acceptCommandPeer();
  3. peers.add(newPeer);
  4. fds.add(newPeer.getFileDesciptor());
看到了吗,新创建的ZygoteConnection会被再次写入文件描述符数组(fds)。

如果select动作发现文件描述符数组(fds)的其他文件描述符有东西可读了,说明有其他进程通过某个已建立好的ZygoteConnection发来了命令,此时我们需要调用runOnce()。

  1. // (index > 0)的情况
  2. boolean done;
  3. done = peers.get(index).runOnce();
  4. if (done) {
  5. peers.remove(index);
  6. fds.remove(index);
  7. }
建立ZygoteConnection的acceptCommandPeer()的代码如下:
  1. private static ZygoteConnection acceptCommandPeer() {
  2. try {
  3. return new ZygoteConnection(sServerSocket.accept());
  4. } catch (IOException ex) {
  5. throw new RuntimeException(
  6. "IOException during accept()", ex);
  7. }
  8. }
 
3.2.5.1.1ZygoteConnection的runOnce()

ZygoteConnection的runOnce()代码截选如下:

  1. boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
  2. String args[];
  3. Arguments parsedArgs = null;
  4. FileDescriptor[] descriptors;
  5. . . . . . .
  6. args = readArgumentList();
  7. descriptors = mSocket.getAncillaryFileDescriptors();
  8. . . . . . .
  9. int pid = -1;
  10. FileDescriptor childPipeFd = null;
  11. FileDescriptor serverPipeFd = null;
  12. try {
  13. parsedArgs = new Arguments(args);
  14. . . . . . .
  15. pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
  16. parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal,
  17. parsedArgs.seInfo, parsedArgs.niceName);
  18. }
  19. . . . . . .
  20. if (pid == 0) {
  21. // in child
  22. IoUtils.closeQuietly(serverPipeFd);
  23. serverPipeFd = null;
  24. handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
  25. return true;
  26. } else {
  27. // in parent...pid of < 0 means failure
  28. IoUtils.closeQuietly(childPipeFd);
  29. childPipeFd = null;
  30. return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
  31. }
  32. . . . . . .
  33. }
 
3.2.5.1.2readArgumentList()

runOnce()中从socket中读取参数数据的动作是由readArgumentList()完成的,该函数的代码如下:

  1. private String[] readArgumentList()
  2. throws IOException
  3. {
  4. int argc;
  5. . . . . . .
  6. String s = mSocketReader.readLine();
  7. . . . . . .
  8. argc = Integer.parseInt(s);
  9. . . . . . .
  10. String[] result = new String[argc];
  11. for (int i = 0; i < argc; i++) {
  12. result[i] = mSocketReader.readLine();
  13. if (result[i] == null) {
  14. // We got an unexpected EOF.
  15. throw new IOException("truncated request");
  16. }
  17. }
  18. return result;
  19. }
可是是谁在向这个socket写入参数的呢?当然是AMS啦。

我们知道,当AMS需要启动一个新进程时,会调用类似下面的句子:

  1. Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
  2. app.processName, uid, uid, gids, debugFlags, mountExternal,
  3. app.info.targetSdkVersion, app.info.seinfo, null);
包括ActivityThread类名等重要信息的参数,最终就会通过socket传递给zygote。
3.2.5.1.3handleChildProc()

runOnce()在读完参数之后,会进一步调用到handleChildProc()。正如前文所说,该函数会间接抛出特殊的MethodAndArgsCaller异常,只不过此时抛出的异常携带的类名为ActivityThread。

  1. private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
  2. FileDescriptor pipeFd, PrintStream newStderr)
  3. throws ZygoteInit.MethodAndArgsCaller
  4. {
  5. closeSocket();
  6. ZygoteInit.closeServerSocket();
  7. . . . . . .
  8. if (parsedArgs.niceName != null) {
  9. Process.setArgV0(parsedArgs.niceName);
  10. }
  11. if (parsedArgs.runtimeInit) {
  12. if (parsedArgs.invokeWith != null) {
  13. WrapperInit.execApplication(parsedArgs.invokeWith,
  14. parsedArgs.niceName, parsedArgs.targetSdkVersion,
  15. pipeFd, parsedArgs.remainingArgs);
  16. } else {
  17. RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
  18. parsedArgs.remainingArgs);
  19. }
  20. } else {
  21. String className;
  22. . . . . . .
  23. className = parsedArgs.remainingArgs[0];
  24. . . . . . .
  25. String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];
  26. System.arraycopy(parsedArgs.remainingArgs, 1,
  27. mainArgs, 0, mainArgs.length);
  28. if (parsedArgs.invokeWith != null) {
  29. WrapperInit.execStandalone(parsedArgs.invokeWith,
  30. parsedArgs.classpath, className, mainArgs);
  31. } else {
  32. ClassLoader cloader;
  33. if (parsedArgs.classpath != null) {
  34. cloader = new PathClassLoader(parsedArgs.classpath,
  35. ClassLoader.getSystemClassLoader());
  36. } else {
  37. cloader = ClassLoader.getSystemClassLoader();
  38. }
  39. try {
  40. ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
  41. } catch (RuntimeException ex) {
  42. logAndPrintError(newStderr, "Error starting.", ex);
  43. }
  44. }
  45. }
  46. }
 

4小结

至此,zygote进程就阐述完毕了。作为一个最原始的“受精卵”,它必须在合适的时机进行必要的细胞分裂。分裂动作也没什么大的花样,不过就是fork()新进程而已。如果fork()出的新进程是system server,那么其最终执行的就是SystemServer类的main()函数,而如果fork()出的新进程是普通的用户进程的话,那么其最终执行的就是ActivityThread类的main()函数。有关ActivityThread的细节,我们有时间再深入探讨,这里就不细说了。

本篇文章和我的上一篇文章《Android4.4的init进程》可以算是姊妹篇啦。读完这两篇文章,我相信大家对Android的启动流程能有一些大面上的认识了。

转自http://blog.csdn.net/codefly/article/details/48413829

Android4.4的zygote进程(下)的更多相关文章

  1. Android4.4的zygote进程(上)

    1背景 前些天为了在科室做培训,我基于Android 4.4重新整理了一份关于zygote的文档.从技术的角度看,这几年zygote并没有出现什么大的变化,所以如果有人以前研究过zygote,应该不会 ...

  2. Android4.4 Framework分析——Zygote进程的启动过程

    Android启动过程中的第一个进程init.在启动过程中会启动两个关键的系统服务进程ServiceManager和Zygote. 本文要介绍的就是Zygote进程的启动,Zygote俗称孵化器,专门 ...

  3. Zygote进程【1】——Zygote的诞生

    在Android中存在着C和Java两个完全不同的世界,前者直接建立在Linux的基础上,后者直接建立在JVM的基础上.zygote的中文名字为"受精卵",这个名字很好的诠释了zy ...

  4. Zygote进程【3】——SystemServer的诞生

    在ZygoteInit的main()方法中做了几件大事,其中一件便是启动Systemserver进程,代码如下: @/frameworks/base/core/Java/com/Android/int ...

  5. Android Zygote进程是如何fork一个APP进程的

    进程创建流程 不管从桌面启动应用还是应用内启动其它应用,如果这个应用所在进程不存在的话,都需要发起进程通过Binder机制告诉system server进程的AMS system server进程的A ...

  6. Android Zygote进程启动分析

    dvm,app进程,linux进程三者关系 DVM指 dalivk 的虚拟机.每一个 Android 应用程序都在它自己的进程中运行,都拥有一个独立的 Dalvik 虚拟机实例.而每一个 DVM 都是 ...

  7. Zygote进程介绍【转】

    本文转载自:http://blog.csdn.net/yangwen123/article/details/17258023 Zygote进程介绍   在Android系统中,存在不同的服务,这些服务 ...

  8. Zygote进程【2】——Zygote的分裂

    在Zygote的诞生一文中init进程是如何一步步创建Zygote进程的,也了解了Zygote的进程的作用.Zygote进程的诞生对于整个Java世界可以说有着"开天辟地"的作用, ...

  9. 父进程结束,其子进程不会结束,会挂到init进程下

    结论:一个父进程产生子进程,父进程结束(kill),子进程不会结束,子进程被init进程托管 下面是过程: d.sh脚本是一个ping命令,执行d.sh 目前,103310 进程为父进程,103344 ...

随机推荐

  1. java多线程处理导入数据拆分List集合 同步处理插入数据

    原文:https://www.2cto.com/kf/201612/581174.html import org.apache.log4j.Logger; import org.apache.poi. ...

  2. 【hibernate】错误:org.hibernate.HibernateException: identifier of an instance of com.agen.entity.Monthdetail was altered from xx to xx

    所报错误: org.hibernate.HibernateException: identifier of an instance of com.agen.entity.Monthdetail was ...

  3. Netty游戏服务器二

    上节我们写个server主类,那么发现什么事情都干不了,是的,我们还没有做任何的业务处理. 接着我们开始写处理客户端连接,发送接收数据的类ServerHandler. public class Ser ...

  4. 以下内容为Stackoverflow上整理以作纪录

    PRO 用IMG标签 Use IMG plus alt attribute if the image is part of the content such as a logo or diagram ...

  5. Spring 自定义配置类bean

    <!-- 引入配置文件 --> <bean id="propertyConfigurer" class="org.springframework.bea ...

  6. 记一次MySQL找回用户数据

    事情经过 有天,我们公司外区的一个销售C说他8月3号以前的工作流记录找不到了.问清缘由,原来是更新了微信号(我们公司的工作流是基于企业微信开发的).经过分析,微信号和流程数据并没什么关系,所以初步得出 ...

  7. vue - static(.gitkeep)

    描述:git上传忽略的文件,与.gitnoignore一样.

  8. Unity3D研究院之DontDestroyOnLoad的坑

    http://www.xuanyusong.com/archives/2938 Unity中的一个方法DontDestroyOnLoad可以让某些游戏对象在切换场景的时候不是施放,听起来是一个非常好的 ...

  9. LaTex的注释

    在LaTex中的注释有以下3种 1.注释一行:使用%注释一行文字, 在%后的文字都不予编译: 2.注释一段:使用\iffalse .... \fi 包含一段文字,被包含的文字被注释掉了: 3.注释一段 ...

  10. javaWeb项目部署到阿里云服务器步骤 完整版

    记录web项目部署到阿里云服务器步骤 (使用 web项目.阿里云服务器.Xftp.Xshell),敬请参考和指正 1.将要部署的项目打包成WAR文件格式,可以在MyEclipse.Eclipse都可以 ...