Android 系统启动之 zygote 进程启动分析三

更多 Android Framework 相关教程:yuandaimaahao.gitee.io/androidfram...

上节讲到 Zygote 进程的初始化过程将转到 Java 层,开始执行 ZygoteInit 的 main 函数了.

main 函数很长,我们分步查看:

java 复制代码
    @UnsupportedAppUsage
    public static void main(String argv[]) {

        ZygoteServer zygoteServer = null;

        // Mark zygote start. This ensures that thread creation will throw
        // an error.
        // 调用此方法后,虚拟机会拒绝线程的创建,如果此时创建会产生错误
        ZygoteHooks.startZygoteNoThreadCreation();

调用 startZygoteNoThreadCreation() 方法后,会设置一个标志位,此时运行时(虚拟机)会拒绝线程的创建,如果此时创建会产生错误。

接着往下看 main 函数:

java 复制代码
        // Zygote goes into its own process group.
        // 设置进程的 group id
        try {
            Os.setpgid(0, 0);
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to setpgid(0,0)", ex);
        }

        Runnable caller;
        try {
            // 记录一些时间信息,用于性能分析,和主要功能无关
            // Report Zygote start time to tron unless it is a runtime restart
            if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {
                MetricsLogger.histogram(null, "boot_zygote_init",
                        (int) SystemClock.elapsedRealtime());
            }

            // 记录 trace 信息
            String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
            TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
                    Trace.TRACE_TAG_DALVIK);
            bootTimingsTraceLog.traceBegin("ZygoteInit");

            // 启动DDMS虚拟机监控调试服务
            RuntimeInit.enableDdms();

这里主要是设置进程 groupid,记录一些时间和 trace 信息, 启动 DDMS 虚拟机监控调试服务,这些东西都是服务于程序的性能分析,与主要流程无关。

接着往下看 main 函数:

java 复制代码
            // 参数解析
            boolean startSystemServer = false;
            String zygoteSocketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                     // 开启系统服务
                    startSystemServer = true;
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    // 启动延迟加载
                    enableLazyPreload = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    // abi 类型,一个 CPU 对应一个 abi
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                     // 解析 socket name
                    zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    // 未知参数会抛出异常
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);

             // 没有指定 ABI 参数会抛出异常
            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }

            // In some configurations, we avoid preloading resources and classes eagerly.
            // In such cases, we will preload things prior to our first fork.
            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();
            }

            // Do an initial gc to clean up after startup
            bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
            gcAndFinalize();
            bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC

            bootTimingsTraceLog.traceEnd(); // ZygoteInit
            // Disable tracing so that forked processes do not inherit stale tracing tags from
            // Zygote.
            Trace.setTracingEnabled(false, 0);
  • 解析出参数
  • 参数不正确,直接排除异常
  • trace 相关的记录,用于程序的分析

接着往下看 main 函数:

java 复制代码
            // 一些与安全相关的初始化操作
            Zygote.initNativeState(isPrimaryZygote);
            // 呼应前面的startZygoteNoThreadCreation()方法
            // 通知虚拟机,现在可以在 zygote 进程中创建线程了
            ZygoteHooks.stopZygoteNoThreadCreation();

            // 初始化 Zygote 服务管理类,用来注册 socket 监听
            zygoteServer = new ZygoteServer(isPrimaryZygote);

            if (startSystemServer) {
                // fork SystemServer
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                 
                 // 如果 r 为空,说明是 zygote 进程,不做任何处理,继续执行

                if (r != null) {
                    // r 不为空,说明是孵化的子进程 systemserver,启动后直接返回
                    r.run();
                    return;
                }
            }
  • 执行一些与安全相关的初始化操作
  • 通知虚拟机,现在可以在 zygote 进程中创建线程了
  • 初始化 Zygote 服务管理类
  • 调用 forkSystemServer 方法,创建 SystemServer 进程

我们重点看看 forkSystemServer 的实现。

看之前先简单了解一下 linux 中的 fork 系统调用:

  • fork 会产生和当前进程完全一样的新进程
  • 在 fork 函数调用后
    • 新的进程将启动
    • 并和当前进程一起从 fork 函数返回
  • 关于 fork 的返回值
    • 新的进程返回 0
    • 当前进程返回新进程的 pid

看个例子:

cpp 复制代码
int main()
{
	pid_t fpid; //fpid 用于保存 fork 函数返回的值
	int count = 0;
	fpid = fork();
	if (fpid < 0) {
        printf("error in fork!");
    }
		
	else if (fpid == 0) {
		printf("我是子进程,我的 pid 是 %d/n", getpid());
		count++;
	} else {
		printf("我是父进程,我的 pid 是 %d/n", getpid());
		count++;
	}

	printf("统计结果是: %d/n", count);
	return 0;
}

有了上面的基础知识,我们就可以来看 forkSystemServer 方法的具体实现了:

java 复制代码
private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        long capabilities = posixCapabilitiesAsBits(
                OsConstants.CAP_IPC_LOCK,
                OsConstants.CAP_KILL,
                OsConstants.CAP_NET_ADMIN,
                OsConstants.CAP_NET_BIND_SERVICE,
                OsConstants.CAP_NET_BROADCAST,
                OsConstants.CAP_NET_RAW,
                OsConstants.CAP_SYS_MODULE,
                OsConstants.CAP_SYS_NICE,
                OsConstants.CAP_SYS_PTRACE,
                OsConstants.CAP_SYS_TIME,
                OsConstants.CAP_SYS_TTY_CONFIG,
                OsConstants.CAP_WAKE_ALARM,
                OsConstants.CAP_BLOCK_SUSPEND
        );
        /* Containers run without some capabilities, so drop any caps that are not available. */
        StructCapUserHeader header = new StructCapUserHeader(
                OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
        StructCapUserData[] data;
        try {
            data = Os.capget(header);
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to capget()", ex);
        }
        capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32);

        /* Hardcoded command line to start the system server */
        String args[] = {
                "--setuid=1000",
                "--setgid=1000",
                "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
                        + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
                "--capabilities=" + capabilities + "," + capabilities,
                "--nice-name=system_server",
                "--runtime-args",
                "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
                "com.android.server.SystemServer",
        };
        ZygoteArguments parsedArgs = null;

        int pid;

        try {
            parsedArgs = new ZygoteArguments(args);
            Zygote.applyDebuggerSystemProperty(parsedArgs);
            Zygote.applyInvokeWithSystemProperty(parsedArgs);

            boolean profileSystemServer = SystemProperties.getBoolean(
                    "dalvik.vm.profilesystemserver", false);
            if (profileSystemServer) {
                parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
            }

            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.mUid, parsedArgs.mGid,
                    parsedArgs.mGids,
                    parsedArgs.mRuntimeFlags,
                    null,
                    parsedArgs.mPermittedCapabilities,
                    parsedArgs.mEffectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) { // 子进程
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);
        }

        return null;
    }

准备好参数,然后接着调用 Zygote.forkSystemServer :

cpp 复制代码
    public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
        ZygoteHooks.preFork();
        // Resets nice priority for zygote process.
        resetNicePriority();
        int pid = nativeForkSystemServer(
                uid, gid, gids, runtimeFlags, rlimits,
                permittedCapabilities, effectiveCapabilities);
        // Enable tracing as soon as we enter the system_server.
        if (pid == 0) {
            Trace.setTracingEnabled(true, runtimeFlags);
        }
        ZygoteHooks.postForkCommon();
        return pid;
    }

private static native int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);    

这里进一步调用 nativeForkSystemServer native 方法,其对应的 JNI 方法如下:

cpp 复制代码
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
        JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
        jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
        jlong effective_capabilities) {
  std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()),
                   fds_to_ignore(fds_to_close);

  fds_to_close.push_back(gUsapPoolSocketFD);

  if (gUsapPoolEventFD != -1) {
    fds_to_close.push_back(gUsapPoolEventFD);
    fds_to_ignore.push_back(gUsapPoolEventFD);
  }

    // ForkCommon 对 fork 进程了包装,针对 Android 平台各个进程的共性最同意的初始化操作
  pid_t pid = ForkCommon(env, true,
                         fds_to_close,
                         fds_to_ignore);
  if (pid == 0) {
      SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
                       permitted_capabilities, effective_capabilities,
                       MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
                       false, nullptr, nullptr);
  } else if (pid > 0) {
      // The zygote process checks whether the child process has died or not.
      ALOGI("System server process %d has been created", pid);
      gSystemServerPid = pid;
      // There is a slight window that the system server process has crashed
      // but it went unnoticed because we haven't published its pid yet. So
      // we recheck here just to make sure that all is well.
      int status;
      if (waitpid(pid, &status, WNOHANG) == pid) {
          ALOGE("System server process %d has died. Restarting Zygote!", pid);
          RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!");
      }

      if (UsePerAppMemcg()) {
          // Assign system_server to the correct memory cgroup.
          // Not all devices mount memcg so check if it is mounted first
          // to avoid unnecessarily printing errors and denials in the logs.
          if (!SetTaskProfiles(pid, std::vector<std::string>{"SystemMemoryProcess"})) {
              ALOGE("couldn't add process %d into system memcg group", pid);
          }
      }
  }
  return pid;
}

ForkCommon 对 fork 进程了包装,针对 Android 平台各个进程的共性做了统一的初始化操作。

从这里可以看出 Zygote.forkSystemServer 实际是对 Native 层的 fork 调用的包装,用于启动一个 SystemServer 进程。

我们回到 private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) 函数中:

java 复制代码
private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        
        //......

        try {
            
            // ......

           // 执行完后会产生两个进程:zygote 和 systemserver ,两个进程同时开始执行,但是进程收到的 pid是不一样的
            pid = Zygote.forkSystemServer(
                    parsedArgs.mUid, parsedArgs.mGid,
                    parsedArgs.mGids,
                    parsedArgs.mRuntimeFlags,
                    null,
                    parsedArgs.mPermittedCapabilities,
                    parsedArgs.mEffectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) { // pid 等于 0,表示是子进程 SystemServer
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            // 子进程不需要 Socket 服务
            zygoteServer.closeServerSocket();
             // 通过反射找到SystemServer的main函数
            // 并包装到Runnable的run函数中
            return handleSystemServerProcess(parsedArgs);
        }

        return null;
    }

            // main 函数部分
            if (startSystemServer) {
                // fork SystemServer
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                 
                 // 如果 r 为空,说明是 zygote 进程,不做任何处理,继续执行

                if (r != null) {
                    // r 不为空,说明是孵化的子进程 systemserver,启动后直接返回
                    r.run();
                    return;
                }
            }   

这里调用 forkSystemServer 方法,完成新进程的创建,执行完后会产生两个进程:zygote 和 systemserver ,两个进程同时开始执行,但是进程收到的 pid是不一样的。对于子进程 (返回的 pid 值为 0)接下来会关闭 Socket 服务,然后通过反射找到 SystemServer 的 main 函数并包装到 Runnable 的 run 函数中返回给主函数。主函数调用 run 执行 SystemServer 的 main 函数。

接着 Zygote 进程继续执行剩下的 main 函数:

java 复制代码
            Log.i(TAG, "Accepting command socket connections");

            // The select loop returns early in the child process after a fork and
            // loops forever in the zygote.
            // 这部分是在zygote进程中执行
            // 此处进入一个无限循环中,处理zygote socket接收到数据
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
              // 请留意这部分,主要是给子进程用的
            // 子进程中是不需要在有zygote服务的
            // 所以这里的关闭理论上是为了在子进程中关闭无用的zygote服务
            if (zygoteServer != null) {

                zygoteServer.closeServerSocket();
            }
        }

        // We're in the child process and have exited the select loop. Proceed to execute the
        // command.
        if (caller != null) {
            caller.run();
        }
    }

这里会调用 zygoteServer.runSelectLoop 进入一个无限循环中,处理 zygote socket 接收到数据,这部分主要用于启动新的进程,具体细节我们会在下一节来讲。这里我们知道 runSelectLoop 方法 fork 一个新进程,然后在新进程中把 java main 函数包装为一个 runnable 对象然后返回。接在新进程中执行 zygoteServer.closeServerSocket 来关闭 socket 服务,最后调用 caller.run() 来执行新进程的主函数

参考资料

相关推荐
鸿蒙布道师32 分钟前
鸿蒙NEXT开发设备相关工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
darkchink1 小时前
[LevelDB]Block系统内幕解析-元数据块(Meta Block)&元数据索引块(MetaIndex Block)&索引块(Index Block)
android·java·服务器·c语言·数据库·c++·分布式
archko2 小时前
telophoto源码查看记录 三
android
QING6183 小时前
Activity和Fragment生命周期 —— 新手指南
android·面试·app
QING6183 小时前
Kotlin Result 类型扩展详解 —— 新手使用指南
android·kotlin·app
缘来的精彩3 小时前
kotlin 多个fragment beginTransaction容器添加使用
android·开发语言·kotlin
安小牛3 小时前
Kotlin 学习-集合
android·开发语言·学习·kotlin
顾林海3 小时前
Flutter 图片组件全面解析:从基础加载到高级应用
android·前端·flutter
molong9313 小时前
Android开发鸿蒙环境问题记录
android·华为·harmonyos
顾林海3 小时前
深度解析LinkedHashSet工作原理
android·java·面试