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() 来执行新进程的主函数

参考资料

相关推荐
500了6 小时前
Kotlin基本知识
android·开发语言·kotlin
人工智能的苟富贵7 小时前
Android Debug Bridge(ADB)完全指南
android·adb
小雨cc5566ru12 小时前
uniapp+Android面向网络学习的时间管理工具软件 微信小程序
android·微信小程序·uni-app
bianshaopeng13 小时前
android 原生加载pdf
android·pdf
hhzz13 小时前
Linux Shell编程快速入门以及案例(Linux一键批量启动、停止、重启Jar包Shell脚本)
android·linux·jar
火红的小辣椒14 小时前
XSS基础
android·web安全
勿问东西16 小时前
【Android】设备操作
android
五味香16 小时前
C++学习,信号处理
android·c语言·开发语言·c++·学习·算法·信号处理
图王大胜18 小时前
Android Framework AMS(01)AMS启动及相关初始化1-4
android·framework·ams·systemserver
工程师老罗20 小时前
Android Button “No speakable text present” 问题解决
android