Android UID

1. Android UID 概述

在 Android 操作系统中,UID (User ID) 是用于标识一个应用程序的核心标识符。

  1. 分配机制:UID 在应用安装时由系统(PackageManagerService)分配。
  2. 生命周期 :在应用存在于设备期间,其 UID 保持不变。只有当应用被卸载后,该 UID 才可能被回收并分配给新的应用。
  3. 唯一性原则:通常情况下,一个应用程序对应一个 UID。
  4. 共享机制 :多个应用可以通过 sharedUserId 方式共享同一个 UID,但前提是这些应用必须使用相同的签名

UID 是 Android 安全沙箱(Sandbox)机制的基础,它决定了应用的文件访问权限、资源使用权限以及进程间通信(IPC)的身份验证。

2. UID 的格式与计算

在 Android log 中,我们经常看到类似 u0_a36 的标识,这就是 UID 的一种表现形式。


u0_a199 为例:

  1. u0 : 代表 User 0 ,即 Android 系统的主用户(Owner)。Android 支持多用户,其他用户可能是 u10 等。
  2. a199: 代表该应用在该用户下的 ID 偏移量,这里是 199。

Android 普通应用程序的 UID 起始值定义为 10000 (FIRST_APPLICATION_UID)。

真实数值计算公式:

<math xmlns="http://www.w3.org/1998/Math/MathML"> UID = Base + Offset \text{UID} = \text{Base} + \text{Offset} </math>UID=Base+Offset

针对 u0_a1999

<math xmlns="http://www.w3.org/1998/Math/MathML"> 10000 ( 基础值 ) + 199 ( 偏移量 ) = 10199 10000 (\text{基础值}) + 199 (\text{偏移量}) = 10199 </math>10000(基础值)+199(偏移量)=10199

因此,系统底层实际使用的 int 类型 UID 为 10036

3. UID 的分配范围

根据 frameworks\base\core\java\android\os\Process.java 中的定义:

java 复制代码
// 应用程序 UID 范围
public static final int FIRST_APPLICATION_UID = 10000;
public static final int LAST_APPLICATION_UID = 19999;

// SDK 沙箱进程 UID 范围
public static final int FIRST_SDK_SANDBOX_UID = 20000;
public static final int LAST_SDK_SANDBOX_UID = 29999;

// 隔离进程 UID 范围
public static final int FIRST_ISOLATED_UID = 99000;
public static final int LAST_ISOLATED_UID = 99999;

// 应用 Zygote 隔离进程 UID 范围
public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000;
public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999;

系统预定义的特殊 UID:

java 复制代码
public static final int SYSTEM_UID = 1000;        // 系统进程
public static final int PHONE_UID = 1001;         // 电话服务
public static final int SHELL_UID = 2000;         // Shell 进程
public static final int LOG_UID = 1007;           // 日志服务
public static final int WIFI_UID = 1010;          // WiFi 服务
public static final int MEDIA_UID = 1013;         // 媒体服务
public static final int DRM_UID = 1019;           // DRM 服务
public static final int VPN_UID = 1016;           // VPN 服务
public static final int NFC_UID = 1027;           // NFC 服务
public static final int BLUETOOTH_UID = 1002;     // 蓝牙服务

4. 应用

4.1 通过包名获取 UID

在应用开发中,可以通过 PackageManager 获取任意应用的 UID:

ini 复制代码
PackageManager mPm = getPackageManager();
try {
    // 0 表示不需要特殊的 flag
    ApplicationInfo applicationInfo = mPm.getApplicationInfo("com.tencent.mm", 0);
    int uid = applicationInfo.uid;
    
    // 显示 UID
    Toast.makeText(MainActivity.this, "UID: " + uid, Toast.LENGTH_SHORT).show();
} catch (Exception e) {
    e.printStackTrace();
}

4.2 通过 UID 获取包名

反之,也可以通过 UID 反查包名。

ini 复制代码
String packagename = getPackageManager().getNameForUid(uid); 

4.3 声明 Shared UID (系统级应用开发)

如果拥有系统签名,或者需要让两个自己的应用运行在同一进程、共享数据,可以在 AndroidManifest.xml 中声明 sharedUserId

示例:设置应用为系统进程 UID

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"
    package="cn.izis.chessdeskrobot"
    android:sharedUserId="android.uid.system">
    
    <!-- 注意:必须使用与系统相同的签名文件对 APK 进行签名,否则安装会失败 -->
    ...
</manifest>

常见的共享 UID 类型:

  1. android.uid.system (系统权限)
  2. android.uid.shared
  3. android.uid.media

仅仅配置 android:sharedUserId="android.uid.system"(即 UID 1000)并不代表能无条件互相访问,实际情况取决于三层机制:

  1. Linux 权限层(允许): 如果两个应用 UID 相同且签名一致 ,Linux 内核视它们为同一个用户,默认打破沙箱,可以互相读写数据。
  2. SELinux 层(可能拦截): 即使 UID 相同,如果两个进程属于不同的 SELinux 安全域(system_server,system_app),系统仍会强制拦截访问。
  3. 多用户层(物理隔离): 不同 Android 用户(如主用户 vs 工作资料)下的应用,实际运行时的 UID 是不同的(如 1000 vs 1001000),因此无法互通

5. UID vs PID

5.1 对比分析

特性 UID (User ID) PID (Process ID)
定义 用户身份标识 进程实例标识
层级 应用级 (Application Scope) 进程级 (Process Scope)
分配时机 应用安装时 进程启动时
生命周期 极长(应用安装到卸载) 短暂(进程启动到被杀/退出)
唯一性 可共享 (sharedUserId) 系统运行时唯一
主要作用 权限控制、沙箱隔离、文件归属 进程调度、内存管理、信号发送

5.2 为什么需要 UID?

PID 是临时的、易变的。应用重启后 PID 会改变,但 UID 不会。Android 权限系统(如是否允许访问相机、文件)是基于 UID 进行持久化记录和检查的,而不是 PID。

  1. 权限检查示例 :当 App 请求打开相机时,系统检查的是 Binder.getCallingUid() 是否拥有相机权限。
  2. 文件安全/data/data/com.example.app/ 目录的所有者是该应用的 UID,Linux 内核通过 UID 确保其他应用无法访问该目录。

尝试以 Shell 用户(UID 2000)查看目录 /data/data/com.example.study:

bash 复制代码
$ adb shell dumpsys package com.android.shell | grep uid
    uid=2000 gids=[] type=0 prot=signature
    sharedUser=SharedUserSetting{83df8ed android.uid.shell/2000}
  SharedUser [android.uid.shell] (83df8ed):
  
$ adb shell ls -l //data/data/com.example.study
ls: //data/data/com.example.study: Permission denied

$ adb shell run-as com.example.study ls -l //data/data/com.example.study
total 40
drwxrws--x 2 u0_a199 u0_a199_cache 4096 2025-12-16 13:35 cache
drwxrws--x 5 u0_a199 u0_a199_cache 4096 2025-12-16 13:35 code_cache
drwxrwx--x 2 u0_a199 u0_a199       4096 2025-12-16 13:35 databases
drwxrwx--x 3 u0_a199 u0_a199       4096 2025-12-16 13:35 files
drwxrwx--x 2 u0_a199 u0_a199       4096 2025-12-16 13:35 shared_prefs


$ adb shell pm list packages --uid 1000
package:com.android.inputdevices uid:1000
package:com.android.location.fused uid:1000
package:com.android.settings uid:1000
package:com.android.localtransport uid:1000
package:android uid:1000
package:com.android.emulator.multidisplay uid:1000
package:com.android.dynsystem uid:1000
package:com.android.keychain uid:1000
package:com.android.server.telecom uid:1000
package:com.android.providers.settings uid:1000
package:com.android.wallpaperbackup uid:1000

5.3 线程与进程的关系

在 Linux/Android 内核中:

  • 主线程 ID (TID) == 进程 ID (PID)
  • 可以通过 Process.myPid() == Process.myTid() 来判断当前代码是否运行在主线程。

6. 特殊进程机制

6.1 隔离进程 (Isolated Process)

  1. UID 范围:99000 - 99999
  2. 特点:没有网络访问权限、无法访问外部存储、只能访问极少数系统服务。
  3. 用途:用于解析不信任的数据(如 Chrome 的渲染进程),即使进程被攻破,攻击者也无法获取用户隐私数据。

6.2 SDK 沙箱 (SDK Sandbox)

  1. UID 范围:20000 - 29999
  2. 背景:Android 13 引入。
  3. 用途:将第三方广告 SDK 等运行在独立的沙箱进程中,使其无法直接访问主应用的敏感数据,增强隐私保护。
相关推荐
C雨后彩虹2 小时前
任务总执行时长
java·数据结构·算法·华为·面试
小鸡吃米…2 小时前
Python编程语言面试问题二
开发语言·python·面试
LYFlied3 小时前
【每日算法】LeetCode 84. 柱状图中最大的矩形
前端·算法·leetcode·面试·职场和发展
zwjapple4 小时前
全栈开发面试高频算法题
算法·面试·职场和发展
程序员爱钓鱼4 小时前
Node.js 编程实战:Redis缓存与消息队列实践
后端·面试·node.js
nono牛4 小时前
安卓/MTK平台日志关键词详解
android
TimeFine5 小时前
Android AI解放生产力(四)实战:解放绘制UI的繁琐工作
android
sheji34166 小时前
【开题答辩全过程】以 基于Android的社区车位共享管理系统的设计与实现为例,包含答辩的问题和答案
android
TimeFine6 小时前
Android AI解放生产力(三):认识custom_prompts和skills
android