一、动态权限的核心流程:应用层与框架层的协作
Android 动态权限申请机制,是应用与系统服务之间的一次跨进程协作。
1. 应用层调用
- 权限检查:开发者通过
ContextCompat.checkSelfPermission(),检查应用是否已经拥有某个权限。 - 权限请求:如果权限未授予,开发者会调用
ActivityCompat.requestPermissions(),向系统发起权限请求。 - 结果回调:
onRequestPermissionsResult()方法会接收到用户的操作结果。
2. 底层调用链
Activity.requestPermissions()→ActivityCompat→Instrumentation→ActivityTaskManagerService(AMS)AMS接收到请求后,会启动一个系统级的GrantPermissionsActivity,来显示权限请求弹窗。
二、底层原理与源码分析:权限状态的维护
1. 权限检查
ContextCompat.checkSelfPermission()最终会通过 Binder 调用到PermissionManagerService(在现代 Android 系统中,权限管理的核心服务是它)。PermissionManagerService会在内存中查询该应用的 UID 对应的权限状态。如果权限被授予,返回PERMISSION_GRANTED;否则返回PERMISSION_DENIED。
2. 权限请求与弹窗
- 跨进程通信:
Activity调用requestPermissions(),通过Binder将请求发送给AMS。AMS作为“项目经理”,负责协调权限弹窗的显示。 - 系统弹窗:
AMS会启动一个特殊的Activity——GrantPermissionsActivity。这个Activity运行在独立的系统进程中,负责向用户展示权限请求弹窗。
三、权限状态的存储与安全机制
1. 权限状态持久化
- 权限状态由
PackageManagerService和PermissionManagerService共同管理。 - 权限状态会持久化存储在
/data/system/目录下的 XML 文件中(如packages.xml),确保在设备重启后,权限状态仍然有效。
2. 权限分组与自动授予
- 权限组:Android 将功能相似的权限归入一个权限组(如
LOCATION组包含ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION)。 - 自动授予:当用户授予某个权限组中的一个权限时,系统会自动授予该组中的其他权限。这简化了权限申请流程,避免了频繁弹窗。
四、性能与调试
1. 权限检查开销
checkSelfPermission()涉及一次跨进程的Binder调用,但由于权限状态通常缓存在内存中,其性能开销非常小。
2. 权限请求开销
requestPermissions()会启动一个系统Activity,涉及进程切换和 UI 绘制,会引入明显的延迟。因此,不应在应用启动的关键路径上频繁调用。
3. 调试工具
- 使用
adb shell dumpsys package命令,可以查看特定应用的权限状态。 - 通过
adb shell pm list permissions命令,可以列出设备上的所有权限。
总结:
Android 动态权限申请机制通过 PermissionManagerService 管理权限状态,Binder 实现跨进程通信,GrantPermissionsActivity 负责用户交互。这套机制将权限的控制权从应用转移到用户,从而在保障应用功能的同时,确保了用户的隐私安全。