进程uid、pid相关概念

在 Android 系统开发(特别是 Framework 层和 SystemUI 开发)的语境下,AppIDUID 是两个非常容易混淆但通过严格数学逻辑关联的概念。

基于你之前提到的 SystemUI 优化场景,以下是它们的本质区别和底层关系:

1. 核心定义区别

概念全称层面核心含义
UIDUser IDLinux 内核层进程/资源的实际拥有者标识。在 Linux 看来,每一个 Android App 都是一个独立的“用户”,拥有一个唯一的 UID。用于文件权限读写、进程隔离(沙箱机制)。
AppIDApplication IDAndroid 框架层应用本身的唯一标识码。它代表了“这个 App 是谁”,不包含“当前在哪个分身/用户下运行”的信息。

2. 数学关系(核心公式)

在 Android 引入多用户(Multi-user)机制后,UID 不再只是简单的从 10000 开始累加,而是包含了 UserId(当前是哪个用户,如主用户、分身、工作空间) 的信息。

Android 框架中定义了一个常量 PER_USER_RANGE = 100000

换算公式如下:

或者反推:

  • AppID = UID % 100000 (取模)
  • UserId = UID / 100000 (取整)

3. 举例说明(场景化理解)

假设你安装了 “微信” 这个应用,系统给它分配的基础 ID(AppID)是 10235

  • 场景 A:你在“主系统(Owner, UserId=0)”里打开微信
    • UserId = 0
    • UID = = 10235
    • 此时 UID 和 AppID 看数值是一样的。
  • 场景 B:你在“应用双开/分身(Clone, UserId=999)”里打开微信
    • UserId = 999
    • UID = = 99910235
    • 此时 UID 变得极其巨大。
  • 场景 C:你在“工作空间(Work Profile, UserId=10)”里打开微信
    • UserId = 10
    • UID = = 1010235

总结

  • AppID 没变(都是 10235):因为不管是哪个分身,它本质上都是“微信”这个包。
  • UID 变了:因为它们运行在不同的空间,数据目录(/data/user/0/ vs /data/user/999/)互相隔离,Linux 内核通过不同的 UID 来禁止它们互相访问文件。

4. 在 SystemUI 开发中的应用

回到你上一段代码的上下文:

// 判断是否为核心进程
UserHandle.isCore(Process.myUid());

UserHandle.isCore(uid) 的源码逻辑其实就是在看 AppID:

public static boolean isCore(int uid) {
    if (uid >= 0) {
        // 获取 AppID
        final int appId = getAppId(uid);
        // 如果 AppID 小于 10000 (Process.FIRST_APPLICATION_UID)
        // 说明它是 System、Root、Shell、Media 等系统预留进程,而非普通第三方应用
        return appId < Process.FIRST_APPLICATION_UID;
    } else {
        return false;
    }
}

对你的启示:

  1. 做权限判断用 UID:如果你要判断“当前发消息的是不是微信”,你需要校验 UID,因为你要区分是“主用户的微信”还是“分身的微信”。
  2. 做应用识别用 AppID:如果你只关心“这是不是微信这个 App”,不关心是哪个分身,就用 UserHandle.getAppId(uid) 获取 AppID 来判断。
  3. SystemUI 的特殊性:SystemUI 运行在主用户(User 0)下,所以它的 UID 通常就等于 AppID(如果在 System 分区且配置了 persistent,通常 UID 会被固定分配,如 1000 system 或自定义的 id)。

5. 常见误区澄清

  • Gradle 里的 applicationId: 在 Android Studio 的 build.gradle 里配置的 applicationId "com.example.myapp"
    • 这也是 AppID,但这是字符串形式的包名
    • 本文讨论的是 Framework 层整数形式(int)的 AppID
    • 系统内部通过 PackageManagerService 维护了一张表,把字符串 "com.example.myapp" 映射成整数 10xxx

简单来说:UID 是给 Linux 内核看大门的(决定能不能进),AppID 是给 Android 框架认人的(决定你是谁)。