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 四类。

Android 权限保护级别与授权路径 protectionLevel 决定安装时、运行时或签名校验时的授权方式 应用请求权限 uses-permission 系统读取 protectionLevel PackageManager 校验 normal 安装时自动授予 无用户弹窗 INTERNET / VIBRATE dangerous 运行时动态申请 用户弹窗确认 CAMERA / LOCATION signature 同签名才可授予 安装时校验签名 READ_LOGS / 系统权限 special 设置页手动开启 系统框架管理 悬浮窗 / 写设置 关键判断: normal 看安装;dangerous 看运行时;signature 看签名;special 看系统设置页。四类权限的授权时机和用户感知完全不同。 开发时应按最小权限原则申请,避免把 dangerous 权限当作 normal 使用,也不要把 signature 权限误用于普通应用。

二、方法流程:从声明到授权的完整链路

以 dangerous 权限为例,完整流程如下:

  1. 在 AndroidManifest.xml 中声明 <uses-permission android:name="android.permission.CAMERA"/>。
  2. 运行时检查是否已授权:ContextCompat.checkSelfPermission()。
  3. 若未授权,调用 ActivityCompat.requestPermissions() 发起请求。
  4. 系统弹出权限对话框,用户选择“允许”或“拒绝”。
  5. 在 onRequestPermissionsResult() 中处理回调结果。
  6. 若用户勾选“不再询问”并拒绝,后续请求将直接返回拒绝,需引导用户去设置页手动开启。

对于 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 权限模型与系统安全工程中做出正确的权限设计与申请决策。