##################################################
目录
安卓系统用户管理
查询用户
查看用户列表
查看当前登录用户
添加用户
创建新用户
切换用户
切换账号
删除用户
删除一个账户
安卓系统用户应用权限
Android 是一个多用户系统
Android 用户机制
uid
gid
gids
查看 uid/gid/gids
应用的 appid 和 appuid
用户内部外部家目录
外部存储器 /storage/emulated/用户_UID 家目录
内部存储器 /data/user/用户_UID 家目录
Android 是如何创造出来一个虚拟的多用户运行环境的?
Android 多用户的本质
创建多用户流程解析
多用户切换流程解析
应用权限记录
安装时权限存储位置
运行时权限存储位置
权限声明存储位置
权限控制
授予/移除 权限
User ID 和 Group ID
利用 dumpsys package 从指定应用信息中获取 userid 和 gids
查看用户权限
查看应用权限
权限组详解
平台版本与 API 级别
CM311-1A 盒子 Android 9 所有已知的权限组
联系人权限组 android.permission-group.CONTACTS
电话权限组 android.permission-group.PHONE
日历权限组 android.permission-group.CALENDAR
通话记录权限组 android.permission-group.CALL_LOG
相机权限组 android.permission-group.CAMERA
身体传感器权限组 android.permission-group.SENSORS
位置信息权限组 android.permission-group.LOCATION
存储空间权限组 android.permission-group.STORAGE
系统控制权限组 androidlogic.permission-group.SYSTEM_CONTROL
麦克风权限组 android.permission-group.MICROPHONE
短信权限组 android.permission-group.SMS
CM311-1A 盒子和手机设备都没有看到 WIFI 网络相关的权限
三层 Android 权限详解
第三层 —— 系统权限以及软件安装权限真相
Android 底层映射为 Linux 权限
Android 应用程序权限机制
安装一个 APK 的详细过程
声明时权限 安全等级/protectionLevel 分类
第一层 —— 开发层 AndroidManifest.xml
AndroidManifest.xml 配置文件权限分类
AndroidManifest.xml 配置文件详解
第二层 —— 框架层 preferences.xml
示例一个 root 过的手机修改板子 sd 权限
CM311-1A 的 platform.xml 配置文件详解
platform.xml 对应的解析代码
##################################################
——————————
%%%%%
cmcc_jiangsu:/ # pm list users
Users:
UserInfo{0:机主:13} running
cmcc_jiangsu:/ #
%%%%%
cmcc_jiangsu:/ # whoami
root
cmcc_jiangsu:/ #
——————————
非常注意:
多用户的创建、启动、停止等行为是系统级的
因此只有具有 root、system 权限的进程才能操作
%%%%%
语法如下:
pm create-user 用户名
然后发现盒子竟然也不能创建用户!!!
cmcc_jiangsu:/ # pm create-user "user_1"
Error: couldn't create User.
1|cmcc_jiangsu:/ #
无奈只好换上旧手机:
C:\Users\byme>adb devices /* USB 插上之后查看连接状态 */
List of devices attached
8OOXXOOXXxxooxxF device
C:\Users\byme>adb root /* 看来无法获得 root 权限 */
adbd cannot run as root in production builds
C:\Users\byme>adb shell
shell@GIONEE_G1605A:/ $ pm list users /* 查看用户列表 */
Users:
UserInfo{0:机主:13} running
shell@GIONEE_G1605A:/ $ whoami /* 查看登陆账户 */
shell
shell@GIONEE_G1605A:/ $ pm create-user "ranchui" /* 创建用户燃吹 */
Success: created user id 10
1|shell@GIONEE_G1605A:/ $ pm list users /* 用户 UID 是 10 */
Users:
UserInfo{0:机主:13} running
UserInfo{10:ranchui:0}
shell@GIONEE_G1605A:/ $
如果之前创建多了也没关系 删除多余的用户之后重启手机 UID 就会重新计算:
shell@GIONEE_G1605A:/ $ pm create-user "user"
Success: created user id 10
1|shell@GIONEE_G1605A:/ $ pm list users
Users:
UserInfo{0:机主:13} running
UserInfo{10:user:0}
shell@GIONEE_G1605A:/ $
——————————
%%%%%
启动和切换用户语法如下:
am start-user USER_ID /* 启用一个账户 */
am switch-user USER_ID /* 切换到指定账户 */
启动指定用户:
shell@GIONEE_G1605A:/ $ pm list users /* 当前 ranchui 未上线 */
Users:
UserInfo{0:机主:13} running
UserInfo{10:ranchui:0}
shell@GIONEE_G1605A:/ $ am start-user 10 /* 根据 UID 启用用户 ranchui */
Success: user started
shell@GIONEE_G1605A:/ $ pm list users /* 用户 ranchui 已经在线 */
Users:
UserInfo{0:机主:13} running
UserInfo{10:ranchui:10} running
shell@GIONEE_G1605A:/ $
切换成指定用户:
shell@GIONEE_G1605A:/ $ am switch-user 10 /* 切换成 ranchui 用户 */
shell@GIONEE_G1605A:/ $
正在切换用户:
然后就发现无法调试了:
shell@GIONEE_G1605A:/ $ /* 这边莫名退出去了 */
C:\Users\byme>adb shell /* 查看连接还在 但是不支持调试 */
adb.exe: device unauthorized.
This adb server's $ADB_VENDOR_KEYS is not set
Try 'adb kill-server' if that seems wrong.
Otherwise check for a confirmation dialog on your device.
C:\Users\byme>adb kill-server /* 关掉一次 adb */
C:\Users\byme>adb devices /* 发现不是 device 是个未经授权的 unauthorized */
* daemon not running; starting now at tcp:5037
* daemon started successfully
List of devices attached
8ooxxOOOXXXooxxF unauthorized
C:\Users\byme>
然后手机竟然开始首次登陆配置:
这个新建立的用户确确实实不允许 USB 调试:
无奈 只好重启手机之后默认登陆主账户再次开启调试功能:
C:\Users\byme>adb devices /* 此时还未授权 */
List of devices attached
8ooxxOOOXXXooxxF unauthorized
C:\Users\byme>adb devices /* 授权过后 */
List of devices attached
8ooxxOOOXXXooxxF device
C:\Users\byme>
——————————
%%%%%
语法如下:
pm remove-user USER_ID
示例删除刚刚创建的 ranchui 用户:
C:\Users\byme>adb shell
shell@GIONEE_G1605A:/ $ pm list users /* 查看用户列表 */
Users:
UserInfo{0:机主:13} running
UserInfo{10:ranchui:10}
shell@GIONEE_G1605A:/ $ pm remove-user 10 /* 根据 UID 删除用户 */
Success: removed user
shell@GIONEE_G1605A:/ $ pm list users /* 再次查看用户列表 */
Users:
UserInfo{0:机主:13} running
shell@GIONEE_G1605A:/ $ am start-user 10 /* 因为没有该账户所以报错 */
Error: could not start user
shell@GIONEE_G1605A:/ $ am switch-user 10 /* 没有该账户所以屏幕也没切换过去 */
shell@GIONEE_G1605A:/ $
##################################################
——————————
Android 4.0 开始 Google 就开始在 Android 上布局多用户
UserManager 由此诞生 然而此时尚未对应的 Binder 服务 真正支持多用户是从 Android 4.2 开始
即使如此系统中也依然存在各类 Bug 和兼容性问题
直到 Android 6.0 多用户才比较完善
国内外的厂家也纷纷开始针对多用户这个噱头来作各类 花里胡哨 的操作
手机分身
分身应用
应用双开
等等等等 不得不说 国内的厂家在多用户这方面定制化到现在已经很是稳定和完善了
——————————
对于 Android 中的每一个进程都有一个单独的 uid、gid 以及 gids 集合
经过这三者 Android 系统实现了一套文件和数据访问权限规则系统
例如 访问某个文件 文件系统规定了该文件在磁盘中的 rwx 权限
%%%%%
UID 是用户 id
在 Linux 上一个用户 uid 标识着一个给定的用户 而 Android 上也沿用了 Linux 用户的概念
root 用户 uid 为 0
system Uid 为 1000
Android 在创建每个用户时 都会分配一个整型的 userId
对于主用户 就是正常下的默认用户 来说 userId 为 0
之后创建的 userId 将从 10 开始计算 每增加一个用户 userId 就会加 1
而且每一个应用程序在安装时也被赋予了单独的 uid
这个 uid 将伴随着应用从安装到卸载包括缓存
%%%%%
GID 是用户组 id
Linux 上规定每一个应用都应该有一个用户组
对于 Android 应用程序来讲每一个应用的所属用户组与 uid 相同
%%%%%
GIDS 是应用在安装后所得到权限的 id 集合
在 Android 上每一个权限均可能对应一个或多个 group 而每一个 group 都有一个 gid name
所以 gids 就是经过对每一个 gid name 计算得出的 id 集合
一个 uid 能够关联 gids 代表该 uid 拥有多种权限
%%%%%
获取 system_server 的 PID 然后根据这个 PID 查看 UID/GID/Groups :
cmcc_jiangsu:/ # ps -A | grep system_server /* 得到 PID 为 3620 */
system 3620 2604 1386312 181192 SyS_epoll_wait 0 S system_server
cmcc_jiangsu:/ # cat /proc/3620/status /* 查看该进程的 status */
Name: system_server
Umask: 0077
State: S (sleeping)
Tgid: 3620
Ngid: 0
Pid: 3620
PPid: 2604
TracerPid: 0
Uid: 1000 1000 1000 1000
Gid: 1000 1000 1000 1000
FDSize: 512
Groups: 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1018 1021 1023 1024 10
32 1065 3001 3002 3003 3006 3007 3009 3010
VmPeak: 1419816 kB
VmSize: 1386312 kB
VmLck: 0 kB
VmPin: 0 kB
VmHWM: 206464 kB
VmRSS: 181088 kB
RssAnon: 15028 kB
RssFile: 165708 kB
RssShmem: 352 kB
VmData: 1018244 kB
VmStk: 8192 kB
VmExe: 24 kB
VmLib: 80572 kB
VmPTE: 524 kB
VmPMD: 0 kB
VmSwap: 0 kB
Threads: 97
SigQ: 0/10948
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000001204
SigIgn: 0000000000000001
SigCgt: 00000006400084f8
CapInh: 0000001806897c20
CapPrm: 0000001806897c20
CapEff: 0000001806897c20
CapBnd: 0000000000000000
CapAmb: 0000000000000000
Seccomp: 0
Speculation_Store_Bypass: unknown
Cpus_allowed: f
Cpus_allowed_list: 0-3
Mems_allowed: 1
Mems_allowed_list: 0
voluntary_ctxt_switches: 2526
nonvoluntary_ctxt_switches: 1818
cmcc_jiangsu:/ #
——————————
在 Android 中应用的 uid 是和当前的用户有关的
同一个应用具有相同的 appId
其 uid 的计算方式为:
appUid = userId * 1000000 + appId
在主用户中 uid 就等于 appId
——————————
为了多用户下的数据安全性
在每个新用户创建之初不管是 外部存储器/External Storage 还是 app data 目录
Android 都为其准备了独立的文件存储
新用户创建时 Android 在
/storage/emulated
/data/user
目录下为每个用户都创建了名为用户 id 的家目录
%%%%%
目录 /storage/emulated/ 下拥有不同的用户分区
当我们在代码中使用
Environment.getExternalStorageDirectory().absolutePath
获取外部存储路径时返回的就是当前用户下的对应目录
例如 userId = 11 则返回为
/storage/emulated/11
多用户下的 /storage 分区有不同的用户家目录
可以看出常用的 /sdcard 目录其实最终也是软链到了 /storage/emulated/0 目录:
cmcc_jiangsu:/ # ls -l /storage/emulated/
total 8
drwxrwx--x 32 root sdcard_rw 4096 2022-07-25 11:35 0
drwxrwx--x 2 root sdcard_rw 4096 2015-01-01 08:00 obb
cmcc_jiangsu:/ # ls -l /sdcard
lrwxrwxrwx 1 root root 21 1970-01-01 08:00 /sdcard -> /storage/self/primary
cmcc_jiangsu:/ # ls -l /storage/self/primary
lrwxrwxrwx 1 root root 19 2015-01-01 08:00 /storage/self/primary -> /mnt/user/0/primary
cmcc_jiangsu:/ # ls -l /mnt/user/0/primary
lrwxrwxrwx 1 root reserved_disk 19 2015-01-01 08:00 /mnt/user/0/primary -> /storage/emulated/0
cmcc_jiangsu:/ #
%%%%%
多用户下的 /data 分区也有不同用户的家目录
也是以用户 UID 命名
与 External Storage/外部存储器 相同
新用户创建时 Android 也会在 /data/user 目录下创建名为 userId 的目录
用于存储该用户中所有 App 的隐私数据
如果在代码中使用 Context.getFilesDir() 来获取应用的 data 目录不同 User 下也会有不同
也可以看出来平常说到的 /data/data 目录其实也是软链到了 /data/user/0
cmcc_jiangsu:/ # ls /data/user -alh
total 6.0K
drwx--x--x 2 system system 4.0K 2015-01-01 08:00 .
drwxrwx--x 40 system system 4.0K 2015-01-01 08:00 ..
lrwxrwxrwx 1 root root 10 2015-01-01 08:00 0 -> /data/data
cmcc_jiangsu:/ # ls -l /data/user/0/
android.ext.services/ com.android.sharedstoragebackup/
android.ext.shared/ com.android.shell/
android/ com.android.statementservice/
com.android.backupconfirm/ com.android.superuser/
com.android.bluetooth/ com.android.systemui/
com.android.certinstaller/ com.android.dialogs/
com.android.companiondevicemanager/ com.android.webview/
com.android.defcontainer/ com.cmcc.mid.softdetector/
com.android.externalstorage/ com.dangbei.tvlauncher/
com.android.inputdevices/ com.dangbeimarket/
com.android.inputmethod.latin/ com.droidlogic.BluetoothRemote/
com.android.keychain/ com.droidlogic.inputmethod.remote/
com.android.location.fused/ com.droidlogic/
com.android.managedprovisioning/ com.fengyun.live/
com.android.packageinstaller/ com.iflytek.bt.auto/
com.android.pacprocessor/ com.iflytek.xiri/
com.android.providers.downloads/ com.iflytek.xiri2.system/
com.android.providers.media/ com.mylejia.store/
com.android.providers.settings/ com.tv.kuaisou/
com.android.proxyhandler/ com.xiaodianshi.tv.yst/
com.android.se/ jackpal.androidterm/
com.android.settings/ me.thomastv.rebootupdate/
cmcc_jiangsu:/ # ls -lh /data/user/0/com.android.shell/
total 4.0K
drwxrws--x 2 shell shell 4.0K 2015-01-01 08:00 cache
drwxrws--x 2 shell shell 4.0K 2015-01-01 08:00 code_cache
cmcc_jiangsu:/ #
——————————
%%%%%
多用户其实是系统为应用的 data 目录和 storage 目录分配了一份不同且独立的存储空间
不同用户下的存储空间互不影响且没有权限访问
/storage 目录不可以跨用户访问
例如用户 10 的 app 是无法访问 /storage/emulated/0 下的文件的
是不可以互相访问的
同时系统中的 AMS、PMS、WMS 等各大服务都会针对 userId/UserHandle 进行多用户适配
并在用户启动、切换、停止、删除等生命周期时做出相应策略的改变
%%%%%
多用户的创建流程主要在
UserManagerService.createUserInternalUnchecked()
函数中完成
用户创建的过程主要是应用运行环境例如文件系统、权限等的准备过程
主要可以分为六个步骤
第一步 为新用户创建一个新的 userId
新用户的 userId 从 10 开始递增
第二步 固化新用户信息和创建状态
构造包含新用户信息的 UserData 并固化到 /data/system/users/${userId}.xml 中:
cmcc_jiangsu:/ # cat /data/system/users/0.xml
cmcc_jiangsu:/ #
将新创建新 userId 固化到 /data/system/users/userlist.xml 中:
cmcc_jiangsu:/ # cat /data/system/users/userlist.xml
cmcc_jiangsu:/ #
第三步 准备文件系统
通过 vold 这个 Android 存储守护进程为新用户进行文件系统加密
创建 /data/system/users/${userId} 并设置 0700 权限
cmcc_jiangsu:/ # ls -alh /data/system/users/
total 10K
drwxrwxr-x 3 system system 4.0K 2015-01-01 08:00 .
drwxrwxr-x 19 system system 4.0K 2022-07-27 19:29 ..
drwx------ 2 system system 4.0K 2022-07-27 19:20 0
-rw------- 1 system system 298 2015-01-01 08:00 0.xml
-rw------- 1 system system 335 2015-01-01 08:00 userlist.xml
cmcc_jiangsu:/ #
创建 /data/misc/users/${userId} 并设置 0750 权限
cmcc_jiangsu:/ # ls /data/misc/user/ -alh
total 6.0K
drwxrwx--x 3 root root 4.0K 2015-01-01 08:00 .
drwxrwx--t 43 system misc 4.0K 2015-01-01 08:00 ..
drwxr-x--- 2 system everybody 4.0K 2015-01-01 08:00 0
cmcc_jiangsu:/ #
第四步 为已安装应用准备数据目录并记录其组件和默认权限配置
在 /data/user/${userId}/ 下创建各个已安装应用的 package 目录
cmcc_jiangsu:/ # ls /data/user/0/
android com.android.sharedstoragebackup
android.ext.services com.android.shell
android.ext.shared com.android.statementservice
com.android.backupconfirm com.android.superuser
com.android.bluetooth com.android.systemui
com.android.certinstaller com.android.dialogs
com.android.companiondevicemanager com.android.webview
com.android.defcontainer com.cmcc.mid.softdetector
com.android.externalstorage com.dangbei.tvlauncher
com.android.inputdevices com.dangbeimarket
com.android.inputmethod.latin com.droidlogic
com.android.keychain com.droidlogic.BluetoothRemote
com.android.location.fused com.droidlogic.inputmethod.remote
com.android.managedprovisioning com.fengyun.live
com.android.packageinstaller com.iflytek.bt.auto
com.android.pacprocessor com.iflytek.xiri
com.android.providers.downloads com.iflytek.xiri2.system
com.android.providers.media com.mylejia.store
com.android.providers.settings com.tv.kuaisou
com.android.proxyhandler com.xiaodianshi.tv.yst
com.android.se jackpal.androidterm
com.android.settings me.thomastv.rebootupdate
cmcc_jiangsu:/ #
在 /data/system/users/${userId}/package-restrictions.xml 中写入非默认启动组件的信息
cmcc_jiangsu:/ # cat /data/system/users/0/package-restrictions.xml
cmcc_jiangsu:/ #
更新 /data/system/packages.list 文件主要是最后一串 gids 可能会改变
cmcc_jiangsu:/ # cat /data/system/packages.list
com.iflytek.xiri 10021 0 /data/user/0/com.iflytek.xiri default:targetSdkVersion=19 3002,3003,3001
com.droidlogic.inputmethod.remote 10022 0 /data/user/0/com.droidlogic.inputmethod.remote default:targetSdkVersion=28 none
com.xiaodianshi.tv.yst 10032 0 /data/user_de/0/com.xiaodianshi.tv.yst default:targetSdkVersion=26 3003
com.android.providers.media 10002 0 /data/user/0/com.android.providers.media media:privapp:targetSdkVersion=28 2001,1065,1023,1015,3003,3007,1024
com.mylejia.store 10026 0 /data/user_de/0/com.mylejia.store default:targetSdkVersion=24 3003,1007
com.android.externalstorage 10004 0 /data/user/0/com.android.externalstorage platform:privapp:targetSdkVersion=28 1023,1015
com.android.companiondevicemanager 10012 0 /data/user/0/com.android.companiondevicemanager default:targetSdkVersion=28 3002,3001
com.android.providers.downloads 10002 0 /data/user/0/com.android.providers.downloads media:privapp:targetSdkVersion=28 2001,1065,1023,1015,3003,3007,1024
com.fengyun.live 10027 0 /data/user_de/0/com.fengyun.live default:targetSdkVersion=24 3003
com.droidlogic 1000 0 /data/user/0/com.droidlogic platform:privapp:targetSdkVersion=28 1065,3002,1023,1015,3003,3001,1007
com.dangbei.tvlauncher 10016 0 /data/user/0/com.dangbei.tvlauncher default:targetSdkVersion=22 3002,3003,3001
com.android.defcontainer 10000 0 /data/user_de/0/com.android.defcontainer platform:privapp:targetSdkVersion=28 2001
com.android.pacprocessor 10017 0 /data/user/0/com.android.pacprocessor platform:targetSdkVersion=28 3003
com.android.certinstaller 10013 0 /data/user/0/com.android.certinstaller platform:targetSdkVersion=28 none
me.thomastv.rebootupdate 10024 0 /data/user_de/0/me.thomastv.rebootupdate default:targetSdkVersion=25 none
android 1000 0 /data/system platform:privapp:targetSdkVersion=28 1065,3002,1023,1015,3003,3001,1007
com.android.backupconfirm 10001 0 /data/user/0/com.android.backupconfirm platform:privapp:targetSdkVersion=28 none
com.android.statementservice 10009 0 /data/user/0/com.android.statementservice default:privapp:targetSdkVersion=28 3003
com.android.superuser 10019 1 /data/user/0/com.android.superuser default:targetSdkVersion=22 none
com.android.providers.settings 1000 0 /data/user_de/0/com.android.providers.settings platform:privapp:targetSdkVersion=28 1065,3002,1023,1015,3003,3001,1007
com.android.sharedstoragebackup 10007 0 /data/user/0/com.android.sharedstoragebackup platform:privapp:targetSdkVersion=28 1023,1015
com.iflytek.xiri2.system 1000 0 /data/user/0/com.iflytek.xiri2.system platform:privapp:targetSdkVersion=28 1065,3002,1023,1015,3003,3001,1007
com.android.webview 10023 0 /data/user/0/com.android.webview default:targetSdkVersion=28 3003
com.android.se 1068 0 /data/user/0/com.android.se platform:privapp:targetSdkVersion=28 none
com.android.inputdevices 1000 0 /data/user_de/0/com.android.inputdevices platform:privapp:targetSdkVersion=28 1065,3002,1023,1015,3003,3001,1007
com.droidlogic.BluetoothRemote 1000 0 /data/user/0/com.droidlogic.BluetoothRemote platform:privapp:targetSdkVersion=28 1065,3002,1023,1015,3003,3001,1007
android.ext.shared 10015 0 /data/user_de/0/android.ext.shared platform:targetSdkVersion=28 none
com.android.keychain 1000 0 /data/user/0/com.android.keychain platform:privapp:targetSdkVersion=28 1065,3002,1023,1015,3003,3001,1007
android.ext.services 10003 0 /data/user_de/0/android.ext.services platform:privapp:targetSdkVersion=28 none
com.android.packageinstaller 10008 0 /data/user_de/0/com.android.packageinstaller platform:privapp:targetSdkVersion=28 1065
com.android.proxyhandler 10006 0 /data/user_de/0/com.android.proxyhandler platform:privapp:targetSdkVersion=28 3003
com.android.inputmethod.latin 10020 0 /data/user_de/0/com.android.inputmethod.latin default:targetSdkVersion=23 none
com.android.managedprovisioning 10005 0 /data/user/0/com.android.managedprovisioning platform:privapp:targetSdkVersion=28 3003
jackpal.androidterm 10031 0 /data/user_de/0/jackpal.androidterm default:targetSdkVersion=22 3003
com.iflytek.bt.auto 10014 0 /data/user/0/com.iflytek.bt.auto default:targetSdkVersion=28 3002,3001
com.android.settings 1000 1 /data/user/0/com.android.settings platform:privapp:targetSdkVersion=28 1065,3002,1023,1015,3003,3001,1007
com.android.dialogs 10010 0 /data/user/0/com.android.dialogs platform:privapp:targetSdkVersion=28 none
com.android.shell 2000 0 /data/user_de/0/com.android.shell platform:privapp:targetSdkVersion=28 1065,3002,1023,1015,1002,3010,3011
com.dangbeimarket 10025 0 /data/user_de/0/com.dangbeimarket default:targetSdkVersion=19 3002,3003,3001
com.android.location.fused 1000 0 /data/user_de/0/com.android.location.fused platform:privapp:targetSdkVersion=28 1065,3002,1023,1015,3003,3001,1007
com.android.systemui 10011 0 /data/user_de/0/com.android.systemui platform:privapp:targetSdkVersion=28 1065,3002,1023,1015,3001,3006
com.tv.kuaisou 10028 0 /data/user_de/0/com.tv.kuaisou default:targetSdkVersion=22 3002,3003,3001
com.android.bluetooth 1002 0 /data/user_de/0/com.android.bluetooth platform:privapp:targetSdkVersion=28 3002,3003,3001,3007,1002,3010,3011,3005,1016
com.cmcc.mid.softdetector 10018 0 /data/user/0/com.cmcc.mid.softdetector default:targetSdkVersion=17 3003
cmcc_jiangsu:/ #
这个改变的可能性是根据 permUser 的配置来决定
第五步 固化新用户创建完成的状态、通知 PMS 为新用户和应用赋予默认的权限
第六步 发送 ACTION_USER_ADDED 广播 新用户创建完成
%%%%%
Android 多用户的切换函数入口是
ActivityManagerService.switchUser()
AMS 的 startUser 方法只是判断了是否展示切换用户的 Dialog
最终都会调用到 UserController.startUser 这个函数中
方法很长 涉及到 AMS 和 WMS 的方法分支也很多
切换分为前台切换和后台切换 这里从前台切换 并且对用户未启动的情况总结下关键的切换过程
第一步 切换前冻结屏幕 禁止一切输入操作
这个过程在屏幕旋转的过程中也会执行 因此截取屏幕并展示也是采用和横竖屏切换一样的方式
冻结输入事件
强制结束 App 动画
截取当前屏幕并显示
如果是待启动用户 则初始化待启动用户的状态为 STATE_BOOTING
第二步 为待切换用户更改系统配置 设置 Keyguard
从 SettingsProvider 读取待切换用户的字体、语言、地区等配置并更新到系统
如果是初创用户 则字体使用默认配置 语言和地区使用当前用户的配置
为待切换用户更新资源 如 Attributes、Drawable、Color、Animator、StateList 等
有兴趣可以重点看下 AMS 的 updateGlobalConfiguration()
修改当前用户下所有 Window 的可见性 启动 Keyguard 切换过程中关闭 Keyguard 的指纹监听 并设置锁屏
在 Android 8.0 以前 Keyguard 是一个单独的 System App
8.0 后将其移至 SystemUI 中 该模块的功能主要有 展示和隐藏锁屏界面 认证和校验锁屏密码、指纹密码 等
如果是待启动用户 为待启动用户设置权限 校验或准备待启动用户的 App 存储目录
通知系统所有服务新用户正在启动 如 JobSchedulerService 会根据 Job 对应的用户是否启动来决定 Job 的维护
第三步 并行通知系统所有服务用户开始切换
系统所有服务及相关监听者在收到开始切换的消息后进行一系列的操作
也是用户切换所要完成的核心任务
所有系统服务及相关监听者完成切换任务后 执行 UserController.continueUserSwitch()
第四步 设置切换超时定时器
设置 3s 的延迟消息
如果 3s 内没有完成用户切换 则取消该消息 终止切换过程并执行 UserController.continueUserSwitch()
第五步 将待切换用户拉到前台
stop 当前用户下所有的 Activity
修改所有 ActivityStack 中 TaskRecord 的顺序 将切换用户或者在两个用户中都能运行的 Task 移动到栈顶
将最顶端 Task 对应的 Window 移动到最顶端
取出切换应用之前存在的前台 Activity 置于前台并 resume 如果没有前台应用 则启动 HomeActivity
发送用户切换广播
如果是后台切换 则发送 ACTION_USER_BACKGROUND
如果是前台切换 则发送 ACTION_USER_FOREGROUND 和 ACTION_USER_SWITCHED
第六步 切换超时消息到达时需要继续进行的切换操作
在
设置切换超时定时器
和
将待切换用户拉到前台
中切换超时消息到达时需要继续进行的切换操作 continueUserSwitch
解冻屏幕和输入
设置 Keyguard 如果切换用户设置了指纹 则需要开始监听指纹信息通知监听者用户已经完成了切换
第七步 完成切换用户
如果是后台切换
则直接调用 UserController.finishUserBoot()
如果是前台切换
ActivityThread 会在 handleResumeActivity 时设置 Main 线程 MessageQueue 的 mIdleHandlers
在 MessageQueue 执行 next() 会检查该列表并最终调用到 AMS 的 activityIdle() 中
此时会检查正在切换的用户列表并调用最终调用到 UserController.finishUserBoot()
设置切换用户的状态为 STATE_RUNNING_LOCKED
如果是新启动的用户,则通知系统所有用户监听者用户已经启动
并发送 ACTION_LOCKED_BOOT_COMPLETED 广播
在 Keyguard 第一次解锁时 会发送 ACTION_BOOT_COMPLETED 广播
——————————
%%%%%
安装 APP 时权限的获取记录存储在
/data/system/packages.xml
cmcc_jiangsu:/ # cat /data/system/packages.xml | grep xiaodianshi /* 查看关于 bilibili tv 的权限 */
cmcc_jiangsu:/ # cat /data/system/packages.xml | grep jackpal.androidterm
cmcc_jiangsu:/ # pm list packages -3 /* 查看第三方应用 */
package:com.xiaodianshi.tv.yst
package:com.mylejia.store
package:com.fengyun.live
package:me.thomastv.rebootupdate
package:jackpal.androidterm
package:com.dangbeimarket
package:com.tv.kuaisou
cmcc_jiangsu:/ # cat /data/system/packages.xml | grep com.dangbeimarket /* 查看当贝市场权限 */
cmcc_jiangsu:/ #
%%%%%
运行时权限的获取记录存储在
/data/system/users/$userId/runtime-permissions.xml
cmcc_jiangsu:/ # cat /data/system/users/0/runtime-permissions.xml
cmcc_jiangsu:/ #
%%%%%
Android 系统和应用安装后的权限声明保存在
/etc/permissions/
目录下:
cmcc_jiangsu:/ # ls /etc/permissions/
android.hardware.bluetooth.xml com.android.media.remotedisplay.xml
android.hardware.bluetooth_le.xml com.android.mediadrm.signer.xml
android.hardware.hdmi.cec.xml platform.xml
android.software.webview.xml privapp-permissions-platform.xml
com.android.location.provider.xml
cmcc_jiangsu:/ #
如果要查看最常使用的 platform 权限可以:
cat /etc/permissions/platform.xml | more
可以简单看一下这个配置文件 每个我们常见的权限都可能对应一个或多个 group gid
而我们上面说的 gids 就是由这个 group gid 生成的集合
——————————
%%%%%
语法如下:
pm grant 包名 权限 /* 授予权限 */
pm revoke 包名 权限 /* 移除权限*/
示例为终端模拟器添加删除写文件权限:
cmcc_jiangsu:/ # pm grant jackpal.androidterm android.permission.WRITE_EXTERNAL_STORAGE
cmcc_jiangsu:/ # pm revoke jackpal.androidterm android.permission.WRITE_EXTERNAL_STORAGE
cmcc_jiangsu:/ #
其她常用权限:
android.permission.CAMERA /* 相机权限 */
android.permission.READ_EXTERNAL_STORAGE /* 读文件权限 */
android.permission.WRITE_EXTERNAL_STORAGE /* 写文件权限 */
%%%%%
Android 系统上每一个独立的应用运行在不同的系统空间
以 User ID 和 Group ID 来标识
不同应用之间互相访问数据接口资源就牵涉到权限问题
关于用户 ID
我们在安装一个应用的时候系统就会为这个应用分配一个 userid
这个 userid 是全局唯一的
在同一 Android 系统的机器上不可能存在两个相同 userid 的应用
也就是说 userid 对于一个应用来说是唯一不变的 除非你卸载重新安装了该应用
但是 userid 并不像 MAC 地址一样是全球唯一的 同一个应用在不同的设备上 userid 可能会不同
这里所说的唯一是指在同一个 Android 设备上
Android 的安全机制是进程级别的
通常情况下一个应用就是一个进程
并且一个应用也只有一个进程
当然应用内实现多进程这个是没有任何问题的
这里是说一般情况下
应用 A 是无法直接运行在应用 B 的进程当中的
但是有一点就是除非应用 A 和应用 B 使用了相同的 shareduserid
配置了相同的 shareduserid 的应用被系统视作同一个应用 对应的 userid 和权限都是相同的
但是如果仅仅是配置了相同的 shareduserid 就能够到达目的 显然这是一个很大的漏洞
为此谷歌做了另外一个限制 就是必须保证签名一致
一般的 A 公司的签名肯定是跟 B 公司的签名是不一样的
也就是说想要应用 A 和应用 B 运行在同一个进程当中那么肯定得保证签名和 shareduserid 是一致的
shareduserid 保持一致这个很容易满足 但是签名一致恐怕只能是同一个公司
应用的数据和 user id 是相对应的 默认情况下其她应用是无法访问的
但是如果我们设置了 MODE_WORLD_READABLE 或者 MODE_WORLD_WRITEABLE 的 flag
那么其她应用就可以变得可读可写了 也就是说这些数据就变成了全局的数据
我们知道 Android 系统从 4.2 版本开始支持多用户
也就产生了用户 id 的概念 uid
在这里 uid 和 userid 是两个完全不同的概念
android 中的用户是存在物理文件级数据差异的
例如有两个用户 用户 id 分别是 0 和 10
用户 10 安装了应用 A 此时对于用户 0 来说是完全不可见的
不像两个应用 A 和 B 两者的数据虽然默认情况下是不能互相访问的 但是我们有办法能够实现
那么用户 id 到底是什么:
简单的说用户 id 就是当前用户下为了各个应用之间数据共享和访问的
在 Android 系统中有些常用的 userid 是提前定义好的
例如 system 的用户 id 就是 1000 这个是在代码中提前定义好的
%%%%%
示例使用 dumpsys package 命令获取 终端模拟器 这个应用的所有信息:
cmcc_jiangsu:/ # dumpsys package jackpal.androidterm
Activity Resolver Table:
Full MIME Types:
*/*:
6eb5070 jackpal.androidterm/.TermHere filter 85f0431
Action: "android.intent.action.SEND"
Category: "android.intent.category.DEFAULT"
Type: "*"
mPriority=0, mOrder=0, mHasPartialTypes=true
b538fe9 jackpal.androidterm/.shortcuts.FSNavigator filter e12d733
Action: "android.intent.action.GET_CONTENT"
Category: "android.intent.category.DEFAULT"
Category: "android.intent.category.OPENABLE"
Type: "*"
mPriority=0, mOrder=0, mHasPartialTypes=true
Wild MIME Types:
*:
6eb5070 jackpal.androidterm/.TermHere filter 85f0431
Action: "android.intent.action.SEND"
Category: "android.intent.category.DEFAULT"
Type: "*"
mPriority=0, mOrder=0, mHasPartialTypes=true
b538fe9 jackpal.androidterm/.shortcuts.FSNavigator filter e12d733
Action: "android.intent.action.GET_CONTENT"
Category: "android.intent.category.DEFAULT"
Category: "android.intent.category.OPENABLE"
Type: "*"
mPriority=0, mOrder=0, mHasPartialTypes=true
Non-Data Actions:
jackpal.androidterm.RUN_SHORTCUT:
3602f82 jackpal.androidterm/.RunShortcut filter 45c4897
Action: "jackpal.androidterm.RUN_SHORTCUT"
Category: "android.intent.category.DEFAULT"
jackpal.androidterm.private.SWITCH_WINDOW:
65c1ce jackpal.androidterm/.TermInternal filter 2d8abbb
Action: "jackpal.androidterm.private.SWITCH_WINDOW"
Category: "android.intent.category.DEFAULT"
jackpal.androidterm.OPEN_NEW_WINDOW:
d877d32 jackpal.androidterm/.RemoteInterface filter 83648d8
Action: "jackpal.androidterm.OPEN_NEW_WINDOW"
Category: "android.intent.category.DEFAULT"
android.intent.action.MAIN:
6ee9b65 jackpal.androidterm/.Term filter 8b301b5
Action: "android.intent.action.MAIN"
Category: "android.intent.category.LAUNCHER"
Category: "android.intent.category.MULTIWINDOW_LAUNCHER"
c0f203a jackpal.androidterm/.shortcuts.AddShortcut filter 5331a84
Action: "android.intent.action.MAIN"
android.intent.action.PICK:
b538fe9 jackpal.androidterm/.shortcuts.FSNavigator filter 34d5ea2
Action: "android.intent.action.PICK"
Category: "android.intent.category.DEFAULT"
jackpal.androidterm.RUN_SCRIPT:
c6dd21d jackpal.androidterm/.RunScript filter 2a1e716
Action: "jackpal.androidterm.RUN_SCRIPT"
Category: "android.intent.category.DEFAULT"
jackpal.androidterm.private.OPEN_NEW_WINDOW:
65c1ce jackpal.androidterm/.TermInternal filter 5bb104a
Action: "jackpal.androidterm.private.OPEN_NEW_WINDOW"
Category: "android.intent.category.DEFAULT"
android.intent.action.CREATE_SHORTCUT:
c0f203a jackpal.androidterm/.shortcuts.AddShortcut filter eeeb26d
Action: "android.intent.action.CREATE_SHORTCUT"
MIME Typed Actions:
android.intent.action.SEND:
6eb5070 jackpal.androidterm/.TermHere filter 85f0431
Action: "android.intent.action.SEND"
Category: "android.intent.category.DEFAULT"
Type: "*"
mPriority=0, mOrder=0, mHasPartialTypes=true
android.intent.action.GET_CONTENT:
b538fe9 jackpal.androidterm/.shortcuts.FSNavigator filter e12d733
Action: "android.intent.action.GET_CONTENT"
Category: "android.intent.category.DEFAULT"
Category: "android.intent.category.OPENABLE"
Type: "*"
mPriority=0, mOrder=0, mHasPartialTypes=true
Service Resolver Table:
Non-Data Actions:
jackpal.androidterm.action.START_TERM.v1:
3f40e99 jackpal.androidterm/.TermService filter f7579ec
Action: "jackpal.androidterm.action.START_TERM.v1"
Category: "android.intent.category.DEFAULT"
Permissions:
Permission [jackpal.androidterm.permission.PREPEND_TO_PATH] (40775e5):
sourcePackage=jackpal.androidterm
uid=10031 gids=null type=0 prot=dangerous
perm=Permission{13728ba jackpal.androidterm.permission.PREPEND_TO_PATH}
packageSetting=PackageSetting{cc1336b jackpal.androidterm/10031}
Permissions:
Permission [jackpal.androidterm.permission.RUN_SCRIPT] (9ec705e):
sourcePackage=jackpal.androidterm
uid=10031 gids=null type=0 prot=dangerous
perm=Permission{a9cac3f jackpal.androidterm.permission.RUN_SCRIPT}
packageSetting=PackageSetting{cc1336b jackpal.androidterm/10031}
Permissions:
Permission [jackpal.androidterm.permission.APPEND_TO_PATH] (13fd63a):
sourcePackage=jackpal.androidterm
uid=10031 gids=null type=0 prot=dangerous
perm=Permission{65012eb jackpal.androidterm.permission.APPEND_TO_PATH}
packageSetting=PackageSetting{cc1336b jackpal.androidterm/10031}
Key Set Manager:
[jackpal.androidterm]
Signing KeySets: 17
Packages:
Package [jackpal.androidterm] (cc1336b):
userId=10031
pkg=Package{ab23cd9 jackpal.androidterm}
codePath=/data/app/jackpal.androidterm-sAgHElvcbHuZtUuQdCSIdQ==
resourcePath=/data/app/jackpal.androidterm-sAgHElvcbHuZtUuQdCSIdQ==
legacyNativeLibraryDir=/data/app/jackpal.androidterm-sAgHElvcbHuZtUuQdCSIdQ=
=/lib
primaryCpuAbi=armeabi
secondaryCpuAbi=null
versionCode=71 minSdk=4 targetSdk=22
versionName=1.0.70
splits=[base]
apkSigningVersion=1
applicationInfo=ApplicationInfo{544369e jackpal.androidterm}
flags=[ HAS_CODE ALLOW_CLEAR_USER_DATA ALLOW_BACKUP ]
privateFlags=[ DEFAULT_TO_DEVICE_PROTECTED_STORAGE DIRECT_BOOT_AWARE ]
dataDir=/data/user_de/0/jackpal.androidterm
supportsScreens=[small, medium, large, xlarge, resizeable, anyDensity]
usesLibraries:
org.apache.http.legacy
usesLibraryFiles:
/system/framework/org.apache.http.legacy.boot.jar
timeStamp=2022-07-23 23:53:02
firstInstallTime=2022-07-23 23:53:02
lastUpdateTime=2022-07-23 23:53:02
signatures=PackageSignatures{2e3957f version:1, signatures:[e7b54ff0], past
signatures:[]}
installPermissionsFixed=true
pkgFlags=[ HAS_CODE ALLOW_CLEAR_USER_DATA ALLOW_BACKUP ]
declared permissions:
jackpal.androidterm.permission.RUN_SCRIPT: prot=dangerous, INSTALLED
jackpal.androidterm.permission.APPEND_TO_PATH: prot=dangerous, INSTALLED
jackpal.androidterm.permission.PREPEND_TO_PATH: prot=dangerous, INSTALLED
requested permissions:
android.permission.INTERNET
android.permission.READ_EXTERNAL_STORAGE
android.permission.WRITE_EXTERNAL_STORAGE
android.permission.ACCESS_SUPERUSER
android.permission.WAKE_LOCK
install permissions:
android.permission.INTERNET: granted=true
android.permission.READ_EXTERNAL_STORAGE: granted=true
android.permission.WRITE_EXTERNAL_STORAGE: granted=true
android.permission.WAKE_LOCK: granted=true
User 0: ceDataInode=-4294966708 installed=true hidden=false suspended=false
stopped=false notLaunched=false enabled=0 instant=false virtual=false
gids=[3003]
runtime permissions:
Package Changes:
Sequence number=0
Dexopt state:
[jackpal.androidterm]
path: /data/app/jackpal.androidterm-sAgHElvcbHuZtUuQdCSIdQ==/base.apk
arm: [status=speed-profile] [reason=install]
Compiler stats:
[jackpal.androidterm]
(No recorded stats)
cmcc_jiangsu:/ #
获取 userid 可以使用 dumpsys package 搭配 grep 筛选 userId 和 gids:
cmcc_jiangsu:/ # dumpsys package jackpal.androidterm | grep userId
userId=10031
cmcc_jiangsu:/ # dumpsys package jackpal.androidterm | grep gids
uid=10031 gids=null type=0 prot=dangerous
uid=10031 gids=null type=0 prot=dangerous
uid=10031 gids=null type=0 prot=dangerous
gids=[3003]
cmcc_jiangsu:/ #
%%%%%
不同用户具有的权限不同
使用 dumpsys user 命令可以查看所有的用户信息 例如 userId、name、restrictions 等等:
cmcc_jiangsu:/ # dumpsys user
Users:
UserInfo{0:null:13} serialNo=0
State: RUNNING_UNLOCKED
Created:
Last logged in: +2762d4h27m19s3ms ago
Last logged in fingerprint: CM311-1a-YST/CM311-1a-YST/CM311-1a-YST:9/PPR1.18
0610.011/V.955.05:userdebug/test-keys
Start time: +1h8m33s992ms ago
Unlock time: +1h8m33s812ms ago
Has profile owner: false
Restrictions:
none
Device policy global restrictions:
null
Device policy local restrictions:
null
Effective restrictions:
none
Device owner id:-10000
Guest restrictions:
no_sms
no_install_unknown_sources
no_config_wifi
no_outgoing_calls
Device managed: false
Started users state: {0=3}
Max users: 1
Supports switchable users: false
All guests ephemeral: false
cmcc_jiangsu:/ #
解释一下 访客用户/Guest 的默认权限限制:
Guest restrictions: /* 来宾账户限制 */
no_sms /* 限制发送短信 */
no_install_unknown_sources /* 限制安装软件 */
no_config_wifi /* 限制配置 WiFi */
no_outgoing_calls /* 限制拨打电话 */
这些权限可以在创建用户时规定也可以后期由系统动态设置
特殊权限的用户:
用户 uid
system 1000
radio 1001
%%%%%
不同用户下的 App 应用权限也是独立的
上面说了 uid 与 userId 存在一种计算关系
appUid = userId * 1000000 + appId
而在系统中对于权限控制也是根据 uid 和对应的 userId 来判定的
因此不同用户下相同应用可以具有不同的权限
查看所有已知的权限组和单独权限组的权限:
cmcc_jiangsu:/ # pm list permission-groups /* 查看所有已知的权限组 */
permission group:android.permission-group.CONTACTS
permission group:android.permission-group.PHONE
permission group:android.permission-group.CALENDAR
permission group:android.permission-group.CALL_LOG
permission group:android.permission-group.CAMERA
permission group:android.permission-group.SENSORS
permission group:android.permission-group.LOCATION
permission group:android.permission-group.STORAGE
permission group:droidlogic.permission-group.SYSTEM_CONTROL
permission group:android.permission-group.MICROPHONE
permission group:android.permission-group.SMS
cmcc_jiangsu:/ # pm list permissions android.permission-group.CONTACTS /* 查看单独的权限组都有什么权限 */
All Permissions:
permission:android.permission.WRITE_CONTACTS
permission:android.permission.GET_ACCOUNTS
permission:android.permission.READ_CONTACTS
cmcc_jiangsu:/ # pm list permissions android.permission-group.PHONE
All Permissions:
permission:android.permission.ACCESS_UCE_OPTIONS_SERVICE
permission:android.permission.ANSWER_PHONE_CALLS
permission:android.permission.READ_PHONE_NUMBERS
permission:android.permission.READ_PHONE_STATE
permission:android.permission.CALL_PHONE
permission:android.permission.ACCESS_UCE_PRESENCE_SERVICE
permission:android.permission.ACCEPT_HANDOVER
permission:android.permission.USE_SIP
permission:com.android.voicemail.permission.ADD_VOICEMAIL
cmcc_jiangsu:/ # pm list permissions android.permission-group.CALENDAR
All Permissions:
permission:android.permission.READ_CALENDAR
permission:android.permission.WRITE_CALENDAR
cmcc_jiangsu:/ # pm list permissions android.permission-group.CALL_LOG
All Permissions:
permission:android.permission.READ_CALL_LOG
permission:android.permission.WRITE_CALL_LOG
permission:android.permission.PROCESS_OUTGOING_CALLS
cmcc_jiangsu:/ # pm list permissions android.permission-group.CAMERA
All Permissions:
permission:android.permission.CAMERA
cmcc_jiangsu:/ # pm list permissions android.permission-group.SENSORS
All Permissions:
permission:android.permission.BODY_SENSORS
permission:android.permission.USE_FINGERPRINT
permission:android.permission.USE_BIOMETRIC
cmcc_jiangsu:/ # pm list permissions android.permission-group.LOCATION
All Permissions:
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION
cmcc_jiangsu:/ # pm list permissions android.permission-group.STORAGE
All Permissions:
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE
cmcc_jiangsu:/ # pm list permissions droidlogic.permission-group.SYSTEM_CONTROL
All Permissions:
permission:droidlogic.permission.SYSTEM_CONTROL
cmcc_jiangsu:/ # pm list permissions android.permission-group.MICROPHONE
All Permissions:
permission:android.permission.RECORD_AUDIO
cmcc_jiangsu:/ # pm list permissions android.permission-group.SMS
All Permissions:
permission:android.permission.READ_SMS
permission:android.permission.RECEIVE_WAP_PUSH
permission:android.permission.RECEIVE_MMS
permission:android.permission.RECEIVE_SMS
permission:android.permission.SEND_SMS
permission:android.permission.READ_CELL_BROADCASTS
cmcc_jiangsu:/ #
permissions 的参数可以组合使用:
-g 按组进行列出权限
-f 打印所有信息
-s 简短的摘要
-d 只有危险的权限列表
-u 只有权限的用户将看到列表 用户自定义权限
例如:
pm list permissions -g -d 权限组
示例:
cmcc_jiangsu:/ # pm list permissions -g -d android.permission-group.CONTACTS
Dangerous Permissions:
group:android.permission-group.CONTACTS
permission:android.permission.WRITE_CONTACTS
permission:android.permission.GET_ACCOUNTS
permission:android.permission.READ_CONTACTS
group:android.permission-group.PHONE
permission:android.permission.ANSWER_PHONE_CALLS
permission:android.permission.READ_PHONE_NUMBERS
permission:android.permission.READ_PHONE_STATE
permission:android.permission.CALL_PHONE
permission:android.permission.ACCEPT_HANDOVER
permission:android.permission.USE_SIP
permission:com.android.voicemail.permission.ADD_VOICEMAIL
group:android.permission-group.CALENDAR
permission:android.permission.READ_CALENDAR
permission:android.permission.WRITE_CALENDAR
group:android.permission-group.CALL_LOG
permission:android.permission.READ_CALL_LOG
permission:android.permission.WRITE_CALL_LOG
permission:android.permission.PROCESS_OUTGOING_CALLS
group:android.permission-group.CAMERA
permission:android.permission.CAMERA
group:android.permission-group.SENSORS
permission:android.permission.BODY_SENSORS
group:android.permission-group.LOCATION
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION
group:android.permission-group.STORAGE
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE
group:droidlogic.permission-group.SYSTEM_CONTROL
group:android.permission-group.MICROPHONE
permission:android.permission.RECORD_AUDIO
group:android.permission-group.SMS
permission:android.permission.READ_SMS
permission:android.permission.RECEIVE_WAP_PUSH
permission:android.permission.RECEIVE_MMS
permission:android.permission.RECEIVE_SMS
permission:android.permission.SEND_SMS
permission:android.permission.READ_CELL_BROADCASTS
ungrouped:
cmcc_jiangsu:/ #
再或者查看描述:
cmcc_jiangsu:/ # pm list permissions -s
All Permissions:
通讯录: 修改您的通讯录, 查找设备上的帐号, 读取联系人
电话: null, 接听来电, 读取电话号码, 读取手机状态和身份, 拨打电话, null, null, 拨
打/接听SIP电话, 添加语音邮件
日历: 读取日历活动和详情, 添加或修改日历活动,并在所有者不知情的情况下向邀请对象
发送电子邮件
通话记录: 读取通话记录, 新建/修改/删除通话记录, 重新设置外拨电话的路径
相机: 拍摄照片和视频
身体传感器: 访问身体传感器(如心率监测器), 使用指纹硬件, 使用生物特征硬件
位置信息: 访问确切位置信息(以 GPS 和网络为依据), 访问大致位置信息(以网络为依
据)
存储空间: 读取您的USB存储设备中的内容, 修改或删除您的USB存储设备中的内容
droidlogic权限组: droidlogic 系统控制权限
麦克风: 录音
短信: 读取短信, 接收讯息 (WAP), 接收讯息(彩信), 接收讯息(短信), 发送短信, 读
取小区广播消息
ungrouped:
null, null, null, null, null, null, null, 修改系统设置, null, null, null, null,
null, 建立或中断 WiMAX 网络连接, null, null, null, null, null, null, null, null,
关闭其他应用, null, null, null, null, null, null, null, null, 更改您的音频设置,
null, null, null, null, “勿扰”模式使用权限, null, null, null, null, null, nul
l, null, null, null, null, null, null, null, null, null, null, null, null, 此应
用可显示在其他应用上方, null, 绑定到运营商服务, null, null, null, null, null, nu
ll, null, null, null, null, 将蓝牙设备列入访问权限白名单。, null, null, null, nu
ll, null, null, 控制近距离通信, null, null, null, null, null, null, null, null,
null, null, 发送下载通知。, null, null, null, null, null, 更改网络连接性, null,
null, 运行前台服务, 让应用始终运行, null, 启用和停用同步, null, 在后台使用数据,
null, null, null, null, 开机启动, null, null, null, null, null, null, 设置时区,
null, null, null, 展开/收拢状态栏, 卸载快捷方式, 管理个人资料和设备所有者, 请求
忽略电池优化, null, null, 与蓝牙设备配对, null, 允许接收WLAN多播, null, null, nu
ll, 设置闹钟, null, null, null, null, null, null, null, null, 检索正在运行的应用
, null, null, null, null, null, 拥有完全的网络访问权限, null, null, 发射红外线,
null, 对正在运行的应用重新排序, null, null, null, 在后台运行, 访问蓝牙设置, null
, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, 计算应用存储空间, null, null, null, nu
ll, null, null, null, null, 访问所有系统下载内容, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, nu
ll, null, null, null, null, null, null, null, null, null, null, null, null, 获取
额外的位置信息提供程序命令, null, null, null, 使用即时通讯通话服务, null, 访问下
载管理器。, 发送持久广播, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, 连接WLAN
网络和断开连接, null, null, 读取安装会话, null, null, null, null, null, null, nu
ll, null, null, 使用下载管理器。, null, null, null, null, null, null, null, null
, null, null, null, null, null, 查看网络连接, null, null, null, 停用屏幕锁定, nu
ll, null, null, null, null, null, null, null, null, null, 设置壁纸, null, null,
在后台使用数据, null, null, null, null, null, null, null, null, null, null, null
, null, null, null, null, null, 关闭其他应用, null, null, null, null, null, null
, null, null, null, null, null, 读取同步统计信息, 通过系统转接来电, null, null,
null, null, 保留下载缓存中的空间, null, null, null, null, null, 请求删除文件包,
null, null, null, null, null, null, null, null, null, null, null, null, null, nu
ll, null, null, null, null, null, null, null, null, null, null, null, null, null
, null, 调整您的壁纸大小, null, 读取同步设置, null, null, null, null, 在后台运行
, null, null, null, null, null, null, null, 控制振动, null, null, null, null, nu
ll, null, null, null, null, null, null, null, null, null, null, null, null, null
, null, null, null, null, null, null, null, null, null, null, null, null, null,
查看WLAN连接, null, null, null, null, null, 更改 WiMAX 状态, null, null, 请求安
装文件包, null, null, null, null, null, 安装快捷方式, null, null, null, null, nu
ll, null, null, null, null, 防止手机休眠, null, 高级下载管理器功能。, null, null
, null, null, null, null, null, null, null, null, null, null, null
cmcc_jiangsu:/ #
更简短的:
cmcc_jiangsu:/ # pm list permissions -g -d -s android.permission-group.CONTACTS
Dangerous Permissions:
通讯录: 修改您的通讯录, 查找设备上的帐号, 读取联系人
电话: 接听来电, 读取电话号码, 读取手机状态和身份, 拨打电话, null, 拨打/接听SIP电
话, 添加语音邮件
日历: 读取日历活动和详情, 添加或修改日历活动,并在所有者不知情的情况下向邀请对象
发送电子邮件
通话记录: 读取通话记录, 新建/修改/删除通话记录, 重新设置外拨电话的路径
相机: 拍摄照片和视频
身体传感器: 访问身体传感器(如心率监测器)
位置信息: 访问确切位置信息(以 GPS 和网络为依据), 访问大致位置信息(以网络为依
据)
存储空间: 读取您的USB存储设备中的内容, 修改或删除您的USB存储设备中的内容
droidlogic权限组: droidlogic 系统控制权限
麦克风: 录音
短信: 读取短信, 接收讯息 (WAP), 接收讯息(彩信), 接收讯息(短信), 发送短信, 读
取小区广播消息
ungrouped:
cmcc_jiangsu:/ #
——————————
%%%%%
平台版本 版本名称 API 级别 版本代码
Android 1.0 无 1 BASE
Android 1.1 无 2 BASE_1_1
Android 1.5 Cupcake 纸杯蛋糕 3 CUPCAKE
Android 1.6 Donut 甜甜圈 4 DONUT
Android 2.0 Eclair 闪电泡芙 5 ECLAIR
Android 2.0.1 Eclair 闪电泡芙 6 ECLAIR_0_1
Android 2.1.x Eclair 闪电泡芙 7 ECLAIR_MR1
Android 2.2.x Froyo 冻酸奶 8 FROYO
Android 2.3/2.3.1/2.3.2 Gingerbread 姜饼 9 GINGERBREAD
Android 2.3.3/2.3.4 Gingerbread 姜饼 10 GINGERBREAD_MR1
Android 3.0.x Honeycomb 蜂巢 11 HONEYCOMB
Android 3.1.x Honeycomb 蜂巢 12 HONEYCOMB_MR1
Android 3.2 Honeycomb 蜂巢 13 HONEYCOMB_MR2
Android 4.0/4.0.1/4.0.2 Ice Cream Sandwich 冰淇凌三明治 14 ICE_CREAM_SANDWICH
Android 4.0.3/4.0.4 Ice Cream Sandwich 冰淇凌三明治 15 ICE_CREAM_SANDWICH_MR1
Android 4.1/4.1.1 Jelly Bean 糖豆 16 JELLY_BEAN
Android 4.2/4.2.2 Jelly Bean 糖豆 17 JELLY_BEAN_MR2
Android 4.3 Jelly Bean 糖豆 18 JELLY_BEAN_MR3
Android 4.4 KitKat 奇巧巧克力棒 19 KITKAT
Android 4.4W KitKat 奇巧巧克力棒 20 KITKAT_WATCH
Android 5.0 Lollipop 棒棒糖 21 LOLLIPOP
Android 5.1 Lollipop 棒棒糖 22 LOLLIPOP_MR1
Android 6.0 Marshmallow 棉花糖 23 M
Android 7.0 Nougat 牛轧糖 24 N
Android 7.1 Nougat 牛轧糖 25 N_MR1
Android 8.0 Oreo 奥利奥 26 O
Android 8.1 Oreo 奥利奥 27 O_MR1
Android 9.0 Pie 馅饼 28 P
Android 10.0 Android 10 29 Q
Android 11 Android 11 R R
%%%%%
android.permission-group.CONTACTS /* 联系人权限组 */
通讯录: 修改您的通讯录, 查找设备上的帐号, 读取联系人
android.permission-group.PHONE /* 电话权限组 */
电话: 接听来电, 读取电话号码, 读取手机状态和身份, 拨打电话, null, 拨打/接听SIP电
话, 添加语音邮件
android.permission-group.CALENDAR /* 日历权限组组 */
日历: 读取日历活动和详情, 添加或修改日历活动,并在所有者不知情的情况下向邀请对象
发送电子邮件
android.permission-group.CALL_LOG /* 呼叫功能的权限组 */
通话记录: 读取通话记录, 新建/修改/删除通话记录, 重新设置外拨电话的路径
android.permission-group.CAMERA /* 相机权限组 */
相机: 拍摄照片和视频
android.permission-group.SENSORS /* 身体传感器权限组 */
身体传感器: 访问身体传感器(如心率监测器)
android.permission-group.LOCATION /* 位置权限组 */
位置信息: 访问确切位置信息(以 GPS 和网络为依据), 访问大致位置信息(以网络为依
据)
android.permission-group.STORAGE /* 外部存储权限组 */
存储空间: 读取您的USB存储设备中的内容, 修改或删除您的USB存储设备中的内容
droidlogic.permission-group.SYSTEM_CONTROL /* 系统控制权限组 */
droidlogic权限组: droidlogic 系统控制权限
android.permission-group.MICROPHONE /* 麦克风权限组 */
麦克风: 录音
android.permission-group.SMS /* 短信权限组 */
短信: 读取短信, 接收讯息 (WAP), 接收讯息(彩信), 接收讯息(短信), 发送短信, 读
取小区广播消息
%%%%%
android.permission-group.CONTACTS /* 联系人权限组_API 级别 23_联系人和配置文件相关的运行时权限 */
android.permission.WRITE_CONTACTS /* 写入联系人权限 允许应用写入用户联系人数据_保护等级 危险_API 级别 1 */
android.permission.GET_ACCOUNTS /* 访问谷歌账户权限 国内用不了…… 该权限意味着是否允许访问帐户服务中的帐户列表_保护等级 危险_API 级别 1 */
android.permission.READ_CONTACTS /* 读取联系人权限 允许应用读取用户联系人数据_保护等级 危险_API 级别 1 */
%%%%%
android.permission-group.PHONE /* 电话权限组_API 级别 23_电话功能相关的权限 */
android.permission.ACCESS_UCE_OPTIONS_SERVICE /* 允许应用访问 UCE-OPTIONS 权限_保护等级 为 签名|专用 */
android.permission.ANSWER_PHONE_CALLS /* 允许应用接听来电权限_保护等级为 危险_API 级别 26 */
android.permission.READ_PHONE_NUMBERS /* 允许应用读取设备的电话号码权限_保护等级为 危险_API 级别 26 */
android.permission.READ_PHONE_STATE /* 读取手机状态权限 就是允许应用访问电话状态_保护等级为 危险_API 级别 1 */
android.permission.CALL_PHONE /* 允许应用在不经过拨号界面的情况下启动电话呼叫以便用户确认呼叫权限_保护等级为 危险_API 级别 1 */
android.permission.ACCESS_UCE_PRESENCE_SERVICE /* 允许应用访问 UCE-Presence 权限_保护等级 为 签名|专用 */
android.permission.ACCEPT_HANDOVER /* 允许呼叫应用继续在其她应用中启动的呼叫权限 如视频通话应用希望在用户的移动网络上继续语音通话_保护等级为 危险_API 级别 28 */
android.permission.USE_SIP /* 允许应用使用 SIP 服务权限_保护等级为 危险_API 级别 9 */
com.android.voicemail.permission.ADD_VOICEMAIL /* 允许应用向系统中添加语音邮件权限_保护等级为 危险_API 级别 14 */
/* 其她权限例如 MANAGE_OWN_CALLS 允许调用应用通过自我管理的 ConnectionService API 管理自己的调用_保护等级为 正常_API 级别 26 */
%%%%%
android.permission-group.CALENDAR /* 日历权限组_API 级别 17_用户日历相关的运行时权限 */
android.permission.READ_CALENDAR /* 允许应用读取用户日历数据权限_保护等级 危险_API 级别 1 */
android.permission.WRITE_CALENDAR /* 允许应用写入用户日历数据权限_保护等级 危险_API 级别 1 */
%%%%%
android.permission-group.CALL_LOG /* 通话记录的权限_API 级别 28 */
android.permission.READ_CALL_LOG /* 允许应用读取用户通话日志权限_危险_16 */
android.permission.WRITE_CALL_LOG /* 允许应用写入用户通话日志_危险_16 */
android.permission.PROCESS_OUTGOING_CALLS /* 允许应用查看拨出呼叫期间拨出的号码_危险_1 */
%%%%%
android.permission-group.CAMERA /* 访问相机或从设备捕获 图像/视频 相关的权限_17 */
android.permission.CAMERA /* 允许访问摄像头_危险|立即_1 */
%%%%%
android.permission-group.SENSORS /* 身体或环境传感器相关的权限_23 */
android.permission.BODY_SENSORS /* 允许应用访问身体传感器的数据_危险_20 */
android.permission.USE_FINGERPRINT /* 允许应用使用指纹硬件 API 级别 28 以后不再建议使用_正常_23 */
android.permission.USE_BIOMETRIC /* 允许应用使用设备支持的生物识别模式_正常_28 */
%%%%%
android.permission-group.LOCATION /* 允许访问设备位置信息的权限_1 */
android.permission.ACCESS_FINE_LOCATION /* 允许应用访问精确的位置_危险_1 */
android.permission.ACCESS_COARSE_LOCATION /* 允许应用访问大概的位置_危险_1 */
%%%%%
android.permission-group.STORAGE /* 外部存储相关的运行时权限 API 级别 Q 以后不再建议使用_4 */
android.permission.READ_EXTERNAL_STORAGE /* 允许应用读取扩展存储 API 级别 Q 以后不再建议使用_危险_16 */
android.permission.WRITE_EXTERNAL_STORAGE /* 允许应用写入扩展存储 API 级别 Q 以后不再建议使用_危险_4 */
%%%%%
droidlogic.permission-group.SYSTEM_CONTROL /* 未知权限 字面翻译为 安卓逻辑系统.授权-组.系统_控制 */
droidlogic.permission.SYSTEM_CONTROL
%%%%%
android.permission-group.MICROPHONE /* 访问麦克风相关的权限 请注意 电话呼叫也会捕获音频 但属于单独的权限组_17 */
android.permission.RECORD_AUDIO /* 允许应用录音_危险_1 */
%%%%%
android.permission-group.SMS /* 短信相关的运行时权限_23 */
android.permission.READ_SMS /* 允许应用访问 SMS 信息_危险_1 */
android.permission.RECEIVE_WAP_PUSH /* 允许应用接收 WAP 推送信息_危险_1 */
android.permission.RECEIVE_MMS /* 允许应用监视传入的彩信_危险_1 */
android.permission.RECEIVE_SMS /* 允许应用接收短信_危险_1 */
android.permission.SEND_SMS /* 允许应用发送短信_危险_1 */
android.permission.READ_CELL_BROADCASTS /* 允许应用读取小区广播消息_危险 */
%%%%%
shell@GIONEE_G1605A:/ $ pm list permission-groups
permission group:android.permission-group.CONTACTS
permission group:android.permission-group.PHONE
permission group:android.permission-group.CALENDAR
permission group:android.permission-group.CAMERA
permission group:android.permission-group.SENSORS
permission group:android.permission-group.LOCATION
permission group:android.permission-group.STORAGE
permission group:android.permission-group.MICROPHONE
permission group:android.permission-group.SMS
shell@GIONEE_G1605A:/ $ pm list permissions -g -d
Dangerous Permissions:
group:android.permission-group.CONTACTS
permission:android.permission.WRITE_CONTACTS
permission:android.permission.GET_ACCOUNTS
permission:android.permission.READ_CONTACTS
group:android.permission-group.PHONE
permission:android.permission.READ_CALL_LOG
permission:android.permission.READ_PHONE_STATE
permission:android.permission.CALL_PHONE
permission:android.permission.WRITE_CALL_LOG
permission:android.permission.USE_SIP
permission:android.permission.PROCESS_OUTGOING_CALLS
permission:com.android.voicemail.permission.ADD_VOICEMAIL
group:android.permission-group.CALENDAR
permission:android.permission.READ_CALENDAR
permission:android.permission.WRITE_CALENDAR
group:android.permission-group.CAMERA
permission:android.permission.CAMERA
group:android.permission-group.SENSORS
permission:android.permission.BODY_SENSORS
group:android.permission-group.LOCATION
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION
group:android.permission-group.STORAGE
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE
group:android.permission-group.MICROPHONE
permission:android.permission.RECORD_AUDIO
group:android.permission-group.SMS
permission:android.permission.READ_SMS
permission:android.permission.RECEIVE_WAP_PUSH
permission:android.permission.RECEIVE_MMS
permission:android.permission.RECEIVE_SMS
permission:android.permission.SEND_SMS
permission:android.permission.READ_CELL_BROADCASTS
ungrouped:
shell@GIONEE_G1605A:/ $ pm list permissions -s
All Permissions:
通讯录: 修改您的通讯录, 查找设备上的帐户, 读取您的通讯录
电话: 读取通话记录, 读取手机状态和身份, 使用即时通讯通话服务, 直接拨打电话号码,
写入通话记录, 拨打/接听SIP电话, 重新设置外拨电话的路径, 添加语音邮件
日历: 读取日历活动和机密信息, 添加或修改日历活动,并在所有者不知情的情况下向邀请
对象发送电子邮件
相机: 拍摄照片和视频
身体传感器: 人体传感器(如心跳速率检测器), 使用指纹硬件
位置信息: 精确位置(基于GPS和网络), 大致位置(基于网络)
存储空间: 读取您的SD卡中的内容, 修改或删除您的SD卡中的内容
麦克风: 录音
短信: 读取您的讯息(短信或彩信), 接收讯息 (WAP), 接收讯息(彩信), 接收讯息(短
信), 发送和查看短信, 读取小区广播消息
ungrouped:
null, null, null, null, null, 修改系统设置, null, null, 建立或中断 WiMAX 网络连
接, null, null, null, null, null, null, Error: java.lang.NullPointerException: A
ttempt to read from field 'java.lang.String android.content.pm.ApplicationInfo.p
ublicSourceDir' on a null object reference
1|shell@GIONEE_G1605A:/ $
##################################################
——————————
%%%%%
每个程序在安装时都有建立一个系统 ID
用以保护数据不被其她应用获取
例如 app_15
Android 系统会根据不同的用户和组来分配不同权限
比如访问 SD 卡、访问网络等等
底层均映射为 Linux 权限!
%%%%%
Android 安全模型基于 Linux 的权限管理
android 系统充分利用了 linux 的用户权限管理方法
使用沙箱隔离机制将每个应用的进程资源隔离
Android 应用程序在安装时赋予一个 UID
UID 不同的应用程序完全隔离
另一方面 应用如果想使用某种服务 需要在 AndroidManifest.xml 中申请
比如想使用网络的话需要在 AndroidManifest.xml 中添加:
INTERNET 权限将被映射到底层的 GID
所以一个应用有一个 UID 可以有多个 GID 来获得多个权限
Android 本身支持在应用程序的 AndroidManifest.xml 中自定义权限
但这种自定义的权限没有被映射到系统底层的用户组中 没有独立的 GID
如果在系统中有一个 C 语言写的服务 只有应用申请了权限才可以使用 我们就需要将这个权限映射到底层
例如在开发中自定义一个类似于上面的 INTERNET 的系统级权限组
一个用户可以属于多个组
一个文件只能属于某个组
这里主要是在 AndroidManifest.xml 中声明权限
主要是通过在 AndroidManifest.xml 中显式地声明应用程序需要的权限 防止应用程序错误的使用服务 不恰当访问资源
Android 中每种权限都用一个独立的标签表示 示例:
当在安装应用程序时 Android 就会给予一个 UID
这个 UID 可连接到该应用程序的 AndroidManifest.xml 文件的内容
所以 User 在安装你的应用程序时在屏幕上的窗口里可以看到这个 AndroidManifest.xml 文件的内容
用户会看到你对应用程序的目的、权限等说明
当你接受这支程序的意图、权限说明之后 Android 就安装她 并给她一个 UID
万一在你的应用程序执行期间有越轨 企图做出非权限范围 的行为时 用户将会得到 Android 的警告讯息
Android 的系统权限不是由用户控制 而是由开发者根据开发的需要控制相关权限的开放与否
例如 AndroidManifest.xml 中有如下内容:
表示需要使用存储设备和录音设备 在安装的时候 就会提示用户她需要的权限
%%%%%
安装 APK 时发生了什么:
在安装 apk 的时候会解析
AndroidManifest.xml
把相应的信息保存起来
解析权限调用的是函数
private Package parsePackage
这里保存的都是
android.permission.WRITE_EXTERNAL_STORAGE
这样的字符串
在解析完后会调用
private void grantPermissionsLP
函数获取对应的
group_id
该函数把相应的组都保存到了 gids 中
当应用程序启动的过程中会调用
private final void startProcessLocked
这里就是获取前面保存的 gids
再后面调用创建了一个新的进程 这里传的参数就有 gids
创建新进程利用 jni 最终调用
static pid_t forkAndSpecializeCommon
函数
我们如果研究代码可以看到在子进程里调用
setgroupsIntarray
设置该进程所属的组 这样她就拥有了该组的权限
也通过 setgid 及 setuid 决定了应用程序的 uid 及 gid 值
权限控制主要放置在 AndroidManifest.xml 文件中
最后镜像生成在 system\etc\permissions\platform.xml 配置文件中
%%%%%
多用户下的应用其实只安装一次 不同用户下同一个应用的版本和签名都应该相同
不同用户下相同 App 能够独立运行是因为系统为她们创造了不同的运行环境和权限
protectionLevel 分为三类:
normal 是普通权限
在 AndroidManifest.xml 中声明就可以获取的权限
如 INTERNET 权限
dangerous 敏感权限需要动态申请告知用户才能获取
signature|privileged 签名|特权
具有系统签名的系统应用才可以获取的权限
对应上方的安装在 /system/priv-app 的特权应用!
——————————
第一层是在开发人员编写代码时由应用设置 主要是修改 AndroidManifest.xml 文件
AndroidManifest.xml 是 APP 的运行配置文件 她是一个 XML 描述文件 指定了 APP 的运行配置信息
一般都存放在 APP 包下的 manifests 目录下
不过我也见过放在 src/main/res/AndroidManifest.xm 下面的
AndroidManifest.xml 文件的作用:
描述 app 的包名
描述 app 使用的 android 系统版本信息
描述 app 本身的版本信息 这样对于同一个 app 的两个版本 系统就能区分那个新版本旧版本
描述应用对外暴露的组件等等
我们将 apk 文件后缀修改成 zip 就可以使用平常的解压工具进行解压了:
第一眼看到的就是 AndroidManifest.xml 配置文件:
AndroidManifest 官方解释是 应用清单 manifest 意思是货单
每个应用的根目录中都必须包含一个 并且文件名必须一模一样
这个文件中包含了 APP 的配置信息 系统需要根据里面的内容运行 APP 的代码 显示界面
AndroidManifest.xml 是每个 apk 文件解压后根目录下的一个文件
每个 apk 都必须包含一个 AndroidManifest.xml 文件 且名字必须与此完全一致.
示例 AndroidManifest.xml 中的一段配置代码:
%%%%%
通过 shareduserid 来实现数据共享有一个限制就是相同的签名
这个是很高要求的
一般都是同一个公司开发出来的 app 才能满足获取内置到第三方 ROM 里面去才能满足
通常的做法是通过 uses-permission 来实现 我们自己定义一个权限!
在需要被访问的地方加上这个权限限制这样就能到达目的!
normal 权限 也就是一般的权限 不需要用户去确认的 例如一个应用申请连接网络等
dangerous 权限 这种权限较 normal 权限高一些 需要用户手动点击确认的 例如应用需要读取联系人的信息 因为这些数据是比较隐私的可能会导致你的数据泄露等
signature 只有当申请权限的应用程序的数字签名与声明此权限的应用程序的数字签名相同时 才能将权限授给她 如果是申请系统权限则需要与系统签名相同
signatureOrSystem 签名相同 或者申请权限的应用为系统应用 在 system image 中
signature 和 signatureOrSystem 要求是很高 一般的只有是相同公司开发出来的应用才能满足
%%%%%
我们在安装 Android 软件的时候系统会提示该软件所需要的权限
相对于其她系统 Android 的权限非常多
我们在开发软件的时候也需要声明相应的权限,比如希望软件能发短信,需要声明软件调用短信的权限
否则软件运行的时候就会报错
Android 的权限在 AndroidManifest.xml 文件里配置
AndroidManifest 文件中有四个标签与 permission 有关:
其中最常用的是
当我们需要获取某个权限的时候就必须在我们的 manifest 文件中声明
...
是 android 预定义的权限
是自己定义的权限
用的相对较少
这两个标签就更少见了
简单说 就是声明一个标签 该标签代表了一组 permissions
而 是为一组 permissions 声明了一个 namespace
解释一下:
propectionLevel 这个属性是必须声明的
告诉系统通知用户的应用要求许可 或允许谁认为获得许可的情况下
permissionGroup 这个是可选的 与 配合使用
label, name 和 icon 用于描述权限
常见权限:
/* 允许读写访问 properties 表 在 checkin 数据库中 可以修改上传 */
/* 允许一个程序访问 CellID 或 WiFi 热点来获取粗略的位置 */
/* 允许一个程序访问精良位置 如 GPS */
/* 允许应用程序访问额外的位置提供命令 */
/* 允许程序创建模拟位置提供用于测试 */
/* 允许程序访问有关 GSM 网络信息 */
/* 允许程序使用 SurfaceFlinger 底层特性 */
/* 允许程序访问 Wi-Fi 网络状态信息 */
/* 允许程序发布系统级服务 */
/* 允许程序更新手机电池统计信息 */
/* 允许程序连接到已配对的蓝牙设备 */
/* 允许程序发现和配对蓝牙设备 */
/* 请求能够禁用设备 */
/* 允许程序广播一个提示消息在一个应用程序包已经移除后 */
/* 允许一个程序广播常用 intents */
/* 允许一个程序初始化一个电话拨号不需通过拨号用户界面需要用户确认 */
/* 允许一个程序拨打任何号码 包含紧急号码无需通过拨号用户界面需要用户确认 */
/* 请求访问使用照相设备 */
/* 允许一个程序是否改变一个组件或其她的启用或禁用 */
/* 允许一个程序修改当前设置 如本地化 */
/* 允许程序改变网络连接状态 */
/* 允许程序改变 Wi-Fi 连接状态 */
/* 允许一个程序清楚缓存从所有安装的程序在设备中 */
/* 允许一个程序清除用户设置 */
/* 允许启用禁止位置更新提示从无线模块 */
/* 允许程序删除缓存文件 */
/* 允许一个程序删除包 */
/* 允许访问底层电源管理 */
/* 允许程序 RW 诊断资源 */
/* 允许程序禁用键盘锁 */
/* 允许程序返回状态抓取信息从系统服务 */
android.permission.EXPAND_STATUS_BAR /* 允许一个程序扩展收缩状态栏 */
android.permission.FACTORY_TEST /* 作为一个工厂测试程序 运行在 root 用户 */
android.permission.FLASHLIGHT /* 访问闪光灯 */
android.permission.FORCE_BACK /* 允许程序强行一个后退操作是否在顶层 activities */
android.permission.FOTA_UPDATE android /* 一个预留权限 */
android.permission.GET_ACCOUNTS /* 访问一个帐户列表在 Accounts Service 中 */
android.permission.GET_PACKAGE_SIZE /* 允许一个程序获取任何 package 占用空间容量 */
android.permission.GET_TASKS /* 允许一个程序获取信息有关当前或最近运行的任务 一个缩略的任务状态 是否活动等等 */
android.permission.HARDWARE_TEST /* 允许访问硬件 */
android.permission.INJECT_EVENTS /* 允许一个程序截获用户事件如按键、触摸、轨迹球等等到一个时间流 */
android.permission.INSTALL_PACKAGES /* 允许一个程序安装 packages */
android.permission.INTERNAL_SYSTEM_WINDOW /* 允许打开窗口使用系统用户界面 */
android.permission.INTERNET /* 允许程序打开网络套接字 */
android.permission.MANAGE_APP_TOKENS /* 允许程序管理程序引用在窗口管理器中 创建、催后、z- order 默认向 z 轴推移 */
android.permission.MASTER_CLEAR /* 恢复出厂设置权限 清除一切用户数据 */
android.permission.MODIFY_AUDIO_SETTINGS /* 允许程序修改全局音频设置 */
android.permission.MODIFY_PHONE_STATE /* 允许修改话机状态,如电源,人机接口等 */
android.permission.MOUNT_UNMOUNT_FILESYSTEMS /* 允许挂载和反挂载文件系统可移动存储 */
android.permission.PERSISTENT_ACTIVITY /* 允许一个程序设置她的 activities 显示 */
android.permission.PROCESS_OUTGOING_CALLS /* 允许程序监视、修改有关播出电话 */
android.permission.READ_CALENDAR /* 允许程序读取用户日历数据 */
android.permission.READ_CONTACTS /* 允许程序读取用户联系人数据 */
android.permission.READ_FRAME_BUFFER /* 允许程序屏幕波或和更多常规的访问帧缓冲数据 */
android.permission.READ_INPUT_STATE /* 允许程序读取底层系统日志文件 */
android.permission.READ_OWNER_DATA /* 允许程序读取所有者数据 */
android.permission.READ_SMS /* 允许程序读取短信息 */
android.permission.READ_SYNC_SETTINGS /* 允许程序读取同步设置 */
android.permission.READ_SYNC_STATS /* 允许程序读取同步状态 */
android.permission.REBOOT /* 请求能够重新启动设备 */
android.permission.RECEIVE_BOOT_COMPLETED /* 允许一个程序接收到 ACTION_BOOT_COMPLETED 广播在系统完成启动 */
android.permission.RECEIVE_MMS /* 允许一个程序监控将收到 MMS 彩信 记录或处理 */
android.permission.RECEIVE_SMS /* 允许程序监控一个将收到短信息 记录或处理 */
android.permission.RECEIVE_WAP_PUSH /* 允许程序监控将收到 WAP PUSH 信息 */
android.permission.RECORD_AUDIO /* 允许程序录制音频 */
android.permission.REORDER_TASKS /* 允许程序改变 Z 轴排列任务 */
android.permission.RESTART_PACKAGES /* 允许程序重新启动其她程序 */
android.permission.SEND_SMS /* 允许程序发送 SMS 短信 */
android.permission.SET_ACTIVITY_WATCHER /* 允许程序监控或控制 activities 已经启动全局系统中 */
android.permission.SET_ALWAYS_FINISH /* 允许程序控制是否活动间接完成在处于后台时 */
android.permission.SET_ANIMATION_SCALE /* 修改全局信息比例 */
android.permission.SET_DEBUG_APP /* 配置一个程序用于调试 */
android.permission.SET_ORIENTATION /* 允许底层访问设置屏幕方向和实际旋转 */
android.permission.SET_PREFERRED_APPLICATIONS /* 允许一个程序修改列表参数 PackageManager.addPackageToPreferred() 和 PackageManager.removePackageFromPreferred() 这两个方法 */
android.permission.SET_PROCESS_FOREGROUND /* 允许程序当前运行程序强行到前台 */
android.permission.SET_PROCESS_LIMIT /* 允许设置最大的运行进程数量 */
android.permission.SET_TIME_ZONE /* 允许程序设置时间区域 */
android.permission.SET_WALLPAPER /* 允许程序设置壁纸 */
android.permission.SET_WALLPAPER_HINTS /* 允许程序设置壁纸 hits */
android.permission.SIGNAL_PERSISTENT_PROCESSES /* 允许程序请求发送信号到所有显示的进程中 */
android.permission.STATUS_BAR /* 允许程序打开、关闭或禁用状态栏及图标 */
android.permission.SUBSCRIBED_FEEDS_READ /* 允许一个程序访问订阅 RSS Feed 内容提供 */
android.permission.SUBSCRIBED_FEEDS_WRITE /* 系统暂时保留改设置 */
android.permission.SYSTEM_ALERT_WINDOW /* 允许一个程序打开窗口使用 TYPE_SYSTEM_ALERT 显示在其她所有程序的顶层 */
android.permission.VIBRATE /* 允许访问振动设备 */
android.permission.WAKE_LOCK /* 允许使用 PowerManager 的 WakeLocks 保持进程在休眠时从屏幕消失 */
android.permission.WRITE_APN_SETTINGS /* 允许程序写入 API 设置 */
android.permission.WRITE_CALENDAR /* 允许一个程序写入但不读取用户日历数据 */
android.permission.WRITE_CONTACTS /* 允许程序写入但不读取用户联系人数据 */
android.permission.WRITE_GSERVICES /* 允许程序修改 Google 服务地图 */
android.permission.WRITE_OWNER_DATA /* 允许一个程序写入但不读取所有者数据 */
android.permission.WRITE_SETTINGS /* 允许程序读取或写入系统设置 */
android.permission.WRITE_SMS /* 允许程序写短信 */
android.permission.WRITE_SYNC_SETTINGS /* 允许程序写入同步设置 */
——————————
platform.xml 其实是将 aosp 中的配置文件直接拷贝到手机目录中
AOSP 全称 Android Open Source Project 中文意为 Android 开放源代码项目
安卓开源项目 开源即开放源代码
Android 是一个基于 Linux 由 Google 主导的开源系统
严格意义上来说 Android = AOSP + GMS
GMS 即谷歌移动服务 即常刷的谷歌服务包
国内无法使用 GMS 所以国内的各种定制 ROM 都是 AOSP 的定制修改加上自家的云服务
比如 MIUI、ColorOS 等
所以所有的 ROM 最终的根源就是 AOSP 没有 AOSP 也就没有现在的 Android
应用包中 preferences.xml 文件的位置在 res\xml\preferences.xml
设备目录存放的位置在 /system/etc/permissions/platform.xml
在 aosp 中的存放位置是 framework/base/data/etc/platform.xml
%%%%%
编辑的是
root/system/etc/permissions/platform.xml
文件 看到代码如下:
修改为:
再然后重启就行了
%%%%%
这是对 platform.xml 的解析 注意看注释:
/** 第一部分 >>> 警告部分
说明这个文件是处理普通用户和系统权限之间映射的 如果擅自改动会造成大的安全漏洞
此文件用于定义较低级别系统之间的映射 管理的用户和组 ID 以及更高级别的权限名称在平台旁。
编辑此文件时要非常小心!这里犯的错误可能会打开巨大的安全漏洞。
*/
/** 第二部分 >>> 权限映射
将低等级的 groups id 和权限名称相关联
通过指定这样的映射 表明了一个授予了给定权限的应用进程将附带这所给的 group id 运行
因此她可以执行这个群组所允许的读写和执行操作
以下标记将低级组 ID 与权限名称关联
通过指定这样一个映射,您的意思是,任何被授予给定权限的应用程序进程也将在其进程附加给定组 ID 的情况下运行
因此,她可以执行该组允许的任何文件系统 读、写、执行 操作。
*/
/** 第三部分 >>> 权限映射的例外部分
这些权限映射到 GID 但我们需要将其保留在此处 直到支持从 L 升级到当前版本
这些权限是内置的 在 L 中没有存储在包中
如果在解析包时未在此处定义 则返回 xml
xml 我们将忽略授予应用程序的这些权限 而不传播授予的状态
从 N 开始 我们将内置权限存储在包中
与脆弱性相比 作为保存的存储的 xml 可以忽略不计 带有权限的一个标记
因为可以删除不再需要映射到 GID 和中断授权传播的内置权限
*/
/** 第四部分 >>> 分配权限
有些用户比较特殊 她们是系统核心用户
Android 会分配特定的高级权限来允许她们来完成一些高级的操作
比如 shell 用户有很多权限 这是因为开发者需要比较开放的环境来和 system 进行交互
shell 用户的权限有时候需要 adb root/adb remount 才能享受
对应的需要 userdebug 或者 root 版本
user 版本下 shell 命令还是有所限制的
*/
/** 第五部分 >>> 库
标签设置应用可以链接到的库
可以理解为应用可以调用到的 jar 吧?
这是可供应用程序代码链接的所有库的列表
*/
/** 第六部分 >>> 省电优化白名单
表示这个对应于手机中的省电优化设置
用这个 tag 配置在这张表中就代表该应用不受省电优化显示 可以在后台访问网络
对应应用在原生设置中的电源菜单也是灰显 不可设置优化的
这些是白名单上的标准软件包始终具有互联网功能
可以在省电模式下访问 即使她们不在前台
这个 tag 也和 doze mode 有些关系
就是低耗电模式 什么是低耗电模式:
如果用户设备未插电源、处于静止状态一段时间且屏幕关闭 设备将进入该模式
该模式下系统会尝试通过限制应用对网络和 CPU 密集型服务的访问来节省电量
这还可以阻止引用访问网络并推迟其作业、同步和标准闹铃
系统会定期退出低耗电模式一会儿 好让应用完成其已推迟的 Activity
在此维护时段内 系统会运行所有特定同步 作业和闹铃并允许应用访问网络
在每个维护时段结束后系统会再次进入低耗电模式 暂停网络并推迟作业、同步和闹铃
随着时间推移 系统安排维护时段的次数越来越少 这有助于设备未连接至充电器情况下长期处于不活动状态时降低电池消耗
一旦用户通过移动设备、打开屏幕或连接到充电器唤醒设备 系统就会立即退出低耗电模式 并且所有应用都将返回到正常 Activity
低电耗模式限制:
暂停访问网络
系统将忽略 wake locks
标准 AlarmManager 闹铃将推迟到下一维护时段 包括 setExact() 和 setWindow() 如果需要设置低耗电模式下触发的闹铃请使用 setAndAllowWhileIdle()/setExactAndAllowWhileIdle() 一般情况下使用 setAlarmClock() 设置的闹铃将继续出发 但是系统会在这些闹铃出发之前不久退出低耗电模式
系统不执行 Wi-Fi 扫描
系统不允许运行 同步适配器
系统不允许运行 JobScheduler
可以使用 dumpsys deviceidle whitelist 命令查看:
cmcc_jiangsu:/ # dumpsys deviceidle whitelist
system-excidle,com.android.providers.downloads,10002
system-excidle,com.android.shell,2000
system,com.android.providers.downloads,10002
system,com.android.shell,2000
cmcc_jiangsu:/ #
*/
/** 第七部分 >>> 数据白名单
这些是白名单上的标准软件包 在数据模式下始终可以访问互联网 即使她们不在前台
*/
/** 第八部分 >>> 省电优化白名单
这是一个需要在后台自由运行的核心平台组件
是白名单系统提供商
*/
/** 第九部分 >>> 系统应用白名单
这些是白名单上的软件包 可以作为系统用户运行
*/
/** 第十部分 >>> 系统应用黑名单
这些软件包不应作为系统用户运行
*/
%%%%%
xml 肯定是需要解析才能用的
/frameworks/core/java/com/android/server/SystemConfig.java
这个 SystemConfig 就是来解析 platform.xml 然后供一个个系统接口用作返回值的依据:
void readPermissions(File libraryDir, int permissionFlag) {
// Read permissions from given directory.
if (!libraryDir.exists() || !libraryDir.isDirectory()) {
if (permissionFlag == ALLOW_ALL) {
Slog.w(TAG, "No directory " + libraryDir + ", skipping");
}
return;
}
if (!libraryDir.canRead()) {
Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
return;
}
// Iterate over the files in the directory and scan .xml files
File platformFile = null;
for (File f : libraryDir.listFiles()) {
// We'll read platform.xml last
if (f.getPath().endsWith("etc/permissions/platform.xml")) {
platformFile = f;
continue;
}
if (!f.getPath().endsWith(".xml")) {
Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
continue;
}
if (!f.canRead()) {
Slog.w(TAG, "Permissions library file " + f + " cannot be read");
continue;
}
readPermissionsFromXml(f, permissionFlag);
}
// Read platform permissions last so it will take precedence
if (platformFile != null) {
readPermissionsFromXml(platformFile, permissionFlag);
}
}
private void readPermissionsFromXml(File permFile, int permissionFlag) {
FileReader permReader = null;
try {
permReader = new FileReader(permFile);
} catch (FileNotFoundException e) {
Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
return;
}
final boolean lowRam = ActivityManager.isLowRamDeviceStatic();
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(permReader);
int type;
while ((type=parser.next()) != parser.START_TAG
&& type != parser.END_DOCUMENT) {
;
}
if (type != parser.START_TAG) {
throw new XmlPullParserException("No start tag found");
}
if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {
throw new XmlPullParserException("Unexpected start tag in " + permFile
+ ": found " + parser.getName() + ", expected 'permissions' or 'config'");
}
boolean allowAll = permissionFlag == ALLOW_ALL;
boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0;
boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;
boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;
boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;
boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) != 0;
boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_WHITELISTING) != 0;
while (true) {
XmlUtils.nextElement(parser);
if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
break;
}
String name = parser.getName();
if ("group".equals(name) && allowAll) {
String gidStr = parser.getAttributeValue(null, "gid");
if (gidStr != null) {
int gid = android.os.Process.getGidForName(gidStr);
mGlobalGids = appendInt(mGlobalGids, gid);
} else {
Slog.w(TAG, " without gid in " + permFile + " at "
+ parser.getPositionDescription());
}
XmlUtils.skipCurrentTag(parser);
continue;
} else if ("permission".equals(name) && allowPermissions) {
String perm = parser.getAttributeValue(null, "name");
if (perm == null) {
Slog.w(TAG, " without name in " + permFile + " at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
perm = perm.intern();
readPermission(parser, perm);
} else if ("assign-permission".equals(name) && allowPermissions) {
String perm = parser.getAttributeValue(null, "name");
if (perm == null) {
Slog.w(TAG, " without name in " + permFile + " at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
String uidStr = parser.getAttributeValue(null, "uid");
if (uidStr == null) {
Slog.w(TAG, " without uid in " + permFile + " at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
int uid = Process.getUidForName(uidStr);
if (uid < 0) {
Slog.w(TAG, " with unknown uid \""
+ uidStr + " in " + permFile + " at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
perm = perm.intern();
ArraySet perms = mSystemPermissions.get(uid);
if (perms == null) {
perms = new ArraySet();
mSystemPermissions.put(uid, perms);
}
perms.add(perm);
XmlUtils.skipCurrentTag(parser);
} else if ("library".equals(name) && allowLibs) {
String lname = parser.getAttributeValue(null, "name");
String lfile = parser.getAttributeValue(null, "file");
if (lname == null) {
Slog.w(TAG, " without name in " + permFile + " at "
+ parser.getPositionDescription());
} else if (lfile == null) {
Slog.w(TAG, " without file in " + permFile + " at "
+ parser.getPositionDescription());
} else {
//Log.i(TAG, "Got library " + lname + " in " + lfile);
mSharedLibraries.put(lname, lfile);
}
XmlUtils.skipCurrentTag(parser);
continue;
} else if ("feature".equals(name) && allowFeatures) {
String fname = parser.getAttributeValue(null, "name");
int fversion = XmlUtils.readIntAttribute(parser, "version", 0);
boolean allowed;
if (!lowRam) {
allowed = true;
} else {
String notLowRam = parser.getAttributeValue(null, "notLowRam");
allowed = !"true".equals(notLowRam);
}
if (fname == null) {
Slog.w(TAG, " without name in " + permFile + " at "
+ parser.getPositionDescription());
} else if (allowed) {
addFeature(fname, fversion);
}
XmlUtils.skipCurrentTag(parser);
continue;
} else if ("unavailable-feature".equals(name) && allowFeatures) {
String fname = parser.getAttributeValue(null, "name");
if (fname == null) {
Slog.w(TAG, " without name in " + permFile + " at "
+ parser.getPositionDescription());
} else {
mUnavailableFeatures.add(fname);
}
XmlUtils.skipCurrentTag(parser);
continue;
} else if ("allow-in-power-save-except-idle".equals(name) && allowAll) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, " without package in "
+ permFile + " at " + parser.getPositionDescription());
} else {
mAllowInPowerSaveExceptIdle.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
continue;
} else if ("allow-in-power-save".equals(name) && allowAll) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, " without package in " + permFile + " at "
+ parser.getPositionDescription());
} else {
mAllowInPowerSave.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
continue;
} else if ("allow-in-data-usage-save".equals(name) && allowAll) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, " without package in " + permFile
+ " at " + parser.getPositionDescription());
} else {
mAllowInDataUsageSave.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
continue;
} else if ("allow-unthrottled-location".equals(name) && allowAll) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, " without package in "
+ permFile + " at " + parser.getPositionDescription());
} else {
mAllowUnthrottledLocation.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
continue;
} else if ("allow-implicit-broadcast".equals(name) && allowAll) {
String action = parser.getAttributeValue(null, "action");
if (action == null) {
Slog.w(TAG, " without action in " + permFile
+ " at " + parser.getPositionDescription());
} else {
mAllowImplicitBroadcasts.add(action);
}
XmlUtils.skipCurrentTag(parser);
continue;
} else if ("app-link".equals(name) && allowAppConfigs) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, " without package in " + permFile + " at "
+ parser.getPositionDescription());
} else {
mLinkedApps.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
} else if ("system-user-whitelisted-app".equals(name) && allowAppConfigs) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, " without package in " + permFile
+ " at " + parser.getPositionDescription());
} else {
mSystemUserWhitelistedApps.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
} else if ("system-user-blacklisted-app".equals(name) && allowAppConfigs) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, " without service in "
+ permFile + " at " + parser.getPositionDescription());
} else {
ComponentName cn = ComponentName.unflattenFromString(serviceName);
if (cn == null) {
Slog.w(TAG,
" with invalid service name "
+ serviceName + " in "+ permFile
+ " at " + parser.getPositionDescription());
} else {
mBackupTransportWhitelist.add(cn);
}
}
XmlUtils.skipCurrentTag(parser);
} else if ("disabled-until-used-preinstalled-carrier-associated-app".equals(name)
&& allowAppConfigs) {
String pkgname = parser.getAttributeValue(null, "package");
String carrierPkgname = parser.getAttributeValue(null, "carrierAppPackage");
if (pkgname == null || carrierPkgname == null) {
Slog.w(TAG, " associatedPkgs =
mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get(
carrierPkgname);
if (associatedPkgs == null) {
associatedPkgs = new ArrayList<>();
mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put(
carrierPkgname, associatedPkgs);
}
associatedPkgs.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
} else if ("privapp-permissions".equals(name) && allowPrivappPermissions) {
readPrivAppPermissions(parser);
} else if ("hidden-api-whitelisted-app".equals(name) && allowApiWhitelisting) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, " without package in " + permFile
+ " at " + parser.getPositionDescription());
} else {
mHiddenApiPackageWhitelist.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
} else {
XmlUtils.skipCurrentTag(parser);
continue;
}
}
} catch (XmlPullParserException e) {
Slog.w(TAG, "Got exception parsing permissions.", e);
} catch (IOException e) {
Slog.w(TAG, "Got exception parsing permissions.", e);
} finally {
IoUtils.closeQuietly(permReader);
}
// Some devices can be field-converted to FBE, so offer to splice in
// those features if not already defined by the static config
if (StorageManager.isFileEncryptedNativeOnly()) {
addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0);
addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0);
}
if (ActivityManager.isLowRamDeviceStatic()) {
addFeature(PackageManager.FEATURE_RAM_LOW, 0);
} else {
addFeature(PackageManager.FEATURE_RAM_NORMAL, 0);
}
for (String featureName : mUnavailableFeatures) {
removeFeature(featureName);
}
}
private void addFeature(String name, int version) {
FeatureInfo fi = mAvailableFeatures.get(name);
if (fi == null) {
fi = new FeatureInfo();
fi.name = name;
fi.version = version;
mAvailableFeatures.put(name, fi);
} else {
fi.version = Math.max(fi.version, version);
}
}
private void removeFeature(String name) {
if (mAvailableFeatures.remove(name) != null) {
Slog.d(TAG, "Removed unavailable feature " + name);
}
}
void readPermission(XmlPullParser parser, String name)
throws IOException, XmlPullParserException {
if (mPermissions.containsKey(name)) {
throw new IllegalStateException("Duplicate permission definition for " + name);
}
final boolean perUser = XmlUtils.readBooleanAttribute(parser, "perUser", false);
final PermissionEntry perm = new PermissionEntry(name, perUser);
mPermissions.put(name, perm);
int outerDepth = parser.getDepth();
int type;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG
|| type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if ("group".equals(tagName)) {
String gidStr = parser.getAttributeValue(null, "gid");
if (gidStr != null) {
int gid = Process.getGidForName(gidStr);
perm.gids = appendInt(perm.gids, gid);
} else {
Slog.w(TAG, " without gid at "
+ parser.getPositionDescription());
}
}
XmlUtils.skipCurrentTag(parser);
}
}