从源码角度分析Android中UID与GID的分配

概述

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.javascanPackageLI代码:

//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某些平板对多用户是支持的,我猜大家常见的是阉割版的吧,所以有误会。
打开UserManagerinstallPackageForAllUsers方法可以看到:

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的分配有了更深刻的理解。欢迎一起讨论哈。

    原文作者:Android源码分析
    原文地址: https://blog.csdn.net/leirenbaobao/article/details/48318753
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞