我们知道 Android 是基于 Linux 开发的,因此在 Linux 中 也有 UID、GID、PID。这篇文章就介绍 Linux 和 Android 中 UID、GID、PID 的作用以及区别。
Linux 中的 UID、GID、PID
ID | 含义 | 作用 | 备注 |
---|---|---|---|
UID(用户标识符) | 用于标识Linux系统中的用户,区分普通用户、根用户和系统用户 | 确定用户对系统中文件的增删改查权限以及命令执行权限。不同用户权限不同,如根用户可操作任何文件和执行任何命令,普通用户权限受限 | 根用户UID为0;普通用户UID通常大于500;系统用户UID范围是1 - 499 |
GID(组标识符) | 对UID的封装处理,包含多个UID,代表用户组 | 便于对系统进行统一权限管理。给组分配权限时,组内所有用户都能获取相应权限 | 在Linux下每个UID都对应着一个GID |
PID(进程标识符) | 系统在程序运行时,为每个可执行程序分配的唯一标识 | 表明程序拥有的文件操作权限,确保不同可执行程序运行时互不影响,限制它们之间的数据访问 |
Android 中的 UID、GID、PID
ID | 含义 | 作用 | 取值特点 |
---|---|---|---|
UID(用户标识符) | 在Android中,一个UID对应一个可执行程序,普通程序的UID与GID相同 | 标识程序所拥有的"资源",如文件目录、数据库访问、网络、传感器和日志等,用于区分不同程序,不同程序间"资源"默认相互隔离 | 每个程序的UID唯一,由系统分配,是程序在系统中的身份标识 |
GID(组标识符) | 在Android普通程序中与UID相同 | 与UID共同标识程序资源,参与权限管理 | |
PID(进程标识符) | 系统为程序运行分配的进程标识,同一安卓应用可拥有多个PID | 区分不同进程,保证不同应用或同一应用不同进程间相互独立运行,减少干扰 | 每个进程有唯一PID,同一应用不同进程的PID不同,由系统分配 |
需要注意:不同程序 UID 不同,默认无法访问彼此 "资源"。可通过完全暴露(在 AndroidManifest.xml 中设置 android:exported="true" ,或添加 intentFilter 属性时默认 exported 为 true )、权限提示暴露(在 AndroidManifest.xml 中声明 Activity、Service 或 ContentProvider 时添加 permission,其他应用需添加对应权限才能访问)、私有暴露(通过 sharedUserId + 同一套签名,让不同应用运行在同一个进程中,实现数据相互访问)三种方式开放数据访问权限
获取当前应用的 UID、GID、PID
- 获取PID :通过API调用获取,在应用内调用
int pid = android.os.Process.myPid();
即可获取当前应用的PID 。此方法简单直接,无需额外权限或复杂操作,适用于大多数在应用内部需要获取自身PID的场景。 - 获取UID
- API调用获取 :在应用内使用
int uid = android.os.Process.myUid();
获取当前应用的UID。该方式与获取PID类似,方便快捷,在应用内部获取自身UID时常用。 - 反射调用获取 :通过
Process.getUidForPid(int pid)
方法获取指定PID对应的UID 。不过该方法是@hide
的,需要使用反射调用,代码示例如下:
- API调用获取 :在应用内使用
java
public static int getUidForPidReflection(int pid) {
try {
Method method = Process.class.getDeclaredMethod("getUidForPid", int.class);
method.setAccessible(true);
return (int) method.invoke(null, pid);
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
使用反射调用虽然可以获取到所需信息,但代码相对复杂,且存在一定风险,比如在不同系统版本中方法签名可能变化导致调用失败。