Android Dangerous权限的处理【设为默认】
在日常的使用中,如果我们调用到某一个接口,该接口依赖于危险权限的声明,平时我们会去对权限进行检查,检查这个权限是否被赋予,如果没有被赋予,就需要进行动态申请,否则会报权限异常的Exception.
但如果我本人比较懒,不想手动动他,权限就给他算了。针对和由系统集成的apk而言,可以考虑两种方式。
android:sharedUserId = "android.uid.system" 加上这个后,对应的应用瞬间变得niubility,一般apk是运行在普通的user用户下,加上该标签后,就会运行在system用户下,同时系统级用户对于危险权限是默认授予的,同时用户无法进行操作的。
除了上面这种niubility方法,还有一种方法也可以让某个应用默认授予权限并且用户无法操作,这也是本次要将的重点,稍微结合源码来介绍下
接下来进行操作的实现:
1.创建对应的配置文件,别问,问就是有人要读
2.编写对应的集成文档,别问,问就是有人要从那里取
先说一下1吧,这里简单给个例子:
加入我们要继承的配置文件是 default_permission_xxx.xml
<?xml version="1.0" encoding="utf-8"?>
<exceptions>
<!-- exception package 为要授予权限的app包名 -->
<!-- permission name 为要授予权限的app默认授予的权限 -->
<!-- permission的fixed表示授权后是否可以被非系统组件修改权限 -->
<exception package="com.android.xxxtest">
<permission name="android.permission.巴拉巴拉" fixed="false"/>
</exception>
</exceptions>
这里简单说一下,首先package是要设置对应权限的包名,接着在权限中的name是要设置为默认授予的权限名称(这里针对dangerous权限而言,priv权限有自己的定义方式),最后的fixed标志位是用来设置是否可以被非系统组件修改的标志,从用户体验的角度来看就是用户能不能修改该权限。
这里要读的内容差不多按照这个格式来写,那该给它放到哪去呢?
接着就要想办法把这个配置文件集成到特定的位置去。
这里以bp文档为例,mk可以看参考文档中,写法都大差不大:
android_app {
name : "balabala",
...
required:["permission_balabala"],
}
prebuilt_etc {
name: "permission_balabala",
product_specific: true,
sub_dir: "default-permissions",
src: "default-permissions-xxxx.xml",
}
简单说明下:
对于android_app
的name,就是我们应用的名,
required
中包含了要继承的配置文件,
prebuilt_etc
是指要往某个etc/的路径下集成,
product_specific
是指往product分区进行集成,除此之外还有vendor,system_ext,system,Oem等
sub_dir
是指在对应的分区/etc/的子路径下,这里要是集成危险权限,所以必须是default-permissions的文件名,敲重点
最后的src就是对应的资源文件
这两步配置好了就能够实现对应应用的默认权限授予的配置。
接着简单看点源码:
DefaultPermissionGrantPolicy.java
看这个类名应该就直到是专门负责默认权限授予工作的。主要是pms来进行调用
public void grantDefaultPermissions(int userId) {
DelayingPackageManagerCache pm = new DelayingPackageManagerCache();
grantPermissionsToSysComponentsAndPrivApps(pm, userId);
grantDefaultSystemHandlerPermissions(pm, userId);
grantDefaultPermissionExceptions(pm, userId);
// Apply delayed state
pm.apply();
}
看一下中间的三巨头方法,第一个应该是授予默认的系统权限和priv权限
第二个是赋予一些系统级应用的默认权限,比如说语音助手,电话等等
第三个就是今天的重头戏,授予用户配置的危险权限
private void grantDefaultPermissionExceptions(PackageManagerWrapper pm, int userId) {
mHandler.removeMessages(MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS);
synchronized (mLock) {
// readDefaultPermissionExceptionsLocked 这个方法会去对根目录,vendor,Odm,product,以及system_ext分区下etc/default-permissions/下的xml进行读取,读取后返回给mGrantExceptions
if (mGrantExceptions == null) {
mGrantExceptions = readDefaultPermissionExceptionsLocked(pm);
}
}
Set<String> permissions = null;
final int exceptionCount = mGrantExceptions.size();
for (int i = 0; i < exceptionCount; i++) {
String packageName = mGrantExceptions.keyAt(i);
PackageInfo pkg = pm.getSystemPackageInfo(packageName);
List<DefaultPermissionGrant> permissionGrants = mGrantExceptions.valueAt(i);
final int permissionGrantCount = permissionGrants.size();
for (int j = 0; j < permissionGrantCount; j++) {
DefaultPermissionGrant permissionGrant = permissionGrants.get(j);
if (!pm.isPermissionDangerous(permissionGrant.name)) {
Log.w(TAG, "Ignoring permission " + permissionGrant.name
+ " which isn't dangerous");
continue;
}
if (permissions == null) {
permissions = new ArraySet<>();
} else {
permissions.clear();
}
permissions.add(permissionGrant.name);
// 注意看! 这个标志叫permissionGrant.fixed
grantRuntimePermissions(pm, pkg, permissions, permissionGrant.fixed,
permissionGrant.whitelisted, true /*whitelistRestrictedPermissions*/,
userId);
}
}
}
private void grantRuntimePermissions(PackageManagerWrapper pm, PackageInfo pkg,
Set<String> permissionsWithoutSplits, boolean systemFixed, boolean ignoreSystemPackage,
boolean whitelistRestrictedPermissions, int userId) {
UserHandle user = UserHandle.of(userId);
if (pkg == null) {
return;
}
String[] requestedPermissions = pkg.requestedPermissions;
if (ArrayUtils.isEmpty(requestedPermissions)) {
return;
}
// Intersect the requestedPermissions for a factory image with that of its current update
// in case the latter one removed a <uses-permission>
String[] requestedByNonSystemPackage = pm.getPackageInfo(pkg.packageName)
.requestedPermissions;
int size = requestedPermissions.length;
for (int i = 0; i < size; i++) {
if (!ArrayUtils.contains(requestedByNonSystemPackage, requestedPermissions[i])) {
requestedPermissions[i] = null;
}
}
requestedPermissions = ArrayUtils.filterNotNull(requestedPermissions, String[]::new);
final ArraySet<String> permissions = new ArraySet<>(permissionsWithoutSplits);
ApplicationInfo applicationInfo = pkg.applicationInfo;
int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
// 这个值就是在配置文件中的fixed标志位的值,如果是true,就把对应的权限标志位添加上PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
if (systemFixed) {
newFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
}
}
给上一个加上该标志位后的示例dumpsys结果:
User 13:
......
runtime permissions:
android.permission.BLUETOOTH_CONNECT: granted=true, flags=[ SYSTEM_FIXED|GRANTED_BY_DEFAULT|USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
可以看到,对应的runtime权限的列表中,flags包含了SYSTEM_FIXED标签并且有GRANTED_BY_DEFAULT标签,说明该权限是默认授予,并且用户无法进行操作的。具体如何让其不进行操作,可以看Setting对于system_fixed的标志位的处理,会有一个disable的过程。
参考文档:
https://blog.csdn.net/qq_34250794/article/details/128284337
https://blog.csdn.net/qq_37580586/article/details/120132638