Android中的UID和AppId

本篇博客主要记录一下Android中UID的含义,并简单分析应用appId的分配流程。


1、UID
Android是支持多用户的操作系统,其中进程对应的UID由用户ID和应用ID共同决定。
我们来看看UserHandle.java的代码:

    public static int getUid(@UserIdInt int userId, @AppIdInt int appId) {
        //支持多用户时
        if (MU_ENABLED) {
            //userId * 100000 + (appId % 100000)
            return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
        } else {
            return appId;
        }
    }

在android手机上,我们利用adb shell执行ps命令后,可以看到如下信息:

从图中可以看出,其中第一项将显示进程对应的UID。
这里截取的两个进程为root组的,没有分配具体的编号。


对于用户组的进程来说,如上图所示,会显示类似于u0_a86这样的UID。
这个UID的前一部分表示userId,后一部分表示appId(减去Process.FIRST_APPLICATION_UID的结果)。

一个进程的appId是固定的,在初始化或安装的时候就决定了。
因此,同一个进程在不同用户下,只有userId不一样。
例如,上图中的进程在另一个用户下,对应的UID就类似于:

u10_a86
u10_a54

2、appId

现在我们来看看进程的appId是何时分配的。
以Android 8.0的代码为例,我们看看PKMS中的函数:

    //初始化扫描已安装应用,或安装新应用时,都会调用到该函数
    private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg,
            final int policyFlags, final int scanFlags, long currentTime, @Nullable UserHandle user)
                    throws PackageManagerException {
       .............
       synchronized (mPackages) {
           //如果pkg有sharedUserId,那么getSharedUserLPw中会分配appId
           if (pkg.mSharedUserId != null) {
               suid = mSettings.getSharedUserLPw(
                        pkg.mSharedUserId, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
           }
           ......
           //刚初始化时或安装时,pkgSetting应该为null
           pkgSetting = mSettings.getPackageLPr(pkg.packageName);
           ......
           if (pkgSetting == null) {
               ............
               //利用解析的信息,创建出pkgSetting
               pkgSetting = Settings.createNewSetting(......);
               ............
               //这里也会分配appId
               mSettings.addUserToSettingLPw(pkgSetting);
           } else {
               ............
           }
       }
       .............
   }

我们以Settings.java中的addUserToSettingLPw为例,跟进一下分配appId的流程:

    void addUserToSettingLPw(PackageSetting p) throws PackageManagerException {
        if (p.appId == 0) {
            // Assign new user ID
            // 注意此处赋值给p.appId
            p.appId = newUserIdLPw(p);
        } else {
            // Add new setting to list of user IDs
            addUserIdLPw(p.appId, p, p.name);
        }
        ............
    }

容易看出分配appId的函数为newUserIdLPw:

    private int newUserIdLPw(Object obj) {
        // Let's be stupidly inefficient for now...
        final int N = mUserIds.size();

        //从0开始,找到第一个未使用的id
        //此处对应之前有应用被移除等情况,复用之前的id
        for (int i = mFirstAvailableUid; i < N; i++) {
            if (mUserIds.get(i) == null) {
                mUserIds.set(i, obj);
                //FIRST_APPLICATION_UID的值为10000
                return Process.FIRST_APPLICATION_UID + i;
            }
        }

        // None left?
        //N > 9999
        //安装应用过多时,就返回-1
        if (N > (Process.LAST_APPLICATION_UID-Process.FIRST_APPLICATION_UID)) {
            return -1;
        }

        //此处对应新分配一个递增的id的情况
        mUserIds.add(obj);
        return Process.FIRST_APPLICATION_UID + N;
    }

你可能感兴趣的:(Android源码学习笔记)