GTS 中testDefaultGrantsWithRemoteExceptions fail 详解

来源:

https://justinwei.blog.csdn.net/article/details/81173056

前言:

最近在做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:

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 比较多,我们逐步解析。

1、getAllPackages()

    private List<PackageInfo> 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<String> getRuntimePermissionNames(List<PackageInfo> packageInfos) {
        Set<String> 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<String, PackageInfo> getMsdkTargetingPackagesUsingRuntimePerms(List<PackageInfo> packageInfos, Set<String> runtimePermNames) {
        ArrayMap<String, PackageInfo> 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<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 对象。

反言之,如果某个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 常见问题汇总

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

私房菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值