Android下uid与多用户释疑

Android是基于Linux的OS,Linux下有一套自己的账户管理体系,而Android对此有一些封装和改动。同时,Android也引进了自己的多用户功能。所以,大量的类似“uid”的概念存在于Android中,让初学者很头痛,有必要整理一下以释疑。

1.Linux uid/gid 
Linux下的用户id(uid)和群组id(gid)。Linux是多用户系统,每个用户都拥有一个uid,这个uid由系统和用户名做映射绑定。同时,为了便于用户管理(譬如管理文档权限),Linux引入了群组的概念,可以将多个用户归于一个群组。每一个群组拥有一个群组id(gid)。 
root用户:Linux下的唯一的超级用户,拥有所有的系统权限。root用户所在的组即root组。

2.Android uid/gid(Linux uid/gid的移花接木) 
在Android 4.2之前,Android不支持多用户。Android将Linux的账户管理体系用在了应用管理上。举例说明,在一台android手机上安装某应用,通过adb shell查看其数据文档: 
这里写图片描述 
可以看到文件拥有者是u0_a81,所在群组为u0_a81。从data/system/packages.xml根据包名查看此应用信息,可以看到:userId=”10081”。 
在代码中通过接口android.os.Process.myUid()来获取,也可以看到10081。 
从Android源代码Process.java对于此Api的注释来看: 
这里写图片描述 
可以看到应用进程是运行在这个Linux kernel uid下面。 
在Process源代码中还能够看到一些常量定义: 
这里写图片描述 
可以看到,Android对于一些系统uid的保留定义,而且基本上每个用户自成一群组,gid与uid相同。群组的概念已经被淡化。查看某一个系统应用data/data/目录,可以看到: 
这里写图片描述 
拥有者为system,群组为system。结合上面的u0_a81,可以看到,Android会以应用为单位,分配uid/gid。这里的system、u0_a81是用户名/群组名,由android生成,与uid/gid映射匹配。 
分析到这,不难理解AndroidManifest.xml中的sharedUserId属性,譬如,前面举例说明的系统应用Settings,其AndroidManifest.xml中即有 
这里写图片描述 
即,Android为应用准备的uid/gid是可以共享的,其目的当然包括这样可以在不同的应用中共享数据和文件。当然,这还需要应用之间的签名匹配。


3.Android多用户 
Android4.2开始支持多用户。Linux的uid/gid多用户体系已经被用在App管理上了,所以android重新开发了一套多用户体系,在UserManagerService中管理,PackageManagerService和ActivityManagerService中也有相关逻辑。Android的多用户可以做到不同用户的应用的物理文件级(数据)的区分,以实现不同用户有不同的壁纸、密码,以及不同的应用等。本文不展开多用户的机制,只集中于uid。 
先看一下在多用户下,应用的uid怎么变化。 
在一个有两个用户(用户id分别为0和10)的安卓设备上,在用户10下安装一个应用,此时,在0下是看不到这个应用的。 
从packages.xml查看此应用的uid:userId=”10078” 
Process.myUid()得到uid为”1010078” 
Process.myUserHandle()得到”userHandle{10}” 
在另一个用户0下安装此应用。 
查看packages.xml,看到uid没有变化10078 
Process.myUid()得到uid为”10078” 
Process.myUserHandle()得到”userHandle{0}” 
adb shell进入命令行,分别查看data/user/0和data/user/10下面此应用的数据区: 
用户0: 
这里写图片描述 
用户10: 
这里写图片描述 
可以看到,实际上应用在内部虽然有多用户,但只有一个uid,在不同的用户下,通过uid和用户id合成一个新的uid,以保证在每个用户下能够区分。 
android.os.UserHandle这个类对外提供有关多用户的接口。 
从里面的一些api代码可以看到uid在多用户下的处理逻辑: 
多用户支持开关: 
这里写图片描述 
注意一个api getUid()。这就清楚了,将用户id 10作为第一个参数,packages.xml中记录的该应用的uid 10078作为第二个参数传入,得到了这个应用在10用户下的uid——1010078! 
这里写图片描述 
这里写图片描述 
通过应用的uid得到当前用户的userId,以上过程的逆过程: 
这里写图片描述 
从另一个核心的api myUserId()更能清楚地看到应用uid和用户id的关系: 
这里写图片描述 
当一个应用使用UserHandle.myUserId()来获取当前的用户id的时候,其实就是从他自己的进程得到应用的uid,然后通过上述逻辑计算出当前的用户id。 
从Process.myUserHandle()也能清楚地看到这个逻辑: 
这里写图片描述 
从概念和API命名上,确实有些混乱,但Android也情非得已,Process的API Level是1,UserHandle的API Level是17,可见在最初的android上面,已经将Linux uid/gid给了应用id了,当时应该也没有考虑android有一天需要支持多用户。直到4.2(API Level 17),引入了多用户时,已经是若干年过去了,Process已经被无数的开发者使用,无法改变。只能接受这个概念上混淆了。 
可以用如下的几点来简单地澄清这些id概念: 
(1)Process中的xxid相关的概念和API是关于应用id的。 
(2)UserHandle中的xxid相关的概念和API是关于Android用户id的。 
(3)Process有接口得到UserHandle实例。 
注:以上源代码Android版本为4.4.4。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值