Zygote服务
本文面向已经读过内置命令下和init.rc主配置的读者。前文已经说明 start zygote 只调用 Service::Start(),本文继续追踪这个服务对象到底如何把一行 rc 变成一个带 fd、uid、nice、task profile 和 Java 参数的进程。
旧稿把 init.zygote64_32.rc 当成两份完整 service 定义,并把 audio、camera、media 等服务说成“fork 自 Zygote”。Android 17 的实际文件是“主配置 import + secondary service”结构;这些 native daemon 并不因为被 onrestart 重启就成为 Zygote 子进程。本文把每个结论拆成 owner、消费者和生效时机:init 负责创建资源和 fork,app_process 负责把参数交给 ZygoteInit,Java Zygote 负责预加载、system_server fork 和客户端连接。
1. 配置家族
1.1 属性选择
源码文件:system/core/rootdir/init.rc
import /init.environ.rc
import /system/etc/init/hw/init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /system/etc/init/hw/init.usb.configfs.rc
import /system/etc/init/hw/init.${ro.zygote}.rcro.zygote 不是服务名,而是决定要导入哪一个 rc 文件的属性值。它把“选择 64 位/32 位/双 Zygote”放在 Parser 输入层;真正的服务名仍由被导入文件中的 service zygote 和 service zygote_secondary 定义。导入成功只表示 service definition 进入 ServiceList,不表示进程已经 fork。
1.2 构建安装
源码文件:system/core/rootdir/Android.bp
相关函数/类型:prebuilt_etc
prebuilt_etc {
name: "init.zygote64.rc",
src: "init.zygote64.rc",
sub_dir: "init/hw",
}
prebuilt_etc {
name: "init.zygote64_32.rc",
src: "init.zygote64_32.rc",
sub_dir: "init/hw",
}运行时路径是 /system/etc/init/hw/init.zygote64.rc 和 /system/etc/init/hw/init.zygote64_32.rc。不要把源码目录 system/core/rootdir/ 当作设备上的路径,也不要用旧稿中的 init.zygote32_64.rc 作为 Android 17 AOSP 必然存在的文件;源码中明确列出的文件是 init.zygote32.rc、init.zygote64.rc 和 init.zygote64_32.rc。
1.3 双Zygote的复用
源码文件:system/core/rootdir/init.zygote64_32.rc
import /system/etc/init/hw/init.zygote64.rc
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
class main
priority -20
user root
group root readproc reserved_disk
socket zygote_secondary stream 660 root system
socket usap_pool_secondary stream 660 root system
onrestart restart zygote
task_profiles ProcessCapacityHigh MaxPerformance
rlimit nofile 32768 32768主 64 位 Zygote 的完整定义来自被 import 的 init.zygote64.rc;这个文件只追加 32 位 secondary service。这样解析后的 ServiceList 有两个 service,但配置来源不是两份重复文本。--enable-lazy-preload 只传给 secondary 的 app_process32,是否预加载由 Java ZygoteInit 解析该参数决定。
2. Service解析
2.1 主定义
源码文件:system/core/rootdir/init.zygote64.rc
相关函数/类型:service zygote
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart write /sys/power/wake_lock zygote_kwl
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart --only-if-running media.tuner
onrestart restart netd
onrestart restart wificond
task_profiles ProcessCapacityHigh MaxPerformance
critical window=${zygote.critical_window.minute:-off} target=zygote-fatal这一段不是一个 shell 脚本。service 首行的第一个 token 是 Service 名,后续 token 保存为 args_;缩进选项被 ServiceParser 分派到不同字段。比如 priority 写入 proc_attr_.priority,socket 追加 SocketDescriptor,onrestart 追加一个内部 Action,critical 设置崩溃策略字段。
2.2 解析分派
源码文件:system/core/init/service_parser.cpp
相关函数/类型:GetParserMap
const KeywordMap<ServiceParser::OptionParser>& ServiceParser::GetParserMap() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
[[clang::no_destroy]] static const KeywordMap<OptionParser> parser_map = {
{"class", {1, kMax, &ServiceParser::ParseClass}},
{"critical", {0, 2, &ServiceParser::ParseCritical}},
{"group", {1, NR_SVC_SUPP_GIDS + 1, &ServiceParser::ParseGroup}},
{"onrestart", {1, kMax, &ServiceParser::ParseOnrestart}},
{"priority", {1, 1, &ServiceParser::ParsePriority}},
{"rlimit", {3, 3, &ServiceParser::ParseProcessRlimit}},
{"socket", {3, 6, &ServiceParser::ParseSocket}},
{"task_profiles", {1, kMax, &ServiceParser::ParseTaskProfiles}},
{"user", {1, 1, &ServiceParser::ParseUser}},
};
return parser_map;
}代码是教学摘录,省略了同一 map 中与 Zygote 无关的 option;参数范围和函数指针来自 Android 17 实际 GetParserMap()。这张表解释了为什么 service option 错误会在解析阶段被发现,而不是等 Zygote fork 后才暴露。
2.3 结束校验
源码文件:system/core/init/service_parser.cpp
相关函数/类型:EndSection
Result<void> ServiceParser::EndSection() {
if (!service_) return {};
if (service_->proc_attr_.parsed_uid == std::nullopt) {
return Error() << "No user specified for service '"
<< service_->name() << "', so it would have been root.";
}
if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_R__) {
if ((service_->flags() & SVC_CRITICAL) != 0 &&
(service_->flags() & SVC_ONESHOT) != 0) {
return Error() << "service '" << service_->name()
<< "' can't be both critical and oneshot";
}
}
service_list_->AddService(std::move(service_));
return {};
}user root 不是可有可无的注释,它让 service 定义通过“未指定 uid”校验;critical 与 oneshot 的互斥也在这里落地。Service 被加入 ServiceList 后,后续 class_start main 或 start zygote 才能找到它。
3. 命令行入口
3.1 init保存什么
相关源码:
system/core/init/service.cppServiceNotifyStateChange
Service::Service(const std::string& name, Subcontext* subcontext_for_restart_commands,
const std::string& filename, const std::vector<std::string>& args)
: name_(name),
classnames_({"default"}),
flags_(0),
pid_(0),
crash_count_(0),
subcontext_(subcontext_for_restart_commands),
onrestart_(false, subcontext_for_restart_commands,
"<Service '" + name + "' onrestart>", 0,
"onrestart", {}),
args_(args),
filename_(filename) {}
void Service::NotifyStateChange(const std::string& new_state) const {
std::string prop_name = "init.svc." + name_;
SetProperty(prop_name, new_state);
if (new_state == "running") {
SetProperty("ro.boottime." + name_,
std::to_string(time_started_.time_since_epoch().count()));
}
}Service 保存的是“将来如何启动”的数据结构:名字、class、flags、进程属性、socket 描述、onrestart Action 和 argv。init.svc.zygote=running 是 init 在父进程确认启动状态后写出的状态,不是 Java ZygoteServer 已经开始 accept 的证明。
3.2 Service::Start
源码文件:system/core/init/service.cpp
相关函数/类型:Service::Start
Result<void> Service::Start() {
if (is_updatable() && !IsDefaultMountNamespaceReady()) {
ServiceList::GetInstance().DelayService(*this);
return Error() << "Cannot start an updatable service '" << name_
<< "' before configs from APEXes are all loaded.";
}
bool disabled = (flags_ & (SVC_DISABLED | SVC_RESET));
ResetFlagsForStart();
if (flags_ & SVC_RUNNING) {
return {};
}
auto expanded_path = ExpandProps(args_[0]);
if (!expanded_path.ok()) {
flags_ |= SVC_DISABLED;
return expanded_path.error();
}
args_[0] = *expanded_path;
std::string scon = seclabel_;
if (scon.empty()) {
auto result = ComputeContextFromExecutable(args_[0]);
if (!result.ok()) return result.error();
scon = *result;
}
std::vector<Descriptor> descriptors;
for (const auto& socket : sockets_) {
if (auto result = socket.Create(scon); result.ok()) {
descriptors.emplace_back(std::move(*result));
}
}
pid_t pid = namespaces_.flags ? clone(nullptr, nullptr,
namespaces_.flags | SIGCHLD, nullptr)
: fork();这段路径有三个重要的生效时机:APEX updatable service 可能先被 DelayService;socket 在 fork 前由 init 创建;fork() 返回父子两条路径。Service::Start() 返回成功时,父进程已经记录 pid 并进入 running 状态,但子进程是否成功 execv() 还要由 SIGCHLD/reap 路径继续确认。
3.3 子进程执行
源码文件:system/core/init/service.cpp
相关函数/类型:RunService
void Service::RunService(const std::vector<Descriptor>& descriptors,
InterprocessFifo cgroups_activated,
InterprocessFifo setsid_finished) {
EnterNamespaces(namespaces_, name_, mount_namespace_);
if (auto result = ApplyTaskProfiles(task_profiles_); !result.ok()) {
LOG(ERROR) << "failed to set task profiles";
}
SetProcessAttributesAndCaps(std::move(setsid_finished));
if (!ExpandArgsAndExecv(args_, sigstop_)) {
PLOG(ERROR) << "cannot execv('" << args_[0] << "')";
}
}RunService 依次处理 namespace、task profile、uid/gid/capability/SELinux context 和 exec。priority -20 在 SetProcessAttributes 中变成进程调度属性;user root 只描述 service 初始 uid,不能据此推断所有由 Zygote fork 的 App 仍然是 root。
4. Socket交接
4.1 rc参数
源码文件:system/core/init/service_parser.cpp
相关函数/类型:ParseSocket
Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) {
SocketDescriptor socket;
socket.name = std::move(args[1]);
auto types = Split(args[2], "+");
if (types[0] == "stream") {
socket.type = SOCK_STREAM;
} else if (types[0] == "dgram") {
socket.type = SOCK_DGRAM;
} else if (types[0] == "seqpacket") {
socket.type = SOCK_SEQPACKET;
} else {
return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket'";
}
socket.perm = strtol(args[3].c_str(), nullptr, 8);
if (args.size() > 4) socket.uid = DecodeUid(args[4]).value();
if (args.size() > 5) socket.gid = DecodeUid(args[5]).value();
socket.context = args.size() > 6 ? args[6] : "";
service_->sockets_.emplace_back(std::move(socket));
return {};
}真实函数还检查 passcred/listen decoration、重复 socket、uid/gid 解析和错误路径;摘录突出数据流。socket zygote stream 660 root system 的消费者是后续 Java Zygote.createManagedSocketFromInitSocket(),不是 init 自己接收 fork 请求。
4.2 创建时机
源码文件:system/core/init/service_utils.cpp
相关函数/类型:SocketDescriptor::Create
Result<Descriptor> SocketDescriptor::Create(const std::string& global_context) const {
const auto& socket_context = context.empty() ? global_context : context;
auto result = CreateSocket(name, type | SOCK_CLOEXEC, passcred, listen,
perm, uid, gid, socket_context);
if (!result.ok()) return result.error();
return Descriptor(ANDROID_SOCKET_ENV_PREFIX + name, unique_fd(*result));
}CreateSocket() 创建 /dev/socket/<name> 并设置权限、所有者和 SELinux context;返回的 fd 通过 ANDROID_SOCKET_<name> 环境变量交给子进程。这个 fd 继承发生在 exec 前,ZygoteServer 才能从 init 创建的 fd 接管 socket。若 socket 创建失败,Service::Start() 会记录失败并继续处理其他 descriptor;不能把“rc 中有 socket 行”当成“设备上 socket 一定存在”。
4.3 Java接管
源码文件:frameworks/base/core/java/com/android/internal/os/Zygote.java
相关函数/类型:createManagedSocketFromInitSocket
static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
FileDescriptor fd = new FileDescriptor();
fd.setInt$(Integer.parseInt(System.getenv(fullSocketName)));
return new LocalServerSocket(fd);
}源码文件:frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
public ZygoteServer(boolean isPrimaryZygote) {
mIsPrimaryZygote = isPrimaryZygote;
mZygoteSocket = Zygote.createManagedSocketFromInitSocket(
isPrimaryZygote ? Zygote.PRIMARY_SOCKET_NAME
: Zygote.SECONDARY_SOCKET_NAME);
if (isPrimaryZygote) {
mUsapPoolSocket = Zygote.createManagedSocketFromInitSocket(
Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
} else {
mUsapPoolSocket = Zygote.createManagedSocketFromInitSocket(
Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
}
}这里的“交接”不是重新 bind 一个同名 Unix socket:Java 侧消费的是 init 已经打开的 fd。若环境变量缺失或 fd 无效,Java 侧构造 LocalServerSocket 会失败;这类故障发生在 Service 已被 init 标记 running 之后,因此 init.svc.zygote 与“Zygote 可接受请求”是两个不同时间点。
5. 主次协作
5.1 主Zygote
源码文件:system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
task_profiles ProcessCapacityHigh MaxPerformance主 Zygote 的 --start-system-server 进入 app_process 参数列表,后续由 Java ZygoteInit 决定是否 fork system_server。class main 与 on zygote-start 的 start zygote 是两个不同层次:前者是 class 归属,后者是实际启动触发。
5.2 Secondary
相关源码:
system/core/rootdir/init.zygote64_32.rcsystem/core/rootdir/init.zygote32.rc
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
class main
priority -20
user root
group root readproc reserved_disk
socket zygote_secondary stream 660 root system
socket usap_pool_secondary stream 660 root system
onrestart restart zygote
task_profiles ProcessCapacityHigh MaxPerformance
rlimit nofile 32768 32768secondary 没有 --start-system-server,也使用独立的 socket 和 USAP socket;32 位 ABI 还把 nofile 上限固定为 32768,因为 ilp32 stdio 实现使用 short 保存 fd。它不是“主 Zygote 的低配副本”,而是另一套 Java ZygoteServer,承担支持 32 位 ABI 的 fork 请求。
5.3 等待另一端
相关源码:
frameworks/base/core/java/com/android/internal/os/ZygoteInit.javaforkSystemServer
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
return handleSystemServerProcess(parsedArgs);
}system_server 子进程在进入自己的处理前,若设备存在另一套 ABI Zygote,会等待另一端连接可用。这个等待发生在 Java 子进程路径,不是 init 的 start zygote_secondary 同步等待;两者的 owner 和日志位置不同。
图中 Z64/Z32 是 init 的 Service,J64/J32 是 Java Zygote;两者不能用同一个“zygote 进程”概念代替。system_server 只从带 --start-system-server 的主 Zygote fork,secondary 主要提供另一 ABI 的应用 fork 能力。
6. Java入口
6.1 app_process解析
源码文件:frameworks/base/cmds/app_process/app_main.cpp
相关函数/类型:main
bool zygote = false;
bool startSystemServer = false;
String8 niceName;
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName = (arg + 12);
}
}
if (zygote) {
if (startSystemServer) {
args.add(String8("start-system-server"));
}
args.add(String8("--abi-list=") + abiList);
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
}摘录省略了真实代码中的 option 扫描、ABI property 读取和剩余参数复制;保留的是 rc 参数如何变成 Java main 参数。-Xzygote 是 VM 选项,--zygote 和 --start-system-server 是 app_process 内部参数,--socket-name=... 则作为剩余参数继续传给 ZygoteInit。
6.2 ZygoteInit参数
源码文件:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
相关函数/类型:main
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=")) {
abiList = argv[i].substring("--abi-list=".length());
} else if (argv[i].startsWith("--socket-name=")) {
zygoteSocketName = argv[i].substring("--socket-name=".length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}这段代码把两个容易混淆的选择拆开:start-system-server 决定是否进入 forkSystemServer();--enable-lazy-preload 决定是否跳过启动时 preload();socket name 决定连接哪一组 init fd。secondary 的“32 位”来自 app_process32 和 ABI list,不是 Java 代码里硬编码一个 secondary=true。
6.3 预加载与循环
源码文件:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
相关函数/类型:main
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
preload(bootTimingsTraceLog);
bootTimingsTraceLog.traceEnd();
}
Zygote.initNativeState(isPrimaryZygote);
ZygoteHooks.stopZygoteNoThreadCreation();
zygoteServer = new ZygoteServer(isPrimaryZygote);
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
if (r != null) {
r.run();
return;
}
}
caller = zygoteServer.runSelectLoop(abiList);父进程在 forkSystemServer() 返回 null 后继续进入 runSelectLoop();子进程得到非 null Runnable,关闭 Zygote server socket 并进入 system_server 处理。start zygote 的 init 成功、app_process 进入 Java、完成 preload、开始 accept、system_server fork 是四个不同时间点。
图中需要区分 init.svc.zygote 的写入点和 Java runSelectLoop():前者位于 init 父进程的 Start() 路径,后者位于更后的子进程执行路径。现场只看到前者时,不能直接判断 Zygote socket 已经可用。
7. 失败重启
7.1 onrestart命令
源码文件:system/core/init/service_parser.cpp
相关函数/类型:ParseOnrestart
Result<void> ServiceParser::ParseOnrestart(std::vector<std::string>&& args) {
args.erase(args.begin());
int line = service_->onrestart_.NumCommands() + 1;
if (auto result = service_->onrestart_.AddCommand(std::move(args), line);
!result.ok()) {
return Error() << "cannot add Onrestart command: " << result.error();
}
return {};
}onrestart 不是“启动后立即执行”的 action,而是存进 Service 自己的 onrestart_ Action。只有服务被 reap 并进入重启路径时,Service::Reap() 才会调用 onrestart_.ExecuteAllCommands()。
7.2 Zygote的清理
源码文件:system/core/init/service.cpp
相关函数/类型:Service::Reap
for (const auto& socket : sockets_) {
if (socket.persist) continue;
auto path = ANDROID_SOCKET_DIR "/" + socket.name;
unlink(path.c_str());
}
if ((siginfo.si_code != CLD_EXITED || siginfo.si_status != 0) &&
on_failure_reboot_target_) {
trigger_shutdown(*on_failure_reboot_target_);
}
flags_ &= (~SVC_RESTART);
flags_ |= SVC_RESTARTING;
onrestart_.ExecuteAllCommands();
NotifyStateChange("restarting");重启路径先清理非 persistent socket,再执行 failure reboot 或 onrestart 命令,最后更新 init.svc.*。Zygote rc 的 onrestart restart audioserver 等是 init 层的恢复动作,不表示这些服务是 Zygote 的 Unix 子进程;它们是独立 Service,重启是为了恢复跨进程依赖状态。
7.3 临界崩溃
相关源码:
system/core/init/service_parser.cppParseCriticalsystem/core/init/service.cppService::Reap
Result<void> ServiceParser::ParseCritical(std::vector<std::string>&& args) {
std::optional<std::string> fatal_reboot_target;
std::optional<std::chrono::minutes> fatal_crash_window;
for (auto it = args.begin() + 1; it != args.end(); ++it) {
auto arg = android::base::Split(*it, "=");
if (arg[0] == "target") {
fatal_reboot_target = arg[1];
} else if (arg[0] == "window") {
auto window = ExpandProps(arg[1]);
if (!window.ok()) return window.error();
if (*window == "off") return {};
int minutes;
if (!ParseInt(*window, &minutes, 0)) return Error() << "invalid window";
fatal_crash_window = std::chrono::minutes(minutes);
}
}
service_->fatal_reboot_target_ = *fatal_reboot_target;
service_->fatal_crash_window_ = *fatal_crash_window;
service_->flags_ |= SVC_CRITICAL;
return {};
}这段摘录省略了 Android 17 对未知参数、可选值和空 optional 的完整错误处理。实际 critical window=${zygote.critical_window.minute:-off} target=zygote-fatal 默认窗口为 off;只有属性展开为整数时才启用窗口。Reap() 在服务异常退出、未完成启动或崩溃次数超过阈值时,结合 sys.boot_completed、窗口和 24 小时节流决定是否触发 fatal reboot target。
8. 启动检查
8.1 解析测试
相关源码:
system/core/init/service_test.cppService::Start
读者可以用以下断言检查自己是否真正读懂了配置:
| 检查项 | 源码或测试入口 | 未覆盖内容 |
|---|---|---|
socket zygote 变成 descriptor | ParseSocket → SocketDescriptor::Create | Java 已经 accept |
priority -20 影响子进程属性 | ParsePriority → SetProcessAttributes | 一定获得 CPU 时间 |
onrestart 只在 reap 后执行 | ParseOnrestart → Service::Reap | 所有依赖服务恢复成功 |
critical ... target 保存到 Service | ParseCritical → Reap | 一定触发 reboot |
| secondary 使用 lazy preload | rc argv → ZygoteInit | secondary 启动更快 |
service_test.cpp 的测试包括 service 解析、临时 oneshot service、root 权限下真实启动/停止和 namespace/cgroup 行为;它不是 Android 设备上完整 Zygote 启动测试。尤其是 StartConsole 等测试需要 root 或特定 build,不能把 host parser 断言扩大为 SELinux policy、ART preload 或 system_server 证明。
8.2 现场检查
在 userdebug/eng 设备上执行只读检查:
adb shell getprop ro.zygote
adb shell getprop init.svc.zygote
adb shell getprop init.svc.zygote_secondary
adb shell ls -lZ /dev/socket/zygote /dev/socket/usap_pool_primary
adb shell ps -A -o PID,PPID,USER,NAME,ARGS | grep -E 'zygote|system_server'
adb shell logcat -b all -d -s init:I Zygote:I | tail -n 120这些命令分别观察配置选择、init Service 状态、socket inode/标签、父子进程关系和 Java 日志。init.svc.zygote=running 只能证明 init 父进程完成了启动登记;需要同时看到 socket 存在、Zygote Java 日志进入 runSelectLoop,才能把“可接收 fork 请求”作为更强结论。system_server 出现也不等于全部 framework service 已注册。
8.3 可复现搜索
rg -n "service zygote|zygote_secondary|usap_pool" system/core/rootdir
rg -n "ParseSocket|ParseCritical|ParseOnrestart|Service::Start|Service::Reap" system/core/init
rg -n "createManagedSocketFromInitSocket|forkSystemServer|runSelectLoop" frameworks/base/core/java/com/android/internal/os
rg -n "--start-system-server|--socket-name|enable-lazy-preload" frameworks/base/cmds/app_process frameworks/base/core/java/com/android/internal/os第一组搜索回答“哪份 rc 被安装和导入”,第二组回答“init 如何消费 service option”,第三、四组回答“fd 和 argv 如何进入 Java”。如果四条链不能闭合,说明你看到的只是配置文本,而不是可验证的启动过程。
8.4 失败边界
Zygote 启动失败至少有四种不同位置:
- Parser 失败:service option、uid/gid、critical 或 socket 参数错误,Service 根本不会进入可启动状态;
- init Start 失败:可执行文件、SELinux context、socket、fork、cgroup 或 namespace 失败;
- app_process/Java 失败:ABI list、未知参数、预加载、
ZygoteServer接管 fd 失败; - fork 后消费者失败:system_server 或应用请求处理失败,Zygote 本身可能仍在 accept。
恢复也分层:init 的 onrestart 只处理 Service 重启动作,Java Zygote 的内部异常由进程退出交给 init reap;没有一条“重启 Zygote 就自动恢复所有 framework 状态”的事务路径。
9. 启动追踪
建议读者从 init.svc.zygote=running 但 /dev/socket/zygote 不可用的现象开始验证:
- 检查
ro.zygote,确认导入的是init.zygote64.rc、init.zygote64_32.rc还是init.zygote32.rc; - 回到
ServiceParser::ParseSocket(),确认 socket 名、类型、权限、uid/gid 和 context; - 回到
Service::Start(),确认 descriptor 创建发生在 fork 前; - 查看
service_utils.cpp的ANDROID_SOCKET_环境变量交接; - 查看
ZygoteServer是否按 primary/secondary 名称接管 fd; - 最后区分 init 状态、Java Zygote 状态和 system_server 状态,不用单个 property 代替三者。
本文证明了 Android 17 Zygote rc 家族、ServiceParser 字段、init fork/socket/属性交接、app_process 参数转换、Java Zygote 预加载和 system_server fork 的主线;没有证明具体设备的 ABI 选择、SELinux allow 规则、ART preload 完整耗时、AMS 启动完成或应用 ABI 路由策略。下一篇将继续处理 vendor、odm、product rc 的分区加载边界,而不是把所有 service 定义继续堆进 Zygote 文档。
