Skip to content

系统源码路线

沿 init、Zygote、SystemServer 的入口、状态和服务依赖建立可执行的 AOSP 源码阅读路线。

基于android-17.0.0_r1
Android源码阅读启动SystemServer

系统源码路线 ​

本文面向已经会使用 rg 和 Git 阅读 AOSP,理解 C++ 函数、Java 类、进程和 Binder 基本概念的读者。前置阅读可选 C++调用链、Java调用链 和 搜索调用链。

本文不提供按目录浏览的静态清单,而是回答一个阅读决策问题:当你想解释一个 Android 系统行为时,如何从启动链确定进程边界、入口函数、状态 owner 和下一处源码,而不会一开始陷入整个 AOSP?主线固定在 Android 17:PID 1 的多阶段 init、zygote 的预加载与 fork、SystemServer 的服务启动和 boot phase。读完后,读者应能从现象选择入口,沿最小源码路径走到消费者,并知道哪些结论仍需专题文章证明。

1. 路线问题 ​

系统启动路线的价值不在于记住所有服务名称,而在于给每次阅读建立四个坐标:

坐标要回答的问题Android 17 入口
进程谁拥有当前状态?init、zygote、system_server、app
阶段当前代码何时生效?first stage、SELinux setup、second stage、boot phase
入口从哪个函数开始反查?main、FirstStageMain、ZygoteInit.main、SystemServer.run
消费者结果最终谁读取?init action、Zygote socket、SystemService、Binder client

一个问题应先被改写成“现象 + 进程 + 阶段”。例如“Launcher 没启动”不应直接搜索 Launcher,而应先确认是 init 没启动 zygote、zygote 没 fork system_server、system_server 没完成 boot phase,还是 ActivityManager 的用户启动路径失败。

2. PID 1入口 ​

2.1 模式分发 ​

Android 17 的 system/core/init/main.cpp 把多个用户空间阶段集中在同一个 main 中。argv[0] 和 argv[1] 决定它进入 ueventd、subcontext、SELinux setup、second stage 或 first stage:

源码文件:system/core/init/main.cpp

cpp
int main(int argc, char** argv) {
    setpriority(PRIO_PROCESS, 0, -20);
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }
    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
            return SubcontextMain(argc, argv, &function_map);
        }
        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }
        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }
#if defined(FIRST_STAGE_INIT) || defined(RECOVERY)
    return FirstStageMain(argc, argv);
#else
    LOG(FATAL) << "Second-stage init requires an argument to main()";
#endif
}

关键事实是 exec 复用同一个 PID,而不是有多个 init 进程。阅读启动失败时,先把命令行参数和二进制模式分开;否则会把 SetupSelinux 或 SecondStageMain 的问题误归到首阶段挂载。

2.2 首阶段 ​

FirstStageMain 负责在 system 分区可用前建立最小用户空间,随后把控制交给 SELinux setup。它是物理存储和策略加载之间的边界:这里读的是 ramdisk 和 block device,不能假设普通 system 文件已经可用。

源码文件:system/core/init/first_stage_init.cpp

cpp
int FirstStageMain(int argc, char** argv) {
    boot_clock::time_point start_time = boot_clock::now();
    std::vector<std::pair<std::string, int>> errors;
    umask(0);
    CHECKCALL(clearenv());
    CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));
    CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
    CHECKCALL(mkdir("/dev/pts", 0755));
    CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
    CHECKCALL(mount("proc", "/proc", "proc", 0,
                    "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
    CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
    CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));
    // ... first-stage mount, module loading, and ramdisk handoff ...
}

实际挂载和设备映射逻辑继续位于 first_stage_mount.cpp。入口负责阶段分发,资源算法进入下一个 owner,不应把所有首阶段代码复制到路线图中。

2.3 策略阶段 ​

SetupSelinux 是首阶段和 second stage 之间的切换点。它加载已挂载分区上的 SELinux policy,并通过 execv 重新进入带 second_stage 参数的 init。于是同一 PID 1 在新策略下继续运行。

源码文件:system/core/init/selinux.cpp

cpp
int SetupSelinux(char** argv) {
    SetStdioToDevNull(argv);
    InitKernelLogging(argv);
    SelinuxSetupKernelLogging();
    bool use_overlays = EarlySetupOverlays();
    if (IsMicrodroid()) {
        LoadSelinuxPolicyMicrodroid();
    } else {
        LoadSelinuxPolicyAndroid();
    }
    SelinuxSetEnforcement();
    // ... restorecon and overlay handling ...
    const char* path = "/system/bin/init";
    const char* args[] = {path, "second_stage", nullptr};
    execv(path, const_cast<char**>(args));
    PLOG(FATAL) << "execv failed";
}

源码中的 helper 会随构建变体组合,但阅读重点稳定:策略加载、文件恢复标签、exec 复用 PID。遇到 AVC 应转到 SELinux策略链,不要把它当作 init action 语法问题。

3. Second stage ​

3.1 rc解析 ​

SecondStageMain 在策略和基本文件系统就绪后创建 init 的核心对象,解析 init.rc、vendor rc、odm rc 和 product rc,并开始执行 action。这里的 owner 是 init parser 和 service manager,不是 zygote。

源码文件:system/core/init/init.cpp

cpp
int SecondStageMain(int argc, char** argv) {
    if (REBOOT_BOOTLOADER_ON_PANIC && !AttemptingToBootNewSlot()) {
        InstallRebootSignalHandlers();
    }
    SetStdioToDevNull(argv);
    InitKernelLogging(argv);
    LOG(INFO) << "init second stage started!";
    SelinuxSetupKernelLogging();
    PropertyInit();
    UmountSecondStageRes();
    MountExtraFilesystems();
    SelabelInitialize();
    SelinuxRestoreContext();
}

读真实源码时应把上面抽象回 ActionManager、ServiceList、Epoll 的实际定义。学习结果不是记住三个 trigger,而是知道启动服务要从 rc 的 service 声明回到 Service::Start、fork、exec 和子进程回收。

3.2 服务状态 ​

init 的 service owner 持有启动标志、PID、重启计数和 socket/namespace 配置。服务失败后,init 根据 service 状态和 class/trigger 规则决定重启或停止。

源码文件:system/core/init/service.cpp

cpp
Result<void> Service::Start() {
    auto reboot_on_failure = make_scope_guard([this] {
        if (on_failure_reboot_target_) {
            trigger_shutdown(*on_failure_reboot_target_);
        }
    });
    if (is_updatable() && !IsDefaultMountNamespaceReady()) {
        ServiceList::GetInstance().DelayService(*this);
        return Error() << "Cannot start an updatable service before APEX configs are loaded";
    }
    bool disabled = (flags_ & (SVC_DISABLED | SVC_RESET));
    ResetFlagsForStart();
    if (flags_ & SVC_RUNNING) {
        if ((flags_ & SVC_ONESHOT) && disabled) {
            flags_ |= SVC_RESTART;
        }
        reboot_on_failure.Disable();
        return {};
    }
}

遇到 native daemon 未启动,下一步应搜其 rc 声明和 Service::Start,而不是直接读 daemon 的业务 main。

4. Zygote入口 ​

4.1 启动参数 ​

zygote 是 init 通过 rc 启动的 app_process Java runtime。进入 ZygoteInit.main 后,它解析 start-system-server、ABI 列表和 socket 名称。

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

java
public static void main(String[] argv) {
    RuntimeInit.preForkInit();
    boolean startSystemServer = false;
    String zygoteSocketName = "zygote";
    String abiList = null;
    for (int i = 1; i < argv.length; i++) {
        if ("start-system-server".equals(argv[i])) {
            startSystemServer = true;
        } else if (argv[i].startsWith(ABI_LIST_ARG)) {
            abiList = argv[i].substring(ABI_LIST_ARG.length());
        } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
            zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
        }
    }
    preload(bootTimingsTraceLog);
    Zygote.initNativeState(isPrimaryZygote);
    zygoteServer = new ZygoteServer(isPrimaryZygote);
    if (startSystemServer) {
        Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
        if (r != null) {
            r.run();
            return;
        }
    }
    zygoteServer.runSelectLoop(abiList);
}

预加载是 zygote 的状态准备,runSelectLoop 是后续应用 fork 的消费者。SystemServer 的服务注册不属于 zygote;zygote 只负责准备运行时、fork 和监听命令 socket。

4.2 Fork边界 ​

forkSystemServer 构造 uid、gid、capability、nice name 和 com.android.server.SystemServer 参数,再调用 native Zygote.forkSystemServer。返回值决定父子路径:

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

java
private static Runnable forkSystemServer(String abiList, String socketName,
        ZygoteServer zygoteServer) {
    String[] args = {
        "--setuid=1000",
        "--setgid=1000",
        "--nice-name=system_server",
        "--runtime-args",
        "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
        "com.android.server.SystemServer",
    };
    int pid = Zygote.forkSystemServer(
            parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
            parsedArgs.mRuntimeFlags, null,
            parsedArgs.mPermittedCapabilities,
            parsedArgs.mEffectiveCapabilities);
    if (pid == 0) {
        zygoteServer.closeServerSocket();
        return handleSystemServerProcess(parsedArgs);
    }
    return null;
}

父进程返回 null 并继续 select loop,子进程返回 Runnable 并运行 SystemServer。忽略返回值会把 system_server 错看成 zygote 内执行的普通 Java 方法。

5. SystemServer阶段 ​

5.1 主循环 ​

SystemServer 的 Java 入口很短,真正的路线从 run 开始。它建立 Looper、Binder 线程上限、异步初始化线程池和 native library,再启动服务阶段。

源码文件:frameworks/base/services/java/com/android/server/SystemServer.java

java
public static void main(String[] args) {
    new SystemServer().run();
}

private void run() {
    Looper.prepareMainLooper();
    BinderInternal.setMaxThreads(sMaxBinderThreads);
    SystemServerInitThreadPool.start();
    System.loadLibrary("android_servers");
    startBootstrapServices(t);
    startCoreServices(t);
    startOtherServices(t);
    startApexServices(t);
    updateWatchdogTimeout(t);
    CriticalEventLog.getInstance().logSystemServerStarted();
    Looper.loop();
}

异步线程池使部分昂贵初始化并行,但服务依赖仍由显式阶段和 boot phase 控制。读服务启动问题时,先看阶段,再看异步任务何时提交和消费。

5.2 Bootstrap ​

startBootstrapServices 放置最早的核心 owner,例如 Watchdog、PlatformCompat、Installer、ActivityManagerService 和 PackageManagerService:

源码文件:frameworks/base/services/java/com/android/server/SystemServer.java

java
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
    t.traceBegin("startBootstrapServices");
    Watchdog watchdog = Watchdog.getInstance();
    watchdog.start();
    PlatformCompat platformCompat = new PlatformCompat(mSystemContext);
    ServiceManager.addService(Context.PLATFORM_COMPAT_SERVICE, platformCompat);
    mSystemServiceManager.startService(Installer.class);
    mActivityManagerService = mSystemServiceManager
            .startService(ActivityManagerService.Lifecycle.class)
            .getService();
    mPackageManagerService = PackageManagerService.main(
            mSystemContext, installer, domainVerificationService,
            mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF);
    t.traceEnd();
}

这组服务的共同特征是后续服务需要它们提供进程、包、权限或安装基础设施。

5.3 Core与Other ​

startCoreServices 启动系统配置、电池、UsageStats、WebView、设备状态和统计服务;startOtherServices 创建面向功能的服务,并处理显示、输入、窗口和 boot phase。

源码文件:frameworks/base/services/java/com/android/server/SystemServer.java

java
private void startCoreServices(@NonNull TimingsTraceAndSlog t) {
    t.traceBegin("startCoreServices");
    mSystemServiceManager.startService(SystemConfigService.class);
    mSystemServiceManager.startService(BatteryService.class);
    mSystemServiceManager.startService(UsageStatsService.class);
    if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
        mWebViewUpdateService =
                mSystemServiceManager.startService(WebViewUpdateService.class);
    }
    t.traceEnd();
}

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    t.traceBegin("startOtherServices");
    WindowManagerService wm = WindowManagerService.main(
            context, inputManager, !mFirstBoot, ...);
    ServiceManager.addService(Context.WINDOW_SERVICE, wm);
    mActivityManagerService.setWindowManager(wm);
    wm.onInitReady();
    t.traceEnd();
}

Other services 不是简单的“最后启动”。它们经常在局部依赖满足后通过 startBootPhase、onInitReady 或异步线程池完成握手。

5.4 就绪信号 ​

SystemServer 捕获启动异常并记录 Failure starting system services;成功后记录 system server ready 统计事件,随后进入 Looper:

源码文件:frameworks/base/services/java/com/android/server/SystemServer.java

java
try {
    t.traceBegin("StartServices");
    startBootstrapServices(t);
    startCoreServices(t);
    startOtherServices(t);
    startApexServices(t);
    updateWatchdogTimeout(t);
    CriticalEventLog.getInstance().logSystemServerStarted();
} catch (Throwable ex) {
    Slog.e("System",
            "************ Failure starting system services", ex);
    throw ex;
} finally {
    t.traceEnd();
}

这个边界把“服务构造失败”和“系统已经可响应”分开。

6. 阅读分支 ​

不要按“init、zygote、SystemServer 全部读完”推进。根据现象选择分支:

现象第一入口第二入口关键消费者
服务没启动rc 的 serviceService::Startinit ServiceList
AVC deniedscontext/tcontext.te、file_contexts内核 SELinux
app 进程没创建ZygoteInit.mainZygoteServer、fork 参数ActivityManager
system_server 崩溃SystemServer.run对应 start 阶段Watchdog/日志
服务已构造但未 readystartBootPhaseonBootPhase/onInitReadySystemServiceManager
Binder 调用失败接口/AIDL发送者和 Stub服务消费者

路线图只有在每行都能落到真实入口时才有用。不要把 Framework 或 HAL 当作入口名;它们是范围,不是符号。

7. 策略边界 ​

从本文列出的源码可以直接看到:

  • init main 根据 argv 分发多个阶段,并在 first/SELinux/second stage 间复用 PID;
  • zygote 预加载运行时后创建 ZygoteServer,通过 forkSystemServer 分出 system_server;
  • SystemServer 以 bootstrap/core/other/apex 阶段启动服务,并在异常时终止启动;
  • 服务问题应根据进程和阶段选择不同源码入口。

本文没有声称所有设备的 rc、vendor service 或启动耗时都相同;没有声称 SystemServer 中每个服务都严格串行;也没有把 Launcher、用户解锁和 boot completed 的完整链路纳入本文。它们需要进入 ActivityManager、PackageManager、WindowManager 或用户生命周期专题。

8. 阅读验证 ​

在 Android 源码 checkout 中执行:

bash
rg -n "return (FirstStageMain|SetupSelinux|SecondStageMain)" \
  system/core/init/main.cpp
rg -n "forkSystemServer|startSystemServer|runSelectLoop" \
  frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
rg -n "startBootstrapServices|startCoreServices|startOtherServices|startApexServices" \
  frameworks/base/services/java/com/android/server/SystemServer.java
rg -n "se_neverallow_test|domain_auto_trans" \
  system/sepolicy/Android.bp system/sepolicy/private

练习:假设 system_server 已出现,但某个服务没有对外提供 Binder。先判断它属于哪个 start 阶段,再搜索该服务的 onStart、ServiceManager.addService 或 onBootPhase,最后检查启动异常和依赖 phase。这个练习用于检查你是否能从现象选择入口,不等于覆盖系统启动的全部实现。

9. 边界 ​

从 init 到 SystemServer 的路线应被当作导航坐标,而不是替代专题。每到一个边界都要记录:当前进程是谁、状态由谁拥有、下一阶段何时生效、失败由谁清理。沿这四个问题推进,才能从启动入口继续进入 Binder、服务状态、SELinux、HAL 或应用生命周期,而不会把目录浏览误当成源码理解。