Android5 Zygote 与 SystemServer 启动流程分析

前言

Android5.0.1 的启动流程与之前的版本号相比变化并不大,OK,变化尽管还是有:SystemServer 启动过程的 init1(), init2()没有了,但主干流程依旧不变:Linux 内核载入完毕之后,首先启动 init 进程。然后解析 init.rc,并依据其内容由 init 进程装载 Android 文件系统、创建系统文件夹、初始化属性系统、启动一些守护进程,当中最重要的守护进程就是 Zygote 进程。Zygote 进程初始化时会创建 Dalvik 虚拟机、预装载系统的资源和 Java 类。

全部从 Zygote 进程 fork 出来的用户进程都将继承和共享这些预载入的资源。

init 进程是 Android 的第一个进程,而 Zygote 进程则是全部用户进程的根进程。SystemServer 是 Zygote 进程 fork 出的第一个进程,也是整个 Android 系统的核心进程。

zygote 进程

解析 zygote.rc

在文件里 /system/core/rootdir/init.rc 中包括了 zygote.rc:

  1. import /init.${ro.zygote}.rc

${ro.zygote}是平台相关的參数,实际可相应到 init.zygote32.rc。 init.zygote64.rc, init.zygote64_32.rc, init.zygote32_64.rc,前两个仅仅会启动单一app_process(64) 进程,而后两个则会启动两个app_process进程:第二个app_process进程称为 secondary,在后面的代码中能够看到相应 secondary socket 的创建过程。

为简化起见,在这里就不考虑这样的创建两个app_process进程的情形。

以 /system/core/rootdir/init.zygote32.rc 为例:

  1. service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
  2. class main
  3. socket zygote stream 660 root system
  4. onrestart write /sys/android_power/request_state wake
  5. onrestart write /sys/power/state on
  6. onrestart restart media
  7. onrestart restart netd

第一行创建了名为 zygote 的进程,这个进程是通过 app_process 的 main 启动并以”-Xzygote /system/bin –zygote –start-system-server”作为main的入口參数。

app_process 相应代码为 framework/base/cmds/app_process/app_main.cpp。在这个文件的main函数中:

  1. AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
  2. if (zygote) {
  3. runtime.start("com.android.internal.os.ZygoteInit", args);
  4. } else if (className) {
  5. runtime.start("com.android.internal.os.RuntimeInit", args);
  6. }

依据入口參数。我们知道 zygote 为true,args參数中包括了”start-system-server”。

AppRuntime 继承自 AndroidRuntime,因此下一步就运行到 AndroidRuntime 的 start 函数。

  1. void AndroidRuntime::start(const char* className, const Vector<String8>& options)
  2. {
  3. /* start the virtual machine */ // 创建虚拟机
  4. JniInvocation jni_invocation;
  5. jni_invocation.Init(NULL);
  6. JNIEnv* env;
  7. if (startVm(&mJavaVM, &env) != 0) {
  8. return;
  9. }
  10. onVmCreated(env);
  11. ...
  12. //调用className相应类的静态main()函数
  13. char* slashClassName = toSlashClassName(className);
  14. jclass startClass = env->FindClass(slashClassName);
  15. jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
  16. env->CallStaticVoidMethod(startClass, startMeth, strArray);
  17. ...
  18. }

start函数主要做两件事:创建虚拟机和调用传入类名相应类的 main 函数。

因此下一步就运行到 com.android.internal.os.ZygoteInit 的 main 函数。

  1. public static void main(String argv[]) {
  2. try {
  3. boolean startSystemServer = false;
  4. String socketName = "zygote";
  5. for (int i = 1; i < argv.length; i++) {
  6. if ("start-system-server".equals(argv[i])) {
  7. startSystemServer = true;
  8. }
  9. ...
  10. }
  11. registerZygoteSocket(socketName);
  12. ...
  13. preload();
  14. ...
  15. if (startSystemServer) {
  16. startSystemServer(abiList, socketName);
  17. }
  18. Log.i(TAG, "Accepting command socket connections");
  19. runSelectLoop(abiList);
  20. closeServerSocket();
  21. } catch (MethodAndArgsCaller caller) {
  22. caller.run();
  23. } catch (RuntimeException ex) {
  24. Log.e(TAG, "Zygote died with exception", ex);
  25. closeServerSocket();
  26. throw ex;
  27. }
  28. }

它主要做了三件事情:

1. 调用 registerZygoteSocket 函数创建了一个 socket 接口,用来和 ActivityManagerService 通讯;

2. 调用 startSystemServer 函数来启动 SystemServer;

3. 调用 runSelectLoop 函数进入一个无限循环在前面创建的 socket 接口上等待 ActivityManagerService 请求创建新的应用程序进程。

这里要留意 catch (MethodAndArgsCaller caller) 这一行,android 在这里通过抛出一个异常来处理正常的业务逻辑。

  1. socket zygote stream 660 root system

系统启动脚本文件 init.rc 是由 init 进程来解释运行的。而 init 进程的源码位于 system/core/init 文件夹中。在 init.c 文件里,是由 service_start 函数来解释 init.zygote32.rc 文件里的 service 命令的:

  1. void service_start(struct service *svc, const char *dynamic_args)
  2. {
  3. ...
  4. pid = fork();
  5. if (pid == 0) {
  6. struct socketinfo *si;
  7. ...
  8. for (si = svc->sockets; si; si = si->next) {
  9. int socket_type = (
  10. !strcmp(si->type, "stream") ? SOCK_STREAM :
  11. (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
  12. int s = create_socket(si->name, socket_type,
  13. si->perm, si->uid, si->gid, si->socketcon ?: scon);
  14. if (s >= 0) {
  15. publish_socket(si->name, s);
  16. }
  17. }
  18. ...
  19. }
  20. ...
  21. }

每个 service 命令都会促使 init 进程调用 fork 函数来创建一个新的进程,在新的进程里面,会分析里面的 socket 选项,对于每个 socket 选项。都会通过 create_socket 函数来在 /dev/socket 文件夹下创建一个文件,在 zygote 进程中 socket 选项为“socket zygote stream 660 root system”,因此这个文件便是 zygote了,然后得到的文件描写叙述符通过 publish_socket 函数写入到环境变量中去:

  1. static void publish_socket(const char *name, int fd)
  2. {
  3. char key[64] = ANDROID_SOCKET_ENV_PREFIX;
  4. char val[64];
  5. strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
  6. name,
  7. sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
  8. snprintf(val, sizeof(val), "%d", fd);
  9. add_environment(key, val);
  10. /* make sure we don't close-on-exec */
  11. fcntl(fd, F_SETFD, 0);
  12. }

这里传进来的參数name值为”zygote”,而 ANDROID_SOCKET_ENV_PREFIX 在 system/core/include/cutils/sockets.h 定义为:

  1. #define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_"
  2. #define ANDROID_SOCKET_DIR "/dev/socket"

因此。这里就把上面得到的文件描写叙述符写入到以 “ANDROID_SOCKET_zygote” 为 key 值的环境变量中。

又由于上面的 ZygoteInit.registerZygoteSocket 函数与这里创建 socket 文件的 create_socket 函数是运行在同一个进程中,因此,上面的 ZygoteInit.registerZygoteSocket 函数能够直接使用这个文件描写叙述符来创建一个 Java层的LocalServerSocket 对象。假设其他进程也需要打开这个 /dev/socket/zygote 文件来和 zygote 进程进行通信,那就必需要通过文件名称来连接这个 LocalServerSocket了。也就是说创建 zygote socket 之后,ActivityManagerService 就能够通过该 socket 与 zygote 进程通信从而 fork 创建新进程。android 中的全部应用进程都是通过这样的方式 fork zygote 进程创建的。在 ActivityManagerService中 的 startProcessLocked 中调用了Process.start()方法。进而调用 Process.startViaZygote 和 Process.openZygoteSocketIfNeeded。

启动 SystemServer

socket 创建完毕之后,紧接着就通过 startSystemServer 函数来启动 SystemServer 进程。

  1. private static boolean startSystemServer(String abiList, String socketName)
  2. {
  3. long capabilities = posixCapabilitiesAsBits(
  4. OsConstants.CAP_BLOCK_SUSPEND,
  5. OsConstants.CAP_KILL,
  6. OsConstants.CAP_NET_ADMIN,
  7. OsConstants.CAP_NET_BIND_SERVICE,
  8. OsConstants.CAP_NET_BROADCAST,
  9. OsConstants.CAP_NET_RAW,
  10. OsConstants.CAP_SYS_MODULE,
  11. OsConstants.CAP_SYS_NICE,
  12. OsConstants.CAP_SYS_RESOURCE,
  13. OsConstants.CAP_SYS_TIME,
  14. OsConstants.CAP_SYS_TTY_CONFIG
  15. );
  16. /* Hardcoded command line to start the system server */
  17. String args[] = {
  18. "--setuid=1000",
  19. "--setgid=1000",
  20. "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
  21. "--capabilities=" + capabilities + "," + capabilities,
  22. "--runtime-init",
  23. "--nice-name=system_server",
  24. "com.android.server.SystemServer",
  25. };
  26. ZygoteConnection.Arguments parsedArgs = null;
  27. int pid;
  28. try {
  29. parsedArgs = new ZygoteConnection.Arguments(args);
  30. ...
  31. /* Request to fork the system server process */
  32. pid = Zygote.forkSystemServer(
  33. parsedArgs.uid, parsedArgs.gid,
  34. parsedArgs.gids,
  35. parsedArgs.debugFlags,
  36. null,
  37. parsedArgs.permittedCapabilities,
  38. parsedArgs.effectiveCapabilities);
  39. } catch (IllegalArgumentException ex) {
  40. throw new RuntimeException(ex);
  41. }
  42. /* For child process */
  43. if (pid == 0) {
  44. if (hasSecondZygote(abiList)) {
  45. waitForSecondaryZygote(socketName);
  46. }
  47. handleSystemServerProcess(parsedArgs);
  48. }
  49. return true;
  50. }

这里我们能够从參数猜測出:创建名为“system_server”的进程。其入口是: com.android.server.SystemServer 的 main 函数。

zygote 进程通过 Zygote.forkSystemServer 函数来创建一个新的进程来启动 SystemServer 组件,返回值 pid 等 0 的地方就是新的进程要运行的路径。即新创建的进程会运行 handleSystemServerProcess 函数。hasSecondZygote 是针对 init.zygote64_32.rc。 init.zygote32_64.rc 这两者情况的。在这里跳过不谈。接下来来看 handleSystemServerProcess:

  1. /**
  2. * Finish remaining work for the newly forked system server process.
  3. */
  4. private static void handleSystemServerProcess(
  5. ZygoteConnection.Arguments parsedArgs)
  6. throws ZygoteInit.MethodAndArgsCaller
  7. {
  8. closeServerSocket();
  9. // set umask to 0077 so new files and directories will default to owner-only permissions.
  10. Os.umask(S_IRWXG | S_IRWXO);
  11. if (parsedArgs.niceName != null) {
  12. Process.setArgV0(parsedArgs.niceName);
  13. }
  14. final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
  15. ClassLoader cl = null;
  16. if (systemServerClasspath != null) {
  17. cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
  18. Thread.currentThread().setContextClassLoader(cl);
  19. }
  20. /*
  21. * Pass the remaining arguments to SystemServer.
  22. */
  23. RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
  24. /* should never reach here */
  25. }

handleSystemServerProcess 会抛出 MethodAndArgsCaller 异常,前面提到这个异常事实上是处理正常业务逻辑的,相当于一个回调。

由于由 zygote 进程创建的子进程会继承 zygote 进程在前面创建的 socket 文件描写叙述符,而这里的子进程又不会用到它,因此。这里就调用 closeServerSocket 函数来关闭它。SYSTEMSERVERCLASSPATH 是包括 /system/framework/framework.jar 的环境变量。它定义在 system/core/rootdir/init.environ.rc.in 中:

  1. on init
  2. export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
  3. export ANDROID_BOOTLOGO 1
  4. export ANDROID_ROOT /system
  5. export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH%
  6. export LD_PRELOAD libsigchain.so
  7. handleSystemServerProcess 函数接着调用 RuntimeInit.zygoteInit 函数来进一步运行启动 SystemServer 组件的操作。
  8. public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
  9. throws ZygoteInit.MethodAndArgsCaller {
  10. commonInit();
  11. nativeZygoteInit();
  12. applicationInit(targetSdkVersion, argv, classLoader);
  13. }

commonInit 设置线程未处理异常handler,时区等。JNI 方法 nativeZygoteInit 实如今 frameworks/base/core/jni/AndroidRuntime.cpp 中:

  1. static AndroidRuntime* gCurRuntime = NULL;
  2. static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
  3. {
  4. gCurRuntime->onZygoteInit();
  5. }

AndroidRuntime 是个带虚函数的基类,真正的实现是在 app_main.cpp 中的 AppRuntime:

  1. class AppRuntime : public AndroidRuntime
  2. {
  3. virtual void onStarted()
  4. {
  5. sp<ProcessState> proc = ProcessState::self();
  6. ALOGV("App process: starting thread pool.\n");
  7. proc->startThreadPool();
  8. AndroidRuntime* ar = AndroidRuntime::getRuntime();
  9. ar->callMain(mClassName, mClass, mArgs);
  10. IPCThreadState::self()->stopProcess();
  11. }
  12. virtual void onZygoteInit()
  13. {
  14. // Re-enable tracing now that we're no longer in Zygote.
  15. atrace_set_tracing_enabled(true);
  16. sp<ProcessState> proc = ProcessState::self();
  17. ALOGV("App process: starting thread pool.\n");
  18. proc->startThreadPool();
  19. }
  20. virtual void onExit(int code)
  21. {
  22. if (mClassName.isEmpty()) {
  23. // if zygote
  24. IPCThreadState::self()->stopProcess();
  25. }
  26. AndroidRuntime::onExit(code);
  27. }
  28. };

通过运行 AppRuntime::onZygoteInit 函数,这个进程的 Binder 进程间通信机制基础设施就准备好了,參考代码 frameworks/native/libs/binder/ProcessState.cpp。

接下来,看 applicationInit :

  1. private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
  2. throws ZygoteInit.MethodAndArgsCaller {
  3. final Arguments args;
  4. try {
  5. args = new Arguments(argv);
  6. } catch (IllegalArgumentException ex) {
  7. Slog.e(TAG, ex.getMessage());
  8. // let the process exit
  9. return;
  10. }
  11. // Remaining arguments are passed to the start class's static main
  12. invokeStaticMain(args.startClass, args.startArgs, classLoader);
  13. }

applicationInit 仅仅是转调 invokeStaticMain:

  1. private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
  2. throws ZygoteInit.MethodAndArgsCaller
  3. {
  4. Class cl;
  5. cl = Class.forName(className, true, classLoader);
  6. Method m;
  7. m = cl.getMethod("main", new Class[] { String[].class });
  8. /*
  9. * This throw gets caught in ZygoteInit.main(), which responds
  10. * by invoking the exception's run() method. This arrangement
  11. * clears up all the stack frames that were required in setting
  12. * up the process.
  13. */
  14. throw new ZygoteInit.MethodAndArgsCaller(m, argv);
  15. }

invokeStaticMain 也非常easy。通过反射找到參数 className 相应的类的静态 main 方法。然后将该方法与參数生成 ZygoteInit.MethodAndArgsCaller 对象当做异常抛出,这个异常对象在 ZygoteInit 的 main 函数被捕获并运行该对象的 run 方法。

  1. /**
  2. * Helper exception class which holds a method and arguments and
  3. * can call them. This is used as part of a trampoline to get rid of
  4. * the initial process setup stack frames.
  5. */
  6. public static class MethodAndArgsCaller extends Exception
  7. implements Runnable {
  8. public void run() {
  9. ...
  10. mMethod.invoke(null, new Object[] { mArgs });
  11. ...
  12. }
  13. }

这么复杂的跳转。事实上就做了一件简单的事情:依据 className 反射调用该类的静态 main 方法。

这个类名是 ZygoteInit.startSystemServer 方法中写死的 com.android.server.SystemServer。 从而进入 SystemServer 类的 main()方法。

运行 ZygoteInit.runSelectLoop

在 startSystemServer 函数中,创建 system_server 进程之后,pid 等于 0 时在该新进程中运行 SystemServer.main,否则回到 zygote 进程进行运行 ZygoteInit.runSelectLoop:

  1. private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
  2. ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
  3. ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
  4. FileDescriptor[] fdArray = new FileDescriptor[4];
  5. fds.add(sServerSocket.getFileDescriptor());
  6. peers.add(null);
  7. int loopCount = GC_LOOP_COUNT;
  8. while (true) {
  9. int index;
  10. /*
  11. * Call gc() before we block in select().
  12. * It's work that has to be done anyway, and it's better
  13. * to avoid making every child do it. It will also
  14. * madvise() any free memory as a side-effect.
  15. *
  16. * Don't call it every time, because walking the entire
  17. * heap is a lot of overhead to free a few hundred bytes.
  18. */
  19. if (loopCount <= 0) {
  20. gc();
  21. loopCount = GC_LOOP_COUNT;
  22. } else {
  23. loopCount--;
  24. }
  25. try {
  26. fdArray = fds.toArray(fdArray);
  27. index = selectReadable(fdArray);
  28. } catch (IOException ex) {
  29. throw new RuntimeException("Error in select()", ex);
  30. }
  31. if (index < 0) {
  32. throw new RuntimeException("Error in select()");
  33. } else if (index == 0) {
  34. ZygoteConnection newPeer = acceptCommandPeer(abiList);
  35. peers.add(newPeer);
  36. fds.add(newPeer.getFileDescriptor());
  37. } else {
  38. boolean done;
  39. done = peers.get(index).runOnce();
  40. if (done) {
  41. peers.remove(index);
  42. fds.remove(index);
  43. }
  44. }
  45. }
  46. }

runSelectLoop函数的逻辑比較简单,主要有两点:

1、 处理client的连接和请求。前面创建的 LocalServerSocket 对象保存 sServerSocket,这个 socket 通过 selectReadable 等待 ActivityManagerService(简写 AMS) 与之通信。selectReadable 是一个native函数。内部调用select等待 AMS 连接。AMS 连接上之后就会返回: 返回值 < 0:内部错误发生;返回值 = 0:第一次连接到服务端 ;返回值 > 0:与服务端已经建立连接。并開始发送数据。每个链接在 zygote 进程中使用 ZygoteConnection 对象表示。

2、 client的请求由 ZygoteConnection.runOnce 来处理,这种方法也抛出 MethodAndArgsCaller 异常,从而进入 MethodAndArgsCaller.run 中调用依据客户请求数据反射出的类的 main 方法。

  1. private String[] readArgumentList()
  2. {
  3. int argc;
  4. try {
  5. String s = mSocketReader.readLine();
  6. if (s == null) {
  7. // EOF reached.
  8. return null;
  9. }
  10. argc = Integer.parseInt(s);
  11. } catch (NumberFormatException ex) {
  12. Log.e(TAG, "invalid Zygote wire format: non-int at argc");
  13. throw new IOException("invalid wire format");
  14. }
  15. String[] result = new String[argc];
  16. for (int i = 0; i < argc; i++) {
  17. result[i] = mSocketReader.readLine();
  18. if (result[i] == null) {
  19. // We got an unexpected EOF.
  20. throw new IOException("truncated request");
  21. }
  22. }
  23. return result;
  24. }
  25. boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
  26. String args[];
  27. Arguments parsedArgs = null;
  28. args = readArgumentList();
  29. parsedArgs = new Arguments(args);
  30. ...
  31. pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
  32. parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
  33. parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
  34. parsedArgs.appDataDir);
  35. ...
  36. }

SystemServer 启动过程

在前面启动 SystemServer一节讲到,通过反射调用类 com.android.server.SystemServer main() 函数,从而開始运行 SystemServer 的初始化流程。

SystemServer.main()

  1. /**
  2. * The main entry point from zygote.
  3. */
  4. public static void main(String[] args) {
  5. new SystemServer().run();
  6. }

main 函数创建一个 SystemServer 对象,调用其 run() 方法。

  1. private void run() {
  2. // If a device's clock is before 1970 (before 0), a lot of
  3. // APIs crash dealing with negative numbers, notably
  4. // java.io.File#setLastModified, so instead we fake it and
  5. // hope that time from cell towers or NTP fixes it shortly.
  6. if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
  7. Slog.w(TAG, "System clock is before 1970; setting to 1970.");
  8. SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
  9. } // 检測时间设置
  10. // Here we go!
  11. Slog.i(TAG, "Entered the Android system server!");
  12. EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());
  13. // In case the runtime switched since last boot (such as when
  14. // the old runtime was removed in an OTA), set the system
  15. // property so that it is in sync. We can't do this in
  16. // libnativehelper's JniInvocation::Init code where we already
  17. // had to fallback to a different runtime because it is
  18. // running as root and we need to be the system user to set
  19. // the property. http://b/11463182
  20. SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
  21. // Enable the sampling profiler.
  22. if (SamplingProfilerIntegration.isEnabled()) {
  23. SamplingProfilerIntegration.start();
  24. mProfilerSnapshotTimer = new Timer();
  25. mProfilerSnapshotTimer.schedule(new TimerTask() {
  26. @Override
  27. public void run() {
  28. SamplingProfilerIntegration.writeSnapshot("system_server", null);
  29. }
  30. }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
  31. } // 启动性能分析採样
  32. // Mmmmmm... more memory!
  33. VMRuntime.getRuntime().clearGrowthLimit();
  34. // The system server has to run all of the time, so it needs to be
  35. // as efficient as possible with its memory usage.
  36. VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
  37. // Some devices rely on runtime fingerprint generation, so make sure
  38. // we've defined it before booting further.
  39. Build.ensureFingerprintProperty();
  40. // Within the system server, it is an error to access Environment paths without
  41. // explicitly specifying a user.
  42. Environment.setUserRequired(true);
  43. // Ensure binder calls into the system always run at foreground priority.
  44. BinderInternal.disableBackgroundScheduling(true);
  45. // Prepare the main looper thread (this thread).
  46. android.os.Process.setThreadPriority(
  47. android.os.Process.THREAD_PRIORITY_FOREGROUND);
  48. android.os.Process.setCanSelfBackground(false);
  49. Looper.prepareMainLooper(); // 准备主线程循环
  50. // Initialize native services.
  51. System.loadLibrary("android_servers");
  52. nativeInit();
  53. // Check whether we failed to shut down last time we tried.
  54. // This call may not return.
  55. performPendingShutdown();
  56. // Initialize the system context.
  57. createSystemContext();
  58. // Create the system service manager.
  59. mSystemServiceManager = new SystemServiceManager(mSystemContext);
  60. LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
  61. // Start services. // 启动服务
  62. try {
  63. startBootstrapServices();
  64. startCoreServices();
  65. startOtherServices();
  66. } catch (Throwable ex) {
  67. Slog.e("System", "******************************************");
  68. Slog.e("System", "************ Failure starting system services", ex);
  69. throw ex;
  70. }
  71. // For debug builds, log event loop stalls to dropbox for analysis.
  72. if (StrictMode.conditionallyEnableDebugLogging()) {
  73. Slog.i(TAG, "Enabled StrictMode for system server main thread.");
  74. }
  75. // Loop forever.
  76. Looper.loop(); // 启动线程循环,等待消息处理
  77. throw new RuntimeException("Main thread loop unexpectedly exited");
  78. }

在这个 run 方法中,主要完毕三件事情。创建 system context 和 system service manager,启动一些系统服务。进入主线程消息循环。

Zygote 的 fork 本地方法分析

接下来我们细致分析 Zygote.forkSystemServer 与 Zygote.forkAndSpecialize 两个方法。

forkSystemServer

  1. private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
  2. public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
  3. int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
  4. VM_HOOKS.preFork();
  5. int pid = nativeForkSystemServer(
  6. uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
  7. VM_HOOKS.postForkCommon();
  8. return pid;
  9. }

在调用 nativeForkSystemServer 创建 system_server 进程之前与之后,都会调用 ZygoteHooks 进行一些前置与后置处理。

ZygoteHooks.preFork

前置处理 ZygoteHooks.preFork:

  1. public void preFork() {
  2. Daemons.stop();
  3. waitUntilAllThreadsStopped();
  4. token = nativePreFork();
  5. }

Daemons.stop(); 停止虚拟机中一些守护线程操作:如引用队列、终接器、GC等

  1. public static void stop() {
  2. ReferenceQueueDaemon.INSTANCE.stop();
  3. FinalizerDaemon.INSTANCE.stop();
  4. FinalizerWatchdogDaemon.INSTANCE.stop();
  5. HeapTrimmerDaemon.INSTANCE.stop();
  6. GCDaemon.INSTANCE.stop();
  7. }

waitUntilAllThreadsStopped 保证被 fork 的进程是单线程,这样能够确保通过 copyonwrite fork 出来的进程也是单线程。从而节省资源。

与前面提到的在新建 system_server 进程中调用 closeServerSocket 关闭 sockect 有异曲同工之妙。

  1. /**
  2. * We must not fork until we're single-threaded again. Wait until /proc shows we're
  3. * down to just one thread.
  4. */
  5. private static void waitUntilAllThreadsStopped() {
  6. File tasks = new File("/proc/self/task");
  7. while (tasks.list().length > 1) {
  8. try {
  9. // Experimentally, booting and playing about with a stingray, I never saw us
  10. // go round this loop more than once with a 10ms sleep.
  11. Thread.sleep(10);
  12. } catch (InterruptedException ignored) {
  13. }
  14. }
  15. }

本地方法 nativePreFork 实如今 art/runtime/native/dalvik_system_ZygoteHooks.cc 中。

  1. static jlong ZygoteHooks_nativePreFork(JNIEnv* env, jclass) {
  2. Runtime* runtime = Runtime::Current();
  3. CHECK(runtime->IsZygote()) << "runtime instance not started with -Xzygote";
  4. runtime->PreZygoteFork();
  5. // Grab thread before fork potentially makes Thread::pthread_key_self_ unusable.
  6. Thread* self = Thread::Current();
  7. return reinterpret_cast<jlong>(self);
  8. }

ZygoteHooks_nativePreFork 通过调用 Runtime::PreZygoteFork 来完毕 gc 堆的一些初始化,这部分代码在 art/runtime/runtime.cc 中:

  1. heap_ = new gc::Heap(...);
  2. void Runtime::PreZygoteFork() {
  3. heap_->PreZygoteFork();
  4. }

创建 system_server 进程:

nativeForkSystemServer 实如今 framework/base/core/jni/com_android_internal_os_Zygote.cpp 中:

  1. static jint com_android_internal_os_Zygote_nativeForkSystemServer(
  2. JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
  3. jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,
  4. jlong effectiveCapabilities) {
  5. pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
  6. debug_flags, rlimits,
  7. permittedCapabilities, effectiveCapabilities,
  8. MOUNT_EXTERNAL_NONE, NULL, NULL, true, NULL,
  9. NULL, NULL);
  10. if (pid > 0) {
  11. // The zygote process checks whether the child process has died or not.
  12. ALOGI("System server process %d has been created", pid);
  13. gSystemServerPid = pid;
  14. // There is a slight window that the system server process has crashed
  15. // but it went unnoticed because we haven't published its pid yet. So
  16. // we recheck here just to make sure that all is well.
  17. int status;
  18. if (waitpid(pid, &status, WNOHANG) == pid) {
  19. ALOGE("System server process %d has died. Restarting Zygote!", pid);
  20. RuntimeAbort(env);
  21. }
  22. }
  23. return pid;
  24. }

它转调 ForkAndSpecializeCommon 来创建新进程。并确保 system_server 创建成功,若不成功便成仁:重新启动 zygote。由于没有 system_server 就干不了什么事情。ForkAndSpecializeCommon 实现例如以下:

  1. static const char kZygoteClassName[] = "com/android/internal/os/Zygote";
  2. gZygoteClass = (jclass) env->NewGlobalRef(env->FindClass(kZygoteClassName));
  3. gCallPostForkChildHooks = env->GetStaticMethodID(gZygoteClass, "callPostForkChildHooks",
  4. "(ILjava/lang/String;)V");
  5. // Utility routine to fork zygote and specialize the child process.
  6. static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
  7. jint debug_flags, jobjectArray javaRlimits,
  8. jlong permittedCapabilities, jlong effectiveCapabilities,
  9. jint mount_external,
  10. jstring java_se_info, jstring java_se_name,
  11. bool is_system_server, jintArray fdsToClose,
  12. jstring instructionSet, jstring dataDir)
  13. {
  14. SetSigChldHandler();
  15. pid_t pid = fork();
  16. if (pid == 0) {
  17. // The child process.
  18. ...
  19. rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
  20. ...
  21. UnsetSigChldHandler();
  22. ...
  23. env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
  24. is_system_server ? NULL : instructionSet);
  25. }
  26. else if (pid > 0) {
  27. // the parent process
  28. }
  29. return pid;
  30. }

ForkAndSpecializeCommon 首先设置子进程异常处理handler,然后 fork 新进程。在新进程中设置 SELinux,并清除它的子进程异常处理 handler,然后调用 Zygote.callPostForkChildHooks 方法。

  1. private static void callPostForkChildHooks(int debugFlags, String instructionSet) {
  2. long startTime = SystemClock.elapsedRealtime();
  3. VM_HOOKS.postForkChild(debugFlags, instructionSet);
  4. checkTime(startTime, "Zygote.callPostForkChildHooks");
  5. }

callPostForkChildHooks 又转调 ZygoteHooks.postForkChild :

  1. public void postForkChild(int debugFlags, String instructionSet) {
  2. nativePostForkChild(token, debugFlags, instructionSet);
  3. }

本地方法 nativePostForkChild 又进到 dalvik_system_ZygoteHooks.cc 中:

  1. static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, jint debug_flags,
  2. jstring instruction_set) {
  3. Thread* thread = reinterpret_cast<Thread*>(token);
  4. // Our system thread ID, etc, has changed so reset Thread state.
  5. thread->InitAfterFork();
  6. EnableDebugFeatures(debug_flags);
  7. if (instruction_set != nullptr) {
  8. ScopedUtfChars isa_string(env, instruction_set);
  9. InstructionSet isa = GetInstructionSetFromString(isa_string.c_str());
  10. Runtime::NativeBridgeAction action = Runtime::NativeBridgeAction::kUnload;
  11. if (isa != kNone && isa != kRuntimeISA) {
  12. action = Runtime::NativeBridgeAction::kInitialize;
  13. }
  14. Runtime::Current()->DidForkFromZygote(env, action, isa_string.c_str());
  15. } else {
  16. Runtime::Current()->DidForkFromZygote(env, Runtime::NativeBridgeAction::kUnload, nullptr);
  17. }
  18. }

thread->InitAfterFork(); 实如今 art/runtime/thread.cc 中,设置新进程主线程的线程id: tid。DidForkFromZygote 实如今 Runtime.cc 中:

  1. void Runtime::DidForkFromZygote(JNIEnv* env, NativeBridgeAction action, const char* isa) {
  2. is_zygote_ = false;
  3. switch (action) {
  4. case NativeBridgeAction::kUnload:
  5. UnloadNativeBridge();
  6. break;
  7. case NativeBridgeAction::kInitialize:
  8. InitializeNativeBridge(env, isa);
  9. break;
  10. }
  11. // Create the thread pool.
  12. heap_->CreateThreadPool();
  13. StartSignalCatcher();
  14. // Start the JDWP thread. If the command-line debugger flags specified "suspend=y",
  15. // this will pause the runtime, so we probably want this to come last.
  16. Dbg::StartJdwp();
  17. }

首先依据 action 參数来卸载或转载用于跨平台桥接用的库。然后启动 gc 堆的线程池。StartSignalCatcher 设置信号 处理 handler,其代码在 signal_catcher.cc 中。

ZygoteHooks.postForkCommon

后置处理 ZygoteHooks.postForkCommon:

  1. public void postForkCommon() {
  2. Daemons.start();
  3. }

postForkCommon 转调 Daemons.start,以初始化虚拟机中引用队列、终接器以及 gc 的守护线程。

  1. public static void start() {
  2. ReferenceQueueDaemon.INSTANCE.start();
  3. FinalizerDaemon.INSTANCE.start();
  4. FinalizerWatchdogDaemon.INSTANCE.start();
  5. HeapTrimmerDaemon.INSTANCE.start();
  6. GCDaemon.INSTANCE.start();
  7. }

forkAndSpecialize

Zygote.forkAndSpecialize 方法

  1. public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
  2. int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
  3. String instructionSet, String appDataDir) {
  4. long startTime = SystemClock.elapsedRealtime();
  5. VM_HOOKS.preFork();
  6. checkTime(startTime, "Zygote.preFork");
  7. int pid = nativeForkAndSpecialize(
  8. uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
  9. instructionSet, appDataDir);
  10. checkTime(startTime, "Zygote.nativeForkAndSpecialize");
  11. VM_HOOKS.postForkCommon();
  12. checkTime(startTime, "Zygote.postForkCommon");
  13. return pid;
  14. }

前置处理与后置处理与 forkSystemServer 中一样的,这里就跳过不讲了。本地方法 nativeForkAndSpecialize 实如今 framework/base/core/jni/com_android_internal_os_Zygote.cpp 中:

  1. static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
  2. JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
  3. jint debug_flags, jobjectArray rlimits,
  4. jint mount_external, jstring se_info, jstring se_name,
  5. jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {
  6. // Grant CAP_WAKE_ALARM to the Bluetooth process.
  7. jlong capabilities = 0;
  8. if (uid == AID_BLUETOOTH) {
  9. capabilities |= (1LL << CAP_WAKE_ALARM);
  10. }
  11. return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
  12. rlimits, capabilities, capabilities, mount_external, se_info,
  13. se_name, false, fdsToClose, instructionSet, appDataDir);
  14. }

这个函数与 com_android_internal_os_Zygote_nativeForkSystemServer 非常相似,仅仅只是少了一个确保子进程创建成功的步骤。

Android5 Zygote 与 SystemServer 启动流程分析的更多相关文章

  1. u-boot启动流程分析(2)_板级(board)部分

    转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global dat ...

  2. u-boot启动流程分析(1)_平台相关部分

    转自:http://www.wowotech.net/u-boot/boot_flow_1.html 1. 前言 本文将结合u-boot的“board—>machine—>arch—> ...

  3. Cocos2d-x3.3RC0的Android编译Activity启动流程分析

    本文将从引擎源代码Jni分析Cocos2d-x3.3RC0的Android Activity的启动流程,以下是具体分析. 1.引擎源代码Jni.部分Java层和C++层代码分析 watermark/2 ...

  4. Netty 拆包粘包和服务启动流程分析

    Netty 拆包粘包和服务启动流程分析 通过本章学习,笔者希望你能掌握EventLoopGroup的工作流程,ServerBootstrap的启动流程,ChannelPipeline是如何操作管理Ch ...

  5. Uboot启动流程分析(转载)

    最近一段时间一直在做uboot移植相关的工作,需要将uboot-2016-7移植到单位设计的ARMv7的处理器上.正好元旦放假三天闲来无事,有段完整的时间来整理下最近的工作成果.之前在学习uboot时 ...

  6. Storm集群启动流程分析

    Storm集群启动流程分析 程序员 1.客户端运行storm nimbus时,会调用storm的python脚本,该脚本中为每个命令编写了一个方法,每个方法都可以生成一条相应的Java命令. 命令格式 ...

  7. 【转】Netty 拆包粘包和服务启动流程分析

    原文:https://www.cnblogs.com/itdragon/archive/2018/01/29/8365694.html Netty 拆包粘包和服务启动流程分析 通过本章学习,笔者希望你 ...

  8. ubuntu为什么没有/etc/inittab文件? 深究ubuntu的启动流程分析

    Linux 内核启动 init ,init进程ID是1,是所有进程的父进程,所有进程由它控制. Ubuntu 的启动由upstart控制,自9.10后不再使用/etc/event.d目录的配置文件,改 ...

  9. imx6 uboot启动流程分析

    参考http://blog.csdn.net/skyflying2012/article/details/25804209 这里以imx6平台为例,分析uboot启动流程对于任何程序,入口函数是在链接 ...

随机推荐

  1. jquery版手风琴效果

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  2. 模块(二)——简单的log日志

    简单的log日志 鉴于任何功能模块或系统在调试时都需要日志打印,这里随便写了一下,作为以后代码调试之用,只实现了不同等级的日志输出功能,其他的调试功能以后再行添加:使用方法简单,只需要在头文件里事先按 ...

  3. box-sizing重置

    html { /*-webkit-box-sizing: border-box; -moz-box-sizing: border-box;*/ box-sizing: border-box; } *, ...

  4. 妹子(girls)

    妹子(girls) 题目描述 万人迷皮皮轩收到了很多妹子的礼物,由于皮皮轩觉得每个妹子都不错,所以将她们礼物的包装盒都好好保存,但长此以往皮皮轩的房间里都堆不下了,所以只能考虑将一些包装盒放进其他包装 ...

  5. Linux服务器重启后nvidia-smi无法使用的解决方法

    服务器上的nvidia显卡驱动用的好好的,突然有一天,服务器断电了,然后恢复之后发现常用的nvidia-smi命令无法使用了,具体显示什么无法建立和驱动器的通信之类的,上网查了一堆,发现问题的核心:l ...

  6. vue中echarts 在element-ui的tab 切换时 width 为100px 时的解决方式

    最近在项目中遇到了这种情况,需要在tab控件上渲染多个echart图标,然后切换查看时,发现图表的宽度不正确 原因:在页面进行加载时,隐藏的图表找不到对应的div大小,所以默认给了一个大小.所以要做的 ...

  7. div中div水平垂直居中

    方法-1 img { vertical-align: middle; } div:before { content: ""; display: inline-block; widt ...

  8. cf 235C 后缀自动机

    题目大意 给定字符串\(S\)与\(n<=10^5\)个串\(x_1,x_2...x_n\)(总长\(\le10^6\)) 对于每个\(x_i\),输出有多少个\(S\)的子串与\(x_i\)循 ...

  9. hdu 4502 dp

    吉哥系列故事——临时工计划 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tot ...

  10. DataGrid关键字变色

    原文发布时间为:2009-05-01 -- 来源于本人的百度文章 [由搬家工具导入] private   void   DataGrid1_ItemDataBound(object   sender, ...