当前位置: 首页 > news >正文

Android 权限管理机制

一. 权限管理核心机制

Android 的权限管理建立在 Linux 的基础上,并加入了更高级别的抽象和控制。其核心机制可以概括为以下几点:

  1. Linux 内核层隔离 (UID/GID)
    ○ 基础
    : Android 继承并强化了 Linux 的 UID(用户ID)和 GID(组ID)机制
    ○ 沙箱: 每个 Android 应用在安装时都会被分配一个唯一的、永久的 UID。这意味着每个应用都在自己独立的 Linux 进程中运行,拥有自己的文件目录(/data/data/<package_name>),其文件权限被设置为仅允许自身(即相同 UID)访问。这构成了应用沙箱的基础
    ○ 权限映射: 许多 Android 权限(特别是设备资源相关的,如 android.permission.BLUETOOTH)在底层实际上被映射到一个特定的 GID(例如 net_bt)。当应用被授予该权限时,它的进程就会被加入到对应的 GID 组中。在 Linux 中,组权限决定了能否访问某些设备驱动(如 /dev/bluetooth
  2. 权限级别 (Protection Level)
    权限在 AndroidManifest.xml 中定义时,会通过 android:protectionLevel 属性来声明其危险程度和保护方式
    ○ normal: 低风险权限,系统在安装时自动授予
    ○ dangerous: 高风险权限,涉及用户隐私或设备控制。必须向用户显式请求并由用户批准
    ○ signature: 只有与定义该权限的应用使用相同证书签名的应用才能获得此权限。用于应用套件内部通信
    ○ signatureOrSystem / internal: 更高级别的系统权限,通常仅供 OEM 或系统应用使用
  3. 权限授予时机
    ○ 安装时授权 (Android 5.1及以前)
    : 用户在安装应用前,必须同意应用请求的所有权限
    ○ 运行时授权 (Runtime Permissions, Android 6.0+): 对于 dangerous 级别的权限,用户可以在应用运行时再决定是否授予。应用可以在需要时动态请求,用户也可以随时在设置中撤销授权。这给了用户更大的控制权
  4. 权限执行者 (Enforcement)
    ○ 在框架层 (Framework)
    : 由 ActivityManagerService (AMS) 和 PackageManagerService (PMS) 负责。当应用调用一个受权限保护的 API(如 getDeviceId())时,API 内部会通过 Context.checkPermission() 等方法检查调用者是否拥有相应权限
    ○ 在原生层/Native (Binder IPC): 许多系统服务(如 BluetoothServiceVold)运行在 Native 层。它们通过 Binder IPC 接收请求。它们会使用 IPCThreadState::getCallingUid() 获取调用者的 UID,然后向 PMS 查询该 UID 对应的包是否拥有所需权限
    ○ 在内核层 (Kernel): 通过 SELinux (Security-Enhanced Linux) 和传统的文件系统权限(DAC)进行最终的控制。即使应用通过了框架层的检查,如果 SELinux 策略不允许该进程访问某个内核资源,访问也会被拒绝

二. 权限申请流程全链路分析

让我们以应用申请 android.permission.CAMERA 这个危险权限为例,追踪其完整流程

阶段 1:应用层 (Java) - 发起请求
  1. 声明权限: 在 AndroidManifest.xml 中声明
    <uses-permission android:name="android.permission.CAMERA" />
  2. 运行时检查与请求

    // 1. 检查是否已有权限
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED) {// 2. 如果没有,向用户展示解释(可选)if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.CAMERA)) {// 告诉用户为什么需要这个权限}// 3. 发起正式的权限请求弹窗ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA},MY_CAMERA_PERMISSION_REQUEST_CODE);
    } else {// 4. 已经有权限,直接操作相机openCamera();
    }
  3. 处理回调

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {if (requestCode == MY_CAMERA_PERMISSION_REQUEST_CODE) {if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {openCamera(); // 用户同意,执行操作} else {// 用户拒绝}}
    }
阶段 2:框架层 (Framework) - 处理请求与持久化
  1. requestPermissions() 调用路径
    ○ Activity.requestPermissions() -> ActivityCompat.requestPermissions()
    ○ 最终通过 Binder IPC 调用到 ActivityManagerService 的 grantRuntimePermission 相关方法
  2. 权限弹窗: AMS 会协调创建一个系统的权限请求对话框(UI 属于 Settings 应用或 PermissionController 组件),以当前应用的上下文显示,但完全由系统控制,应用无法干预
  3. 用户决策: 用户点击“允许”或“拒绝”
  4. 持久化授权结果
    ○ 用户的决定由 PermissionController 通过 PackageManagerService 的 grantRuntimePermission() 或 revokeRuntimePermission() 方法进行记录
    ○ PMS 是权限状态的最终权威。它将授权结果写入到 /data/system/users/<user-id>/runtime-permissions.xml 文件中。这样即使设备重启,权限状态也会保留
    ○ PMS 还会更新其内存中的数据结构,以便快速查询
阶段 3:权限执行 (Enforcement) - 当应用使用相机时
  1. 应用调用 API: 应用调用 Camera.open()
  2. 框架层检查: CameraService (一个系统服务) 会收到打开摄像头的请求。在它的 Binder 接口方法中,它会执行安全检查:
    // 这是一个概念性代码,类似于CameraService内部的逻辑
    public class CameraService extends ICameraService.Stub {@Overridepublic ICamera connect(ICameraClient client, ...) {// 获取调用者的 UID 和 PIDint callingPid = Binder.getCallingPid();int callingUid = Binder.getCallingUid();// 关键检查:调用者是否有Camera权限?if (mContext.checkPermission(android.Manifest.permission.CAMERA, callingPid, callingUid)!= PackageManager.PERMISSION_GRANTED) {// 如果没有权限,抛出SecurityException异常throw new SecurityException("Required CAMERA permission not granted for uid=" + callingUid);}// ... 继续打开相机的逻辑}
    }
    ○ mContext.checkPermission() 会向 PMS 发起查询:“UID 为 callingUid 的应用是否有 CAMERA 权限?”
    ○ PMS 查阅其内存中的权限数据库(从 runtime-permissions.xml 加载而来),并返回结果
  3. Native 层检查 (可选): 有些服务(如 vold 存储服务)直接运行在 Native 层。它们的检查流程类似:
    ○ IPCThreadState::getCallingUid() 获取调用者 UID
    ○ 通过 Binder 调用回 PMS 的 Native 接口 IPackageManagerNative 或与上层 PMS 的 Java 服务通信,来检查权限
阶段 4:内核层 (Kernel) - 最终防线

即使应用通过了所有框架层的权限检查,当它尝试真正操作硬件设备(如 /dev/video0 摄像头设备节点)时,还会受到内核的最后一道关卡检查

  1. 文件系统权限 (DAC)
    ○ 设备节点 /dev/video0 有其所属用户和组(如 root:camera
    ○ 它的权限可能是 crw-rw----,意味着所有者(root)和组员(camera)有读写权限,其他用户无权限
    ○ 应用进程的 UID 是 app_123,它不属于 camera 组,按理说无法访问。但为什么有权限的应用能访问?因为在安装时授予 CAMERA 权限后,PMS 会将应用的 UID 加入到 camera 组中(在 /data/system/packages.list 中记录)。这样,应用进程就具备了访问设备节点的组权限
  2. SELinux (MAC)
    ○ DAC 的粒度较粗。SELinux 提供了更细粒度的强制访问控制
    ○ 每个进程都有一个 domain(域),每个文件/设备都有一个 type(类型)
    ○ SELinux 策略规则定义了哪个 domain 可以对哪个 type 执行哪些操作(如 readwriteopen
    ○ 示例策略
    # 允许 untrusted_app 域(普通应用)对 camera_device 类型执行 open 操作。
    allow untrusted_app camera_device:chr_file open;

    ○ 如果策略中没有明确允许的规则,即使 DAC 允许,访问也会被 avc: denied 并拒绝。这是 Android 安全的重要基石

总结

Android 的权限管理是一个贯穿整个系统栈的深度防御体系:

层级角色关键技术
应用层申请checkSelfPermission()requestPermissions()
框架层管理、授权、执行PackageManagerServiceActivityManagerService, Binder IPC
Native层执行IPCThreadState::getCallingUid(), 与 PMS 通信
内核层最终执行Linux UID/GID (DAC), SELinux (MAC)

文章转载自:

http://uispgYRF.qrsrs.cn
http://WaWaiDNe.qrsrs.cn
http://Vy5CjS5x.qrsrs.cn
http://pcz0uGZq.qrsrs.cn
http://1x3LQXYD.qrsrs.cn
http://UF3ffhJP.qrsrs.cn
http://jzf4hycS.qrsrs.cn
http://aRzfyluU.qrsrs.cn
http://WdRJU2cf.qrsrs.cn
http://gM5v4qy7.qrsrs.cn
http://ujzhQjKi.qrsrs.cn
http://Y4fdHP0p.qrsrs.cn
http://9a8mIsk7.qrsrs.cn
http://CjfI5I3f.qrsrs.cn
http://1pNtBghp.qrsrs.cn
http://g9GCDUR0.qrsrs.cn
http://bqtJYDCg.qrsrs.cn
http://S0Zf53Mg.qrsrs.cn
http://FbTmgrnc.qrsrs.cn
http://RZq8O7Eh.qrsrs.cn
http://8HSPzj6k.qrsrs.cn
http://MzQN22bH.qrsrs.cn
http://qhPZk4hs.qrsrs.cn
http://NP0CNpkG.qrsrs.cn
http://VFpUtk5R.qrsrs.cn
http://GpFrvjOA.qrsrs.cn
http://bJ5TDUun.qrsrs.cn
http://bP8ug60w.qrsrs.cn
http://P3V6OZkv.qrsrs.cn
http://IL7xfiUe.qrsrs.cn
http://www.dtcms.com/a/367611.html

相关文章:

  • MATLAB平台实现人口预测和GDP预测
  • jQuery的$.Ajax方法分析
  • 实现自己的AI视频监控系统-第三章-信息的推送与共享4
  • Vben5 封装的组件(豆包版)
  • 研发文档更新滞后的常见原因与解决方法
  • AI工具深度测评与选型指南 - Lovart专题
  • 卡方检验(独立性检验)
  • 【C语言】第四课 指针与内存管理
  • Mac开发第一步 - 安装Xcode
  • Full cycle of a machine learning project|机器学习项目的完整周期
  • AES介绍以及应用(crypto.js 实现数据加密)
  • 四十岁编程:热爱、沉淀与行业的真相-优雅草卓伊凡
  • 【数据分享】中国城市营商环境数据库2024(296个城市)(2017-2022)
  • 结合prompt分析NodeRAG的build过程
  • 2025数学建模国赛高教社杯B题思路代码文章助攻
  • Nano-Banana使用教程
  • 在Spring MVC中使用查询字符串与参数
  • Unity中,软遮罩SoftMaskForUGUI的使用
  • Websocket的Key多少个字节
  • 手写Java泛型,彻底掌握它!
  • Redlock:为什么你的 Redis 分布式锁需要不止一个节点?
  • leetcode 1419 数青蛙
  • 蔚来汽车前制动器设计及热性能分析cad+三维图+设计说明书
  • 唯品会获得vip商品详情 API 返回值说明
  • Java对接Kafka的三国演义:三大主流客户端全景评测
  • 2020年_408统考_数据结构41题
  • 简单例子实现 字符串搜索替换
  • Python/JS/Go/Java同步学习(第三篇)四语言“切片“对照表: 财务“小南“纸切片术切凭证到崩溃(附源码/截图/参数表/避坑指南/老板沉默术)
  • 【IO】共享内存、信息量集
  • CmakeLists.txt相关