概述
UID一般理解为User Identifier,在linux中就是用户的ID,表明是哪个用户运行了这个程序,GID则表明了这个用户属于哪个组。它们主要用于权限的管理。
而在Android中,部分权限的管理是依赖底层的linux的,所以了解Android的UID/GID十分必要。
网上有下面的一段话:
而在Android 中又有所不同,因为Android为单用户系统,这时UID 便被赋予了新的使命,android为每个应用几乎都分配了不同的UID,不像传统的linux,每个用户相同就为之分配相同的UID。(当然这也就表明了一个问题,android只能时单用户系统,在设计之初就被他们的工程师给阉割了多用户),使之成了数据共享的工具。
这段话有对有错,这篇文章将结合源码来分析UID与GID的分配,使我们有个最清晰的理解。源码版本为4.3。
首先需要明确的一点是,App的UID和GID是安装的时候确认的。而与安装相关的源码目录是:
frameworks\base\services\java\com\android\server\pm
PackageManagerService.java的scanPackageLI方法
private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
int parseFlags, int scanMode, long currentTime) {
............
//获取一系列属性
pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
destResourceFile, pkg.applicationInfo.nativeLibraryDir,
pkg.applicationInfo.flags, true, false);
............
//UID赋值
pkg.applicationInfo.uid = pkgSetting.appId;
............
可以看到在getPackageLPw方法中,获取了UID,那我们打开这个函数看看:
Settings.java的getPackageLPw方法
private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
String nativeLibraryPathString, int vc, int pkgFlags, boolean create, boolean add) {
.........
s.userId = newUserIdLPw(s);
.........
}
可以看到UID是newUserIdLPw()指定的,那再打开这个看看:
依然是Settings文件
private int newUserIdLPw(Object obj) {
// Let's be stupidly inefficient for now...
final int N = mUserIds.size();
for (int i = 0; i < N; i++) {
if (mUserIds.get(i) == null) {
mUserIds.set(i, obj);
return Process.FIRST_APPLICATION_UID + i;
}
}
// None left?
if (N > (Process.LAST_APPLICATION_UID-Process.FIRST_APPLICATION_UID)) {
return -1;
}
mUserIds.add(obj);
return Process.FIRST_APPLICATION_UID + N;
}
至此,UID就算是分配下来了。
可以看到for循环和if (mUserIds.get(i) == null)语句限定了一个APP只有一个UID,而这个Process.FIRST_APPLICATION_UID是在frameworks/base/core/java/android/os/Process.java中定义的,其值为10000,这就是为什么Android的UID都是从10000开始的。
再回到PackageManagerService.java的scanPackageLI代码:
//invoke installer to do the actual installation
//第二个uid就是GID
int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
pkg.applicationInfo.uid);
if (ret < 0) {
// Error from installer
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return null;
}
// Create data directories for all users
// 指定工作目录
sUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);
if (dataPath.exists()) {
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
Slog.w(TAG, "Unable to create data directory: " + dataPath);
pkg.applicationInfo.dataDir = null;
}
可以看到此函数在运行时,将UID的值直接赋值给了GID,所以通常UID和GID也是相同的。从官方注释这可以看到Android有多用户。事实上,Android某些平板对多用户是支持的,我猜大家常见的是阉割版的吧,所以有误会。
打开UserManager的installPackageForAllUsers方法可以看到:
public void installPackageForAllUsers(String packageName, int uid) {
for (int userId : mUserIds) {
// Don't do it for the primary user, it will become recursive.
if (userId == 0)
continue;
mInstaller.createUserData(packageName, UserId.getUid(userId, uid),
userId);
}
}
写了这么多,相信大家对UID/GID的分配有了更深刻的理解。欢迎一起讨论哈。