4. 权限分类与保护级别
Android 权限模型的核心并不只是“有没有权限”,而是“这个权限由谁授予、在什么条件下授予、授予后能访问什么资源”。保护级别(protectionLevel)正是回答这些问题的关键属性。它决定了系统在安装、运行时或签名校验阶段如何处理权限请求,也决定了应用能否静默获得权限、必须弹窗征求用户同意,还是只能由系统或同签名应用持有。
理解保护级别,需要把它和权限的“应用场景”放在一起看。一个权限被声明为 dangerous,并不意味着它一定危险,而是表示它涉及用户隐私或敏感数据,必须经过用户显式授权;一个权限被声明为 signature,也不代表它更安全,而是表示只有与声明者使用相同签名的应用才能获得。保护级别是权限的“准入门槛”,而不是权限的“功能强弱”。
一、核心原理:保护级别如何决定授权路径
在 Android 中,权限通常由系统应用或框架在 AndroidManifest.xml 中通过 <permission> 标签声明,并指定 android:protectionLevel。应用在清单中通过 <uses-permission> 请求权限。系统在安装或运行时根据保护级别执行不同策略:
- normal:低风险权限,安装时自动授予,不提示用户。例如
INTERNET、ACCESS_NETWORK_STATE、VIBRATE。 - dangerous:涉及隐私或敏感资源,必须运行时动态申请,由用户弹窗确认。例如
CAMERA、RECORD_AUDIO、ACCESS_FINE_LOCATION。 - signature:仅授予与权限声明者签名相同的应用。例如系统级权限
READ_LOGS、部分厂商定制权限。 - special:特殊权限,通常不由普通应用直接声明,而由系统框架管理,用户需在设置页手动开启。例如
SYSTEM_ALERT_WINDOW、WRITE_SETTINGS、PACKAGE_USAGE_STATS。
此外还有 signatureOrSystem、privileged、development 等组合或扩展级别,它们多用于系统镜像、预装应用或开发调试场景。实际开发中,最常打交道的仍是 normal、dangerous、signature 和 special 四类。
二、方法流程:从声明到授权的完整链路
以 dangerous 权限为例,完整流程如下:
- 在 AndroidManifest.xml 中声明
<uses-permission android:name="android.permission.CAMERA"/>。 - 运行时检查是否已授权:
ContextCompat.checkSelfPermission()。 - 若未授权,调用
ActivityCompat.requestPermissions()发起请求。 - 系统弹出权限对话框,用户选择“允许”或“拒绝”。
- 在
onRequestPermissionsResult()中处理回调结果。 - 若用户勾选“不再询问”并拒绝,后续请求将直接返回拒绝,需引导用户去设置页手动开启。
对于 normal 权限,第 2 至第 5 步通常可以省略,因为系统在安装时已经授予。对于 signature 权限,普通应用即使声明也无法获得,除非与系统或声明者同签名。对于 special 权限,应用通常需要跳转到 Settings.ACTION_MANAGE_OVERLAY_PERMISSION 或 Settings.ACTION_USAGE_ACCESS_SETTINGS 等页面,由用户手动开启。
// 检查并申请 CAMERA 权限(dangerous)
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
new String[]{Manifest.permission.CAMERA},
REQ_CAMERA
);
} else {
openCamera();
}
// 处理回调
@Override
public void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] grantResults) {
if (requestCode == REQ_CAMERA) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openCamera();
} else {
showPermissionDeniedTip();
}
}
}
三、案例与场景:不同保护级别的典型应用
| 保护级别 | 典型权限 | 授权时机 | 应用场景 |
|---|---|---|---|
| normal | INTERNET、ACCESS_NETWORK_STATE、VIBRATE | 安装时自动授予 | 网络请求、网络状态监听、震动反馈 |
| dangerous | CAMERA、RECORD_AUDIO、ACCESS_FINE_LOCATION | 运行时弹窗授权 | 拍照、录音、定位导航、扫码 |
| signature | READ_LOGS、部分系统定制权限 | 安装时校验签名 | 系统日志读取、同签名应用间共享能力 |
| special | SYSTEM_ALERT_WINDOW、WRITE_SETTINGS、PACKAGE_USAGE_STATS | 设置页手动开启 | 悬浮窗、修改系统设置、应用使用统计 |
以一款“扫码点餐”应用为例:它需要网络权限(normal)上传订单,需要相机权限(dangerous)扫码,可能还需要悬浮窗权限(special)展示悬浮菜单。网络权限安装即得,相机权限必须运行时申请,悬浮窗权限则要引导用户去设置页开启。三类权限的申请方式完全不同,如果开发者把相机权限当作 normal 处理,应用会在运行时直接崩溃或功能不可用。
四、误区与复盘:保护级别使用中的常见问题
误区一:把 dangerous 权限写在清单里就以为已经获得。清单声明只是“申请”,真正授权发生在运行时。Android 6.0 以后,dangerous 权限必须动态申请,否则调用相关 API 会抛出 SecurityException。
误区二:认为 signature 权限可以通过用户授权获得。signature 权限不弹窗、不询问用户,只校验签名。普通应用即使引导用户去设置页也无法开启,除非与声明者同签名或预装到系统分区。
误区三:把 special 权限当作普通运行时权限申请。special 权限通常没有标准的 requestPermissions 弹窗,必须通过 Settings Intent 跳转,并且用户手动开启后还需回到应用重新检查。
复盘建议:在权限设计阶段,先列出应用真正需要的权限,再逐一标注保护级别。对 dangerous 权限,准备“申请前解释—申请中弹窗—拒绝后引导”的完整链路;对 special 权限,准备设置页跳转和状态回查;对 signature 权限,确认是否真的需要,若需要则评估签名方案或系统集成方式。坚持最小权限原则,能显著降低用户拒绝率和合规风险。
保护级别不是权限的“标签”,而是系统授权策略的入口。normal 让低风险能力静默可用,dangerous 把隐私决定权交给用户,signature 用签名建立信任边界,special 则由系统设置页兜底。理解这四类权限的授权路径和应用场景,才能在 Android 权限模型与系统安全工程中做出正确的权限设计与申请决策。