Skip to content

SystemServer接管

拆解 SystemServer 子进程的 umask、进程名、classpath、profile、invoke-with 和 zygoteInit 交接。

基于android-17.0.0_r1
AndroidSystemServerZygote源码阅读

SystemServer接管 ​

forkSystemServer() 只负责产生子进程和 ZygoteArguments;子进程真正成为 SystemServer,要经过 handleSystemServerProcess()。该函数在 fork 后、SystemServer.main() 前执行:设置文件创建掩码,写入进程名,读取 SYSTEMSERVERCLASSPATH,按 profile/invoke-with 条件决定是否 exec wrapper,最后把剩余参数和 classloader 交给 ZygoteInit.zygoteInit()。

1. 子进程初始状态 ​

源码文件:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

java
private static Runnable handleSystemServerProcess(
        ZygoteArguments parsedArgs) {
    // 新文件和目录默认只允许 owner 访问。
    Os.umask(S_IRWXG | S_IRWXO);

    if (parsedArgs.mNiceName != null) {
        Process.setArgV0(parsedArgs.mNiceName);
    }

    final String systemServerClasspath =
            Os.getenv("SYSTEMSERVERCLASSPATH");

umask 在子进程一开始生效,影响 SystemServer 后续创建的文件;它不是 SELinux domain 切换。setArgV0() 把进程名改成 system_server,供 proc、log 和调试工具识别。classpath 来自环境变量,空值并不自动等于错误,后续会走 boot classpath/默认 loader 路径。

2. 服务profile ​

java
if (systemServerClasspath != null) {
    if (shouldProfileSystemServer()
            && (Build.IS_USERDEBUG || Build.IS_ENG)) {
        try {
            final String standalone =
                    Os.getenv("STANDALONE_SYSTEMSERVER_JARS");
            final String paths = standalone != null
                    ? String.join(":", systemServerClasspath, standalone)
                    : systemServerClasspath;
            prepareSystemServerProfile(paths);
            SystemProperties.set(
                    "debug.tracing.profile_system_server", "1");
        } catch (Exception e) {
            Log.wtf(TAG,
                    "Failed to set up system server profile", e);
        }
    }
}

profile 只在 profilesystemserver 实验开关和 userdebug/eng 构建同时满足时执行;生产 user build 不走该分支。prepareSystemServerProfile() 通过 installd 准备 android 包的 profile,再由 VMRuntime.registerAppInfo() 注册 code paths。profile 初始化失败记录 wtf,但源码继续后续启动,不把性能优化失败等同于 SystemServer 身份或 classpath 失败。

3. Boot profile ​

java
if (shouldProfileBootClasspath()) {
    try {
        SystemProperties.set(
                "debug.tracing.profile_boot_classpath", "1");
    } catch (RuntimeException e) {
        Slog.e(TAG,
                "Failed to set debug.tracing.profile_boot_classpath", e);
    }
}

注释说明 Zygote 因权限限制不能设置该系统属性,必须在已经切换到 SystemServer 的子进程中设置。它与 preloadClasses() 中的 JIT counter 重置不同:前者打开后续 tracing 属性,后者决定预加载后从哪里重新开始统计。

4. invoke-with分支 ​

java
if (parsedArgs.mInvokeWith != null) {
    String[] args = parsedArgs.mRemainingArgs;
    if (systemServerClasspath != null) {
        String[] amendedArgs = new String[args.length + 2];
        amendedArgs[0] = "-cp";
        amendedArgs[1] = systemServerClasspath;
        System.arraycopy(args, 0, amendedArgs, 2, args.length);
        args = amendedArgs;
    }
    WrapperInit.execApplication(parsedArgs.mInvokeWith,
            parsedArgs.mNiceName,
            parsedArgs.mTargetSdkVersion,
            VMRuntime.getCurrentInstructionSet(),
            null, args);
    throw new IllegalStateException(
            "Unexpected return from WrapperInit.execApplication");
}

invoke-with 会把 SystemServer 交给 wrapper exec;如果有 classpath,则显式把 -cp 和路径插入 wrapper 参数。正常 wrapper 不应返回,返回本身被视为非法状态。该分支的安全许可已在 SS012 的 applyInvokeWithSecurityPolicy() 检查,本文只解释 fork 后消费者如何使用该参数。

5. 类加载交接 ​

java
ClassLoader cl = getOrCreateSystemServerClassLoader();
if (cl != null) {
    Thread.currentThread().setContextClassLoader(cl);
}

return ZygoteInit.zygoteInit(
        parsedArgs.mTargetSdkVersion,
        parsedArgs.mDisabledCompatChanges,
        parsedArgs.mEnabledCompatChanges,
        parsedArgs.mRemainingArgs,
        cl);

非 wrapper 路径先创建/缓存 SystemServer classloader,并设置当前主线程 context classloader,再进入 zygoteInit()。parsedArgs.mRemainingArgs 不包含 Zygote 控制选项,专门留给 RuntimeInit/SystemServer。classloader 是 SystemServer 子进程的 Java 类加载 owner;设置 context classloader 后,后续服务启动中的线程和反射代码才能使用正确路径。

6. 交给RuntimeInit ​

源码文件:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java、frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

java
public static Runnable zygoteInit(
        int targetSdkVersion,
        long[] disabledCompatChanges,
        long[] enabledCompatChanges,
        String[] argv,
        ClassLoader classLoader) {
    RuntimeInit.commonInit();
    return RuntimeInit.applicationInit(
            targetSdkVersion, disabledCompatChanges,
            enabledCompatChanges, argv, classLoader);
}

zygoteInit() 负责 RuntimeInit 的通用初始化和 applicationInit 入口;它并不直接创建 SystemServer 实例。RuntimeInit.applicationInit() 最终根据 argv 找到 com.android.server.SystemServer.main(),返回 Runnable,再由 ZygoteInit.main() 的子进程路径调用 caller.run()。

7. 失败边界与下一篇 ​

  • umask/setArgV0:影响文件和进程名,失败通常在 native syscall 或参数阶段暴露;
  • profile:仅影响调试/性能采集,准备失败不必然阻止启动;
  • classpath/classloader:类找不到会在 zygoteInit/反射阶段失败;
  • invoke-with:wrapper 不应返回,返回被视为非法状态;
  • zygoteInit:RuntimeInit 找不到目标 main 或 main 抛异常,SystemServer 不会进入 run()。
bash
# 输入 fork 后处理函数,输出 umask、classpath、profile、wrapper 和 zygoteInit。
rg -n "handleSystemServerProcess|SYSTEMSERVERCLASSPATH|prepareSystemServerProfile|mInvokeWith|getOrCreateSystemServerClassLoader|zygoteInit" \
  frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

# 输入 RuntimeInit 交接,输出 applicationInit 和静态 main 解析。
rg -n "zygoteInit|applicationInit|findStaticMain|SystemServer" \
  frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

下一篇将展开 zygoteInit() 与 RuntimeInit.applicationInit() 的完整反射链,说明 SystemServer.main 的 classloader、参数和异常处理;不会重复本文的 fork 后环境设置。