在剖析 Activity 的发动过程中会涉及到 Android 中的各式各样的 ID,许多同学不太清楚这些 ID 的作用和差异,本文做一个简略的介绍.
1. Linux 中的 uid 与 gid
Linux 是一个多用户操作系统,系统中能够一起存在有多个用户。
每个用户有一个用户名,也便是咱们登录时输入的的用户名。用户名在系统中会对应一个整数值 UID,是用户在系统中的唯一标识,就像现实生活中一个身份证号标识一个详细的人。
在终端中能够经过 whoami 打印当时登录的用户名:
whoami
zzh0838
能够经过 id 指令检查 uid
id
uid=1000(zzh0838) gid=1000(zzh0838) groups=1000(zzh0838),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),120(lpadmin),132(lxd),133(sambashare)**
输出的第一组数据 uid=1000(zzh0838)
表明当时用户 zzh0838 的 uid 是 1000。
为了方便管理系统中的多个用户,系统将用户进行了分组,每个用户能够在一个或许多个组中。每个组也有自己的组名和组 id(gid)。一个用户能够一起在多个组中。这个有点类似大学里边的社团,一个社团便是一个用户组,一个学生便是一个用户,一个学生能够一起参加多个社团,便是说一个用户能够一起归于多个用户组。
咱们能够经过 id 指令检查当时用户的组信息:
id
uid=1000(zzh0838) gid=1000(zzh0838) groups=1000(zzh0838),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),120(lpadmin),132(lxd),133(sambashare)
后半部分便是当时用户的用户组信息:
gid=1000(zzh0838) groups=1000(zzh0838),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),120(lpadmin),132(lxd),133(sambashare)
gid=1000(zzh0838)
表明当时用户的初始组是 zzh0838,初始组 zzh0838 的 gid 是 1000。每个用户的初始组只能有一个,一般便是将和此用户的用户名相同的组名作为该用户的初始组。
后面的内容便是当时用户地点的组,包含了组名和组 id。
2. Android 中的 uid
2.1 进程的 uid
Andorid 基于 Linux 内核打造,在 Android 4.2 之前,Android 是不支撑多用户,可是借用了 linux 的用户系统和文件权限系统完成了 App 之间的数据阻隔,所谓数据阻隔便是每个 App 有自己的一个数据文件夹,App 只能拜访自己的数据文件夹,不能拜访其他的 App 的数据文件夹和其他途径下的文件。
那 Android 是怎样完成的呢?
在 App 的装置过程中,会给每个 App 分配一个 userId,这个 userId 保存在手机的 /data/system/packages.xml
文件中,文件中记载了 App 的包名和 userId 的对应关系。
如果要检查咱们的一个 Demo yuandaima.ahao.myactivitytext
运用的 userId,能够在模拟器的 shell 中履行下面的指令:
cat /data/system/packages.xml | grep yuandaima.ahao.myactivitytext
# ......
<package name="yuandaima.ahao.myactivitytext" codePath="/data/app/yuandaima.ahao.myactivitytext-FicL4FdzvHE8_c4bWCbN9A==" nativeLibraryPath="/data/app/yuandaima.ahao.myactivitytext-FicL4FdzvHE8_c4bWCbN9A==/lib" publicFlags="810073926" privateFlags="0" ft="18cf7636700" it="18cf76369b1" ut="18cf76369b1" version="1" userId="10101">
# ......
能够看到运用 yuandaima.ahao.myactivitytext 的 userId 是 10101。
这儿的 userId 便是上一节说到的 linux 中的 uid。
在 Linux 系统中,每个进程也有个 uid 特点,表明是哪个用户发动了当时进程,传统的 linux 系统中,用户发动的进程的 uid 都是当时登录的 uid。
在 Android 中有一些差异,每个进程的 uid 特点,在发动时会被设置成 data/system/packages.xml
文件中记载的进程的 userId。
比方当咱们发动 yuandaima.ahao.myactivitytext
运用时,运用的 uid 会被设置为 10101
检查进程信息:
ps -elf | grep yuandaima.ahao.myactivitytext
u0_a101 4718 1505 0 13:27:30 ? 00:00:00 yuandaima.ahao.myactivitytext
root 4749 4636 0 13:33:21 pts/0 00:00:00 grep yuandaima.ahao.myactivitytext
能够看到发动 yuandaima.ahao.myactivitytext
进程的用户是 u0_a101。
咱们接着运用 id 指令看 u0_a101 用户的相关信息:
id u0_a101
uid=10101(u0_a101) gid=10101(u0_a101) groups=10101(u0_a101), context=u:r:su:s0
能够看到 u0_a101 对应的 uid 是 10101,这个 uid 便是来自 data/system/packages.xml
文件中记载的进程的 userId。
2.2 运用的数据
Android 中运用的数据一般保存在 /data/data
目录下:
cd /data/data
ls -l
# ......
drwx------ 4 u0_a48 u0_a48 4096 2024-01-11 09:37 com.android.timezone.updater
drwx------ 5 u0_a77 u0_a77 4096 2024-01-11 09:37 com.android.traceur
drwx------ 4 u0_a53 u0_a53 4096 2024-01-11 09:37 com.android.vpndialogs
drwx------ 4 u0_a58 u0_a58 4096 2024-01-11 09:37 com.android.wallpaper.livepicker
drwx------ 4 system system 4096 2024-01-11 09:37 com.android.wallpaperbackup
drwx------ 4 u0_a83 u0_a83 4096 2024-01-11 09:37 com.android.wallpapercropper
drwxr-x--x 4 u0_a89 u0_a89 4096 2024-01-11 09:37 com.android.wallpaperpicker
drwx------ 4 u0_a92 u0_a92 4096 2024-01-13 09:31 com.android.webview
drwx------ 4 u0_a95 u0_a95 4096 2024-01-11 09:37 org.chromium.webview_shell
drwx------ 4 u0_a101 u0_a101 4096 2024-01-11 15:18 yuandaima.ahao.myactivitytext
这儿的文件夹的名字均为运用的包名,文件夹中保存了对应运用的数据。比方 yuandaima.ahao.myactivitytext
文件夹就保存了 yuandaima.ahao.myactivitytext
app 的数据。
需求留意的是这儿文件夹的权限均为 rwx------
(除了少量特例),表明仅文件的所有者可读可写可履行,其他用户均没有读写履行权限。
一起,很重要的一点文件的所属用户和对应 app 进程的所属用户相同。比方 yuandaima.ahao.myactivitytext
文件夹的所属用户是 u0_a101
,yuandaima.ahao.myactivitytext
进程的所属用户也是 u0_a101
。
也便是说 yuandaima.ahao.myactivitytext
文件夹中的文件只能又 yuandaima.ahao.myactivitytext
进程来读写履行。
这样就利用 linux 的用户系统和文件权限系统完成了 App 之间的数据阻隔。妙~
3. Android 中的多用户
前期的 Android 并不支撑多用户,由于 Linux 原本的多用户系统被用来完成 App 之间的数据阻隔了。可是用户对于多用户功用的需求还是存在的。在 Android 4.2 的时候,google 再一次对 Linux 进行了魔改,从头开发了一套多用户系统。
国产手机的兼顾功用一般便是基于这套魔改的多用户系统完成的。
假设咱们的 Android 手机上有两个用户,用户 id 是 0 和 10,这儿的 id 在 Android 中称为 UserHandle
咱们先登录 id 为 10 的用户,装置一个运用,在 data/system/packages.xml
中检查, 此运用的 userId=”10068″
咱们在运用中调用:
Process.myUid() // 返回值为 1010068
Process.myUserHandle() // 返回值为 userHandle{10}
接着从头登录 id 为 0 的用户,此刻是看不到上一步装置的运用,接着咱们再次装置同一个运用。在 data/system/packages.xml
中检查,userId 仍然是 10068
咱们在运用中调用:
Process.myUid() // 返回值为 10068
Process.myUserHandle() // 返回值为 userHandle{0}
这儿能够看出这儿的多用户其实是经过 UserHandle 和 userId 的组合来完成的。