Skip to content

进程specialization

追踪 specializeAppProcess 与 SpecializeCommon 的 mount、UID/GID、Capability、SELinux、Seccomp 和 post-fork 顺序。

基于android-17.0.0_r1
AndroidZygoteSELinuxmount namespace源码阅读

进程specialization ​

fork 出来的进程仍带着 Zygote 的地址空间、文件描述符和部分权限。specialization 先在仍有特权时完成 mount namespace、app data/storage bind mount、capability 和 seccomp 准备,再切换 groups、gid、uid、SELinux context、heap/debug 策略,最后执行 post-fork hooks 并进入 zygoteInit()。

1. Java入口 ​

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

java
private static void specializeAppProcess(
        int uid, int gid, int[] gids,
        int runtimeFlags, int[][] rlimits,
        int mountExternal, String seInfo,
        String niceName, boolean startChildZygote,
        String instructionSet, String appDataDir,
        boolean isTopApp, String[] pkgDataInfoList,
        String[] allowlistedDataInfoList,
        boolean bindMountAppDataDirs,
        boolean bindMountAppStorageDirs,
        boolean bindMountSyspropOverrides) {
    nativeSpecializeAppProcess(...);
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
    if (gids != null && gids.length > 0) {
        NetworkUtilsInternal.setAllowNetworkingForProcess(
                containsInetGid(gids));
    }
    Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
    ZygoteHooks.postForkCommon();
}

Java wrapper 在 native 成功后设置网络组语义、恢复 Java 线程优先级和 ART daemon。权限与 namespace 的 owner 是 native SpecializeCommon()。

2. 能力与挂载 ​

源码文件:frameworks/base/core/jni/com_android_internal_os_Zygote.cpp

cpp
permitted_capabilities |= bounding_capabilities;
if (uid != 0) {
    EnableKeepCapabilities(fail_fn);
}
SetInheritable(permitted_capabilities, fail_fn);
DropCapabilitiesBoundingSet(fail_fn, bounding_capabilities);

MountEmulatedStorage(uid, mount_external,
        need_pre_initialize_native_bridge, fail_fn);
ensureInAppMountNamespace(fail_fn);

UID 切换会清理 capability,所以 keepcaps/inheritable/bounding 必须提前设置。mount namespace 也必须在父 Zygote 仍具备权限时建立,避免修改全局挂载视图。

3. 数据隔离 ​

cpp
if (mount_data_dirs) {
    isolateAppData(env, pkg_data_info_list,
            allowlisted_data_info_list, uid,
            process_name, managed_nice_name, fail_fn);
    isolateJitProfile(env, pkg_data_info_list, uid,
            process_name, managed_nice_name, fail_fn);
}
if (mount_storage_dirs) {
    BindMountStorageDirs(env, pkg_data_info_list,
            uid, process_name, managed_nice_name, fail_fn);
}
if (mount_sysprop_overrides) {
    BindMountSyspropOverride(fail_fn, env);
    MountInitOverride(fail_fn, env);
}

app data/JIT/sandbox 通过 tmpfs 和 bind mount 隔离;storage 参数决定 Android/data/obb 等目录;调试构建还可绑定 sysprop override。ProcessList 已对 isolated process 和 FUSE 状态过滤参数,native 只执行请求。

4. SystemServer预取 ​

cpp
if (is_system_server
        && !(runtime_flags
            & RuntimeFlags::PROFILE_SYSTEM_SERVER)) {
    env->CallStaticObjectMethod(gZygoteInitClass,
            gGetOrCreateSystemServerClassLoader);
    env->CallStaticVoidMethod(gZygoteInitClass,
            gPrefetchStandaloneSystemServerJars);
    if (env->ExceptionCheck()) {
        env->ExceptionClear();
    }
}

SystemServer 在 SELinux domain 切换前预取 classloader/AOT artifacts;profile 模式跳过以便 JIT。异常被清除,Java 后续仍有 fallback,但可能失去预取性能收益。

5. 身份与Seccomp ​

cpp
SetGids(env, gids, is_child_zygote, fail_fn);
SetRLimits(env, rlimits, fail_fn);

if (setresgid(gid, gid, gid) == -1) {
    fail_fn(CREATE_ERROR("setresgid failed"));
}
SetUpSeccompFilter(uid, is_child_zygote);
SetSchedulerPolicy(fail_fn, is_top_app);
if (setresuid(uid, uid, uid) == -1) {
    fail_fn(CREATE_ERROR("setresuid failed"));
}

groups/rlimit 先设置;seccomp 和调度策略在失去特权前安装;最后切换 gid/uid。顺序错误会导致策略无法安装或进程保留过多权限。

6. Heap与SELinux ​

cpp
mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL,
        heap_tagging_level);
android_mallopt(M_INITIALIZE_GWP_ASAN,
        &gwp_asan_options, sizeof(gwp_asan_options));
SetCapabilities(permitted_capabilities,
        effective_capabilities,
        permitted_capabilities, fail_fn);

if (selinux_android_setcontext(uid, is_system_server,
        se_info_ptr, nice_name_ptr) == -1) {
    fail_fn(CREATE_ERROR("selinux context failed"));
}

MTE/TBI、heap zero init、GWP-ASan 和 page-size compat 从 runtime flags 映射到 bionic/allocator,再清除已消费 flag。SELinux context 由 uid、isSystemServer、seInfo 和 niceName 决定。

7. Post-fork hooks ​

cpp
if (is_system_server) {
    env->CallStaticVoidMethod(gZygoteClass,
            gCallPostForkSystemServerHooks,
            runtime_flags);
    selinux_android_setcon("u:r:system_server:s0");
}

env->CallStaticVoidMethod(gZygoteClass,
        gCallPostForkChildHooks, runtime_flags,
        is_system_server, is_child_zygote,
        managed_instruction_set);

setpriority(PRIO_PROCESS, 0,
        PROCESS_PRIORITY_DEFAULT);

SystemServer 有专用 post-fork hook 和固定 domain;所有 child 都执行 postForkChild,恢复 ART/随机种子/coverage 等角色状态,最后恢复默认优先级。异常由 fail_fn 终止子进程。

8. 失败与导航 ​

  • mount/data failure:查 ProcessList 参数、FUSE 和 inode map;
  • capability/seccomp failure:查目标 uid、child zygote 角色和内核策略;
  • SELinux failure:查 seInfo、nice name 与 seapp_context;
  • classloader prefetch error:查 profile flag 和 AOT 权限;
  • post-fork error:查 ART hook 和 role-specific 初始化。
bash
# Java specialization wrapper 和 post-fork。
rg -n "specializeAppProcess|nativeSpecializeAppProcess|postForkCommon|setAllowNetworkingForProcess" \
  frameworks/base/core/java/com/android/internal/os/Zygote.java

# Native mount、身份、heap、SELinux、seccomp 与 hook 顺序。
rg -n "SpecializeCommon|MountEmulatedStorage|isolateAppData|BindMountStorageDirs|SetGids|SetRLimits|SetUpSeccompFilter|setresuid|selinux_android_setcontext|gCallPostForkChildHooks" \
  frameworks/base/core/jni/com_android_internal_os_Zygote.cpp

下一篇将分析 64/32 位进程选择与 ABI 路由,不重复 specialization 的安全和 namespace 顺序。