前言:
最近在做GMS 的验证,其中测试case rmeabi-v7a GtsPermissionTestCases 的时候出现了异常,有些注意点这里总结一下。
问题1:
出现的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 的问题,下面在问题2 中一并分析。
问题2:
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<PackageInfo> allPackages = getAllPackages();
Set<String> runtimePermNames = getRuntimePermissionNames(allPackages);
ArrayMap<String, PackageInfo> packagesToVerify = getMsdkTargetingPackagesUsingRuntimePerms(allPackages, runtimePermNames);
SparseArray<UidState> 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 上看没有多大的问题,主要是轮询系统中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 的对象上。
下面举其中的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的,为什么这里又出问题了呢?
注意上面的Test code 中:
addCameraDefaultPermissions(packagesToVerify, pregrantUidStates);
---->
private void addCameraDefaultPermissions(Map<String, PackageInfo> packageInfos, SparseArray<UidState> 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 对象,结合之前的分析,如果UidState 为null,那么只有可能这里的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);
}
这下应该知道原因了,去问问google 为什么吧!
整个流程分析完了,回到上面的问题1,结合framework 的code 和Test code,其实我们知道GTS 如果想要这一项通过,必须满足条件:
- framework 中轮询到的app,test 中也要能轮询到,这要求轮询的条件要一样。这个就是问题2 的原因
- framework 中grant 的app 默认runtime permission 在test 中也必须是一样的。这个就是问题1 的原因