Android AID/GID映射机制与Zygote进程设置全解析
android_filesystem_config.hAID/GID 的定义是怎么被“连到”framework 层去最终在创建新进程App时被转成 Linux 的 UID/GID 并由 zygote 用系统调用设到子进程上的。关键环节、相关代码/组件名、常见文件、以及可以在设备上用来验证的命令与检查点。重点放在流程与实现点便于排查与定制。结论android_filesystem_config.h 在 platform/build 时定义了 AID/GID 常量并产生平台需要的映射生成给 native 与 framework 使用的常量/映射文件。PackageManager安装时为每个包分配一个 appId基于 AID_APP 起点并把 uid/sharedUserId 等记录在 packages settings 中。启动应用时ActivityManager 请求 Zygote fork并把目标 uid、gid、gids 等一并传给 Zygote。Zygote 的 native fork 接口forkAndSpecialize / forkSystemServer 等在子进程里通过 setgroups()、setgid()、setuid()或 setresgid/setresuid、prctl() 等 syscall 把这些 AID/GID (数字) 设置到进程上。因此 android_filesystem_config.h → 生成/映射→ framework 的包管理数据 → Zygote fork 参数 → 内核用户组/用户实际生效。详细步骤与对应组件1)android_filesystem_config.h的作用与输出这是 AOSP 中定义所有 AIDAndroid IDs, 包括 system/radio/audio 以及 AID_APP 起点、isolated range、user offset 等的 C 头文件。它被 native 组件init、vold、installd、zygote native code引用。在构建系统里这些定义通常被用来生成若干运行时可用的映射/常量例如 /system/etc/gidlist.xml、框架层的一些常量文件或在某些版本把常量注入到 Process.java 等以便 framework 和 native 都能知道名字 ↔ 数字 的映射关系。实现细节不同 AOSP 版本会用不同的生成路径但原则是“统一一个 AID/GID 源头生成 native 与 framework 能用的映射/常量”2) PackageManager 为包分配 appId / uid当安装 APKPackageManagerServicePMS会为包分配一个 appId从 AID_APP 起点分配。分配结果写入 packages.xml持久化。在 multi-user 设备上最终的UID由userId * AID_USER appId构成AID_USER 是 user offset通常 100000。PMS 也负责解析 platform.xml / privapp-permissions-*.xml将 permission → groupname 映射解析为数字 gid查 gidlist并把结果作为该包的 supplementary gids 信息保存或在 fork 时传给 zygote。你可以验证adb shell dumpsys package com.example.app | grep userId # 或 adb shell cat /data/system/packages.xml | grep com.example.app -n3) ActivityManager 请求 zygote fork传参当要启动 App 进程时ActivityManagerServiceAMS通过 Zygote 接口ZygoteProcess 的 socket RPC请求 zygote 创建新的 app 进程。请求里包含uid上面计算好的数字gid通常等同 appId 的 primary gidsupplementary gids一个数字数组来自 platform.xml 的 group 映射或 shared GID 分配nice priority、rlimits、runtime args、SElinux info、ABI 相关等。AMS/PM 在构造参数时使用的是数字 uid/gid而不是名字这些数字源自前面 packages.xml 与映射表由 android_filesystem_config.h 的派生信息提供。4) Zygote 的 native forkAndSpecialize 真正设置 UID/GIDzygote 接到 fork 请求后调用 native 层函数比如 Zygote.forkAndSpecialize() 对应的本地实现该本地代码 fork 出子进程后在子进程内部运行一系列操作来专门化进程包括setgroups(gid_array)用传入的 supplementary gidssetgid(gid), setuid(uid)或 setresgid/setresuid应用 SELinux labelsetcon / prctl关闭不需要的文件描述符设置 rlimitexecve 启动 ART 运行时环境等。这些 syscall 是把数字(来自 package manager 的 uid/gid)直接写入内核进程结构从而完成 Linux 层面的用户/组设置。你可查看 zygote 相关 native 代码frameworks/base/... zygote/zygote.c 或 core/jni 的实现来确认这些 syscalls。三、名字到数字映射在哪里发生group name → gidplatform.xml / privapp-permissions 中通常写的是group 名称例如 。在运行时PackageManager 需要把这个名称解析成具体数字 gid。解析途径在系统编译/打包阶段会生成一个 gid 映射表例如 gidlist.xml 或静态映射该表本质上来源于 android_filesystem_config.h或相关构建脚本把 AID 常量写入 XML/Java。PackageManager 在解析 permission XML 时会用这个表把 group 名称换成数字并保存或直接存为 supplementary gids 列表。验证位置/system/etc/gidlist.xml或类似文件通常包含 name↔number 映射也可在 adb shell cat /system/etc/permissions/... 查看到。验证命令示例adb shell cat /system/etc/gidlist.xml | sed -n 1,200p adb shell grep -R media /system/etc || true四、补充sharedUserId / shared GID / isolated UID 的处理sharedUserId若在 AndroidManifest 指定相同 sharedUserId 并且签名相符这些包会在安装时被赋同一个 appId从而共享同一 uid。PackageManager 在安装时管理这个逻辑并写入 packages.xml。shared GIDframework 允许为一组 app 分配 shared gid50000..59999 区间PackageManager 在安装/配置阶段生成并保存这些 gid 的分配。isolated当某组件请求 isolated processZygote 会为其分配 isolated uid99000并 fork 出进程这些 uid 通常短期/临时不写入 packages.xml。五、你可以实际跑的验证/排查命令一步步看 AID 定义/常量设备上可见映射adb shell cat /system/etc/gidlist.xml # 或若存在 adb shell cat /system/etc/permissions/platform.xml | grep -n group gid看包的持久 uid 设置packages.xml 或 dumpsysadb shell dumpsys package com.example.app | egrep userId|sharedUserId|gids adb shell cat /data/system/packages.xml | grep -A4 com.example.app启动时观察 zygote fork 参数需要源码或系统日志调试- 开启 verbose loggingadb logcat -s Zygote 或 ActivityManager看 zygote fork 调用日志。查看进程实际 uid/gidpid$(adb shell pidof com.example.app) adb shell cat /proc/$pid/status | egrep Uid|Gid|Groups这能直接证实最后内核里进程所带的 uid/gid 数字。六、注意点 / 常见误区android_filesystem_config.h 不是运行时直接被 Java 解析的 header而是构建时/平台层的源AID 源会被用于生成运行时所需的映射XML 或 Java 常量因此 framework 能用名字/常量和数字互相映射。所有最终的权限/组设置在 kernel 层是数字uid/gid生效framework/PackageManager 只是在用户层负责分配和传参。SELinux policy 仍然会约束进程能访问的资源即使进程拥有某个 gid也可能被 SELinux 拒绝。