浅谈Android 权限测试设计
众所周知,Android 系统碎片化严重,关于Android的app权限类测试也复杂多样化,如果缺乏对Android 系统权限基础知识的理解和权限申请实现方式理解、权限与业务映射关系,则会导致测试覆盖不全,质量得不到保障的情况,基于以上痛点,我们基于对权限基础、不同系统权限管理特征、权限申请实现原理、厂商定制权限管理特征进行分析设计Android权限测试正交矩阵用例来保障产品的权限测试质量。
1、Android权限基本认识
在谈如何进行Android 权限测试之前,我们先来理解一下对权限对基本认识。
1.1 Android 权限机制
Android的权限管理遵循的是“最小特权原则”,即所有的Android应用程序都被赋予了最小权限。一个Android应用程序如果没有声明任何权限,就没有任何特权。因此,应用程序如果想访问其他文件、数据和资源就必须在AndroidManifest.xml文件中进行声明,以所声明的权限去访问这些资源。否则,如果缺少必要的权限,由于沙箱的保护,这些应用程序将不能够正常提供所期望的功能与服务。
所有应用程序对权限的申请和声明都被强制标识于AndroidManifest.xml文件之中,通过标签指定。如果需要申请某个权限,可以通过指定。应用程序申请的权限在安装时提示给用户,用户可以根据自身需求和隐私保护决定是否允许对该应用程序授权。
1.2 权限分类
1.2.1 基于Linux内核,Android系统中的权限分类
由于基于Linux内核,Android系统中的权限分为以下3类。
(1) Android手机所有者权限
这个和厂商相关,可以理解为系统权限。
(2) Android ROOT权限
类似于Linux,这是Android系统中的最高权限。如果拥有该权限,就可以对Android系统中的任何文件、数据、资源进行任意操作。所谓“越狱”,就是令用户获得最高的ROOT权限。
(3) Android应用程序权限
该权限在AndroidManifest文件中由程序开发者声明,在程序安装时由用户授权,共有下述4类不同的权限保护级别(Protection Level)。
- normal 表示权限是低风险的,不会对系统、用户或其他应用程序造成危害。
- dangerous 表示权限是高风险的,系统将可能要求用户输入相关信息才会授予权限。
- signature 表示只有当应用程序所用数字签名与声明引用权限的应用程序所有数字签名相同时,才能将权限授予它。
- signatureOrSystem 表示将权限授予具有相同数字签名的应用程序或者只有Android系统包类才可访问。
1.2.2 基于权限的隐私危害性评估分类
Android 6.0 以后,Google对每个权限的隐私危害性进行了评估。将权限分为了主要的三大类:普通权限 、特殊权限 和危险权限。
-
普通权限:不会直接给用户隐私权带来风险。如果您的应用在其清单中列出了正常权限,系统将自动授予该权限。
-
特殊权限:有许多权限其行为方式与正常权限及危险权限都不同。
SYSTEM_ALERT_WINDOW
和WRITE_SETTINGS
特别敏感,因此大多数应用不应该使用它们。如果某应用需要其中一种权限,必须在清单中声明该权限,并且发送请求用户授权的 intent。系统将向用户显示详细信息,以响应该 intent。 -
危险权限:会授予应用访问用户机密数据的权限。如果您列出了危险权限,则用户必须明确批准您的应用使用这些权限。
开发者在使用到危险权限相关的功能时,不仅需要在Manifest文件中配置,还需要在代码中动态获取权限,如果没有确认获取到权限而直接执行相应所需权限的代码,将导致App崩溃。另外,Android6.0 以上系统,App 退到后台,修改应用权限,再次 App 回到前台,会出现应用新开进程重启。
需要向用户申请的危险权限主要有以下权限:
权限组名 | 中文名 | 权限名 |
---|---|---|
LOCATION | 定位 | ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION |
CALENDAR | 日历 | READ_CALENDAR,WRITE_CALENDAR |
CAMERA | 照相机 | CAMERA |
CONTACTS | 通讯录 | READ_CONTACTS,WRITE_CONTACTS,GET_CONTACTS |
STORAGE | 存储 | READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE |
SENSORS | 传感器 | BODY_SENSORS |
MICROPHONE | 麦克风 | RECORD_AUDIO |
PHONE | 电话 | READ_PHONE_STATE,CALL_PHONE,READ_CALL_LOG,WRITE_CALL_LOG,ADD_VOICEMATL,USE_SIP,PROCESS_OUTGOING_CALLS |
SMS | 短信 | SEND_SMS,RECEIVE_SMS,READ_SMS,RECEIVE_WAP_PUSH,RECEIVE_MMS |
1.3 权限相关API说明
首先,在动态权限申请的流程中,开发者主要关注流程和API如下:
1、检查权限是否授予。
Activity.java
public int checkSelfPermission(permission)
2、申请权限。
Activity.java
public final void requestPermissions( new String[permission1,permission2,...], requestCode)
这个时候,会弹出系统授权弹窗(授权弹窗是不支持自定义的,原因理所当然)。
3、权限回调。
用户在系统弹窗里面选择后,结果会通过Activity的onRequestPermissionsResult方法回调APP。
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
//继续执行逻辑或者提示权限获取失败
}
4、权限说明。
用户如果选择了拒绝,下一次在需要声明该权限的时候,Google建议APP开发者给予用户更多的说明,因此提供了下面这个API,这个方法返回值在使用过程中会发现有点纠结(具体解析见下面代码块说明)。
public boolean shouldShowRequestPermissionRationale(permission)
{
1、APP没有申请这个权限的话,返回false
2、用户拒绝时,勾选了不再提示的话,返回false
3、用户拒绝,但是没有勾选不再提示的话,返回true
因此如果想在第一次就给用户提示,需要记录权限是否申请过,没有申请过的话,强制弹窗提示,而不能根据这个方法的返回值来。
}
2、 Android 系统对应用程序权限申请的方式
这里根据不同targetSdkVersion和android系统做判断,总结汇总了一张Android 系统对应用程序权限申请方式方便大家理解,并指导后续进行权限测试设计,具体见图
Android权限使用流程图.png2.1 targetSdkVersion>=23,系统6.0+
安装的时候不会获得权限,在运行时向用户申请对应权限。这部分权限检查比较简单,不涉及权限兼容,使用官方方案就可以 ,使用 Context::checkSelfPermisson
2.2 targetSdkVersion<23,系统6.0+
旧版本APP(targetSdkVersion低于23),因为没有适配权限的申请相关逻辑,在Android6.0以上机型运行的时候,仍然采用安装时授权的方案
- 进入处理应用程序授权申请的入口函数;
- 系统从被安装应用程序的 AndroidManifest.xml 文件中获取该应用正常运行需申请的权限列表;
- 显示对话框,请求用户确认是否满足这些权限需求;
若同意,则应用程序正常安装,并被赋予相应的权限;若否定,则应用程序不被安装。系统仅提供给用户选择“是”或者“否”的权利,没有选择其中某些权限进行授权的权利。
2.3 部分国产定制机,系统小于6.0(api 23)
- 适配了Android6.0的APP,在低版本Android系统上运行的时候,仍然采用安装时授权的方案,但是开发者需要注意的是,权限申请的代码逻辑只应该在Android6.0及以上的机型被执行。
- 对于原生系统而言,系统小于6.0情况肯定是用的老的权限管理机制,在app 安装时会询问。
- 部分国产手机情况:但是目前有不少国产Rom 手机在6.0之前就有关闭权限的开关,例如小米的安全中心。这种情况也是我们兼容的对象。
例如:
(1)部分国产厂商定制了系统(例如小米、华为),在6.0以下系统就可以单独控制权限。但是通常它们处理的不够彻底,代码中判断是否授权的时候,返回的是已经授权。而真正去做操作的时候,却会因为没有权限导致应用crash
(2)部分中国厂商生产手机(例如小米某型号)的Rationale功能,在第一次拒绝后,第二次申请时不会返回true,并且会回调申请失败,也就是说在第一次拒绝后默认勾选了不再提示。
(3)部分中国厂商生产手机(例如vivo、Oppo某型号)在用户允许权限,并且回调了权限授权成功的方法,但是实际执行代码时并没有这个权限
(4)权限组是有权限的,但是部分厂商(例如华为)添加了单独禁止某一条权限,这时候你判断是有权限的,但使用就会有问题。例如通讯录,你可以单独禁止读取通讯录,但是通讯录权限组是有权限的,你这是读取通讯录就会有问题。
(5)APP运行期间,部分厂商(例如三星)去设置页面关闭此APP的权限,APP会被重置。
3、检查Android权限与功能的对应关系
3.1 业务权限梳理
梳理出业务所有权限
通过以下的手段把业务的权限列表梳理出来:
- 获取业务本身自己的权限
可以通过PackageManager.getPackageInfo.(pkgName, PackageManager.GET_PERMISSIONS).requestedPermissions获取到。
PackageManager pm = getPackageManager();
boolean permission = (PackageManager.PERMISSION_GRANTED ==
pm.checkPermission("android.permission.RECORD_AUDIO", "packageName"));
if (permission) {
showToast("有这个权限");
}else {
showToast("木有这个权限");
}
try {
PackageInfo pack = pm.getPackageInfo("packageName",PackageManager.GET_PERMISSIONS);</span>
String[] permissionStrings = pack.requestedPermissions;
showToast("权限清单--->" + permissionStrings.toString());
} catch (NameNotFoundException e) {
e.printStackTrace();
}
2. 获取其他业务的权限
可以通过Android XmlResourceParser解析AndroidManifest.xml文件获取到。
3.2 找出各权限和功能的对应关系
可以通过和相应功能的开发进行沟通确定。确定不了的,需要查看对应功能代码,找出关键的触发权限的API,最后,梳理权限及功能的对应关系,如下图:
业务权限映射图_以xx直销银行app为例.png4、得出测试设计矩阵
根据以上内容中的权限分类,android6.0以下和6.0以上的权限使用重大区别,和权限及功能映射关系,再根据不同厂商的定制特点、不同操作方式得出以下android 权限测试设计矩阵
android权限测试设计矩阵_表格数字代码验证点数.png
备注:厂商权限验证点.png