https://blog.csdn.net/shift_wwx/article/details/81173056
最近在做GMS 的验证,其中测试case rmeabi-v7a GtsPermissionTestCases 的时候出现了异常,有些注意点这里总结一下。
出现的log 如下:
Permission:android.permission.WRITE_EXTERNAL_STORAGE cannot be granted by default to package:com.android.chrome
Permission:android.permission.WRITE_EXTERNAL_STORAGE cannot be granted by default to package:com.android.exchange
Permission:android.permission.READ_PHONE_STATE cannot be granted by default to package:com.android.exchange
Permission:android.permission.READ_EXTERNAL_STORAGE cannot be granted by default to package:com.android.exchange
从log 中分析是这两个app grant 了runtime 的default permission.
如果想要了解更多 runtime permission,请看另一篇博文 Android Runtime Permission 详解.
这里,对于runtime permission 的默认配置,可以看下source code:
frameworks/base/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
带着这个fail 的问题,先来看下另一种问题,下面一同分析。
log 如下:(log 太多了,截取部分)
07-22 04:22:02.819 2255 2273 I TestRunner: java.lang.AssertionError: Permission:android.permission.GET_ACCOUNTS cannot be granted by default to package:com.android.mms
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.READ_PHONE_STATE cannot be granted by default to package:com.android.mms
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.READ_CALL_LOG cannot be granted by default to package:com.android.mms
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.WRITE_CALL_LOG cannot be granted by default to package:com.android.mms
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.CALL_PHONE cannot be granted by default to package:com.android.mms
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:com.android.voicemail.permission.ADD_VOICEMAIL cannot be granted by default to package:com.android.mms
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.PROCESS_OUTGOING_CALLS cannot be granted by default to package:com.android.mms
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.RECEIVE_WAP_PUSH cannot be granted by default to package:com.android.mms
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.GET_ACCOUNTS cannot be granted by default to package:com.qiku.android.contacts
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.READ_CONTACTS cannot be granted by default to package:com.qiku.android.contacts
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.WRITE_CONTACTS cannot be granted by default to package:com.qiku.android.contacts
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.READ_PHONE_STATE cannot be granted by default to package:com.qiku.android.contacts
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.READ_CALL_LOG cannot be granted by default to package:com.qiku.android.contacts
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.WRITE_CALL_LOG cannot be granted by default to package:com.qiku.android.contacts
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.CALL_PHONE cannot be granted by default to package:com.qiku.android.contacts
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:com.android.voicemail.permission.ADD_VOICEMAIL cannot be granted by default to package:com.qiku.android.contacts
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.PROCESS_OUTGOING_CALLS cannot be granted by default to package:com.qiku.android.contacts
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.GET_ACCOUNTS cannot be granted by default to package:com.google.android.gm
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.READ_CONTACTS cannot be granted by default to package:com.google.android.gm
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.WRITE_CONTACTS cannot be granted by default to package:com.google.android.gm
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.READ_CALENDAR cannot be granted by default to package:com.google.android.gm
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.WRITE_CALENDAR cannot be granted by default to package:com.google.android.gm
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.READ_CONTACTS cannot be granted by default to package:com.qiku.android.calendar
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.READ_CALENDAR cannot be granted by default to package:com.qiku.android.calendar
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.WRITE_CALENDAR cannot be granted by default to package:com.qiku.android.calendar
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.ACCESS_COARSE_LOCATION cannot be granted by default to package:com.google.android.apps.maps
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.ACCESS_FINE_LOCATION cannot be granted by default to package:com.google.android.apps.maps
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.CAMERA cannot be granted by default to package:com.android.camera
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.RECORD_AUDIO cannot be granted by default to package:com.android.camera
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.WRITE_EXTERNAL_STORAGE cannot be granted by default to package:com.android.camera
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.READ_EXTERNAL_STORAGE cannot be granted by default to package:com.android.camera
看上去与问题 1很想,这里分开说明,那肯定是有不同的原因的。
来看下GTS 的Test code:
public void testDefaultGrantsWithRemoteExceptions() throws Exception {
List allPackages = getAllPackages();
Set runtimePermNames = getRuntimePermissionNames(allPackages);
ArrayMap packagesToVerify = getMsdkTargetingPackagesUsingRuntimePerms(allPackages, runtimePermNames);
SparseArray pregrantUidStates = new SparseArray();
addSysComponentsAndPrivAppsDefaultPermissions(packagesToVerify, pregrantUidStates);
...
...
addCameraDefaultPermissions(packagesToVerify, pregrantUidStates);
...
addDefaultSmsDefaultPermissions(packagesToVerify, pregrantUidStates);
...
addCalendarDefaultPermissions(packagesToVerify, pregrantUidStates);
...
addContactsDefaultPermissions(packagesToVerify, pregrantUidStates);
...
...
StringBuilder violations = new StringBuilder();
PackageManager packageManager = BusinessLogicTestCase.getInstrumentation().getContext().getPackageManager();
for (PackageInfo packageInfo : packagesToVerify.values()) {
UidState uidState = (UidState) pregrantUidStates.get(packageInfo.applicationInfo.uid);
if (uidState != null) {
int grantCount = uidState.grantedPermissions.size();
for (int i = 0; i < grantCount; i++) {
String permission = (String) uidState.grantedPermissions.keyAt(i);
if (ArrayUtils.contains(packageInfo.requestedPermissions, permission) && packageManager.checkPermission(permission, packageInfo.packageName) == 0) {
boolean grantBackFineLocation = false;
if (permission.equals("android.permission.ACCESS_COARSE_LOCATION")) {
if (packageManager.checkPermission("android.permission.ACCESS_FINE_LOCATION", packageInfo.packageName) == 0) {
setPermissionGrantState(packageInfo.packageName, "android.permission.ACCESS_FINE_LOCATION", false);
grantBackFineLocation = true;
}
}
setPermissionGrantState(packageInfo.packageName, permission, false);
if (!((Boolean) uidState.grantedPermissions.valueAt(i)).booleanValue() && packageManager.checkPermission(permission, packageInfo.packageName) == 0) {
violations.append("Permission:").append(permission).append(" grated by default to package:").append(packageInfo.packageName).append(" should be revocable").append('\n');
}
setPermissionGrantState(packageInfo.packageName, permission, true);
if (grantBackFineLocation) {
setPermissionGrantState(packageInfo.packageName, "android.permission.ACCESS_FINE_LOCATION", true);
}
packageInfo.requestedPermissions = ArrayUtils.removeString(packageInfo.requestedPermissions, permission);
}
}
}
}
for (PackageInfo packageInfo2 : packagesToVerify.values()) {
int uid = packageInfo2.applicationInfo.uid;
for (String requestedPermission : packageInfo2.requestedPermissions) {
uidState = (UidState) pregrantUidStates.get(uid);
if ((uidState == null || uidState.grantedPermissions.indexOfKey(requestedPermission) < 0) && runtimePermNames.contains(requestedPermission) && packageManager.checkPermission(requestedPermission, packageInfo2.packageName) == 0) {
violations.append("Permission:").append(requestedPermission).append(" cannot be granted by default to package:").append(packageInfo2.packageName).append('\n');
}
}
}
if (violations.length() > 0) {
Assert.fail(violations.toString());
}
}
code 比较多,我们逐步解析。
1、getAllPackages()
private List getAllPackages() {
return BusinessLogicTestCase.getInstrumentation().getContext().getPackageManager().getInstalledPackages(12352);
}
12352 转换16进制应该是0x3040,根据PackageManager 中对应,应该是:
GET_UNINSTALLED_PACKAGES | GET_PERMISSIONS | GET_RESOLVED_FILTER,根据系统情况来看,这里传的参数可能是GET_PERMISSIONS 。
2、getRuntimePermissionNames()
private static Set getRuntimePermissionNames(List packageInfos) {
Set permissions = new ArraySet();
for (PackageInfo packageInfo : packageInfos) {
if (packageInfo.permissions != null) {
for (PermissionInfo permissionInfo : packageInfo.permissions) {
if (!((permissionInfo.protectionLevel & 1) == 0 || (permissionInfo.flags & Ints.MAX_POWER_OF_TWO) == 0 || !permissionInfo.packageName.equals(PLATFORM_PACKAGE_NAME))) {
permissions.add(permissionInfo.name);
}
}
}
}
return permissions;
}
这是收集 1 中获取的所有package 中使用到的系统的runtime permission
3、getMsdkTargetingPackagesUsingRuntimePerms()
private static ArrayMap getMsdkTargetingPackagesUsingRuntimePerms(List packageInfos, Set runtimePermNames) {
ArrayMap packageInfoMap = new ArrayMap();
int packageInfoCount = packageInfos.size();
for (int i = 0; i < packageInfoCount; i++) {
PackageInfo packageInfo = (PackageInfo) packageInfos.get(i);
if (packageInfo.requestedPermissions != null) {
if (packageInfo.applicationInfo.targetSdkVersion >= 23) {
for (String requestedPermission : packageInfo.requestedPermissions) {
if (runtimePermNames.contains(requestedPermission)) {
packageInfoMap.put(packageInfo.packageName, packageInfo);
break;
}
}
}
}
}
return packageInfoMap;
}
这里是这个case 中比较重要的一环,要求收集所有含有runtime permission 的package 对应的packageInfo,后面的所有操作都是依赖这里的map。
4、打印异常log
从code 上看没有多大的问题,主要是轮询系统中installed 的所有apps,然后进行遍历找到要求的app 进行verify。注意code 最后的一部分,发现打印的log 是在最后:
for (PackageInfo packageInfo2 : packagesToVerify.values()) {
int uid = packageInfo2.applicationInfo.uid;
for (String requestedPermission : packageInfo2.requestedPermissions) {
uidState = (UidState) pregrantUidStates.get(uid);
if ((uidState == null || uidState.grantedPermissions.indexOfKey(requestedPermission) < 0) && runtimePermNames.contains(requestedPermission) && packageManager.checkPermission(requestedPermission, packageInfo2.packageName) == 0) {
violations.append("Permission:").append(requestedPermission).append(" cannot be granted by default to package:").append(packageInfo2.packageName).append('\n');
}
}
}
这段code 是说如果没有轮询到的系统中的app 对应的UidState 对象为null 或者是UidState 对象中的grantedPermissions 为空的时候会打印 log (后面的条件就忽略就是,要求是granted 的permission),那么如果不想打印这段log,这里必须是UidState 对象不为null 而且对应的成员变量grantedPermissions 不为空。
其实,理论上,这里的Test code 中要求的permission 应该是跟framework 中对应的,要求某些特殊的app 的runtime permission默认是granted,那么之所以出现了问题,肯定就是在UidState 的对象上。
log太多,我们以一种camera 为例,log 如下:
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.CAMERA cannot be granted by default to package:com.android.camera
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.RECORD_AUDIO cannot be granted by default to package:com.android.camera
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.WRITE_EXTERNAL_STORAGE cannot be granted by default to package:com.android.camera
07-22 04:22:02.819 2255 2273 I TestRunner: Permission:android.permission.READ_EXTERNAL_STORAGE cannot be granted by default to package:com.android.camera
看到包名是不是觉得奇怪,从包名来看应该是属于google 源生的app,那肯定google 自己GTS 是pass的,为什么这里又出问题了呢?
主要是看UidState 对象初始化的地方,下面以camera 为例,来看下code。
5、addCameraDefaultPermissions()
addCameraDefaultPermissions(packagesToVerify, pregrantUidStates);
---->
private void addCameraDefaultPermissions(Map packageInfos, SparseArray outUidStates) throws Exception {
String packageName = getDefaultSystemHandlerActivityPackageName(new Intent("android.media.action.IMAGE_CAPTURE"));
if (packageName != null) {
PackageInfo packageInfo = (PackageInfo) packageInfos.get(packageName);
if (packageInfo != null && doesPackageSupportingRuntimePermissions(packageInfo)) {
appendPackagePregrantedPerms(packageInfo, false, CAMERA_PERMISSIONS, outUidStates);
appendPackagePregrantedPerms(packageInfo, false, MICROPHONE_PERMISSIONS, outUidStates);
appendPackagePregrantedPerms(packageInfo, false, STORAGE_PERMISSIONS, outUidStates);
}
}
}
code 大概意思是找到对应action 的packageName,然后进行appendPackagePregrantedPerms 操作。
详细的code 这里暂时不贴了,这个appendPackagePregrantedPerms 其实就是创建UidState 对象。
反言之,如果某个package 中有对应camera 要求的action(这一规则也适合其他的模块),并且是正常安装,那么这个package 默认可以对CAMERA_PERMISSIONS、MICROPHONE_PERMISSIONS、STORAGE_PERMISSIONS 里面的所有权限是 granted 状态(当然,除此以外的permission 是不能默认granted)。
结合上面第 4 点的分析,如果UidState 为null或者UidState 中的grantedPermissions表中没有对应的permission,那么只有可能这里的append 操作失败,也就是说getDefaultSystemHandlerActivityPackageName() 函数的返回值为null。下面来看下这个函数:
private String getDefaultSystemHandlerActivityPackageName(Intent intent) {
return getDefaultSystemHandlerActivityPackageName(intent, 0);
}
private String getDefaultSystemHandlerActivityPackageName(Intent intent, int flags) {
ResolveInfo handler = BusinessLogicTestCase.getInstrumentation().getContext().getPackageManager().resolveActivity(intent, flags);
if (handler == null || (handler.activityInfo.applicationInfo.flags & 1) == 0) {
return null;
}
return handler.activityInfo.packageName;
}
并没有什么问题啊?怎么回事呢?看下framework 对应的source code:
private PackageParser.Package getDefaultSystemHandlerActivityPackageLPr(
Intent intent, int userId) {
ResolveInfo handler = mService.resolveIntent(intent,
intent.resolveType(mService.mContext.getContentResolver()), DEFAULT_FLAGS, userId);
if (handler == null || handler.activityInfo == null) {
return null;
}
ActivityInfo activityInfo = handler.activityInfo;
if (activityInfo.packageName.equals(mService.mResolveActivity.packageName)
&& activityInfo.name.equals(mService.mResolveActivity.name)) {
return null;
}
return getSystemPackageLPr(handler.activityInfo.packageName);
}
这下知道原因了,在framework 中获取app 信息的时候,resolveIntent 的参数中有一项为DEFAULT_FLAGS:
private static final int DEFAULT_FLAGS =
PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.MATCH_UNINSTALLED_PACKAGES;
而同样的函数在Test 中是 0,显然跟 DEFAULT_FLAGS 是有差异的。
整个流程分析完了,回到上面的问题1,结合framework 的code 和Test code,其实我们知道GTS 如果想要这一项通过,必须满足条件:
1. framework 中轮询到的app,test 中也要能轮询到,这要求轮询的条件要一样。
这个就是问题2 的原因
2. framework 中grant 的app 默认runtime permission 在test 中也必须是一样的。
这就要求,默认的DefaultPermissionGrantPolicy.java 文件不能多做权限方面的添加,这个就是问题1 的原因
3. 应用中对于runtime permission,系统中不要手动修改或者特殊地方修改修改为granted。
这个跟问题1 类似
更多GTS 测试的case 见:
CTS/GTS 常见问题汇总