深入解析 pm grant 命令:权限授予的底层逻辑与实战应用

张开发
2026/4/19 17:02:31 15 分钟阅读

分享文章

深入解析 pm grant 命令:权限授予的底层逻辑与实战应用
1. 揭开pm grant命令的神秘面纱第一次接触pm grant命令时我正为一个系统工具开发项目头疼——明明在模拟器运行正常的权限请求到了真机调试时却频频崩溃。这个看似简单的命令行工具实则是Android权限系统的钥匙保管员。它通过PackageManagerService直接操作系统底层的packages.xml文件绕过了常规的运行时权限弹窗机制。pm grant的典型使用场景是这样的当你需要为调试中的APP临时授予危险权限比如WRITE_SETTINGS或者为系统工具配置签名级权限如CHANGE_CONFIGURATION时这个命令就能大显身手。但要注意它需要满足两个前提条件设备必须已获取root权限且执行者需拥有GRANT_REVOKE_PERMISSIONS系统权限。我在开发车载系统时就曾用它批量配置过多个系统应用的权限组合。2. 权限授予的底层实现机制2.1 从命令行到系统服务的调用链当你在adb shell中输入pm grant com.example.app android.permission.CAMERA时这个指令会经历三层关键转换Pm.java解析阶段runGrantRevokePermission()方法会校验参数格式捕获常见的IllegalArgumentException比如包名不存在和SecurityException权限不足。这里有个细节容易被忽略——方法内部会通过mPm.grantPermission()发起Binder调用这个mPm其实就是PackageManagerService的远程代理。PackageManagerService处理阶段核心逻辑在grantPermission()方法中。我通过源码调试发现它会先检查调用者是否具有GRANT_REVOKE_PERMISSIONS权限这就是为什么普通APP无法调用然后通过双重锁机制保护mPackages和mSettings这两个关键数据结构。特别要注意synchronized (mPackages)这个同步块——它解释了为什么批量授权时会出现性能瓶颈。持久化存储阶段最终权限配置会写入/data/system/packages.xml。这个文件采用XML格式存储所有包的权限状态包括perms标签下的显式授权和shared-user中的共享权限。我曾遇到过因文件损坏导致的权限丢失问题这时候packages-backup.xml这个备份文件就派上用场了。2.2 packages.xml的存储奥秘在逆向分析Android 10的Settings.java时我注意到权限数据存储的几个关键点文件头包含SDK版本信息last-platform-version这解释了为什么某些权限在系统升级后会自动重置每个权限项都关联着gid数组这就是为什么授予READ_LOGS权限后应用会自动加入log用户组writeLPr()方法中的FileUtils.sync()调用保证了断电时数据不会丢失但也导致高频授权操作会产生I/O瓶颈通过strace工具跟踪可以发现每次执行pm grant都会触发完整的文件重写流程。这就是为什么在低端设备上连续执行多个授权命令会有明显延迟。我在为智能手表开发系统时就通过合并多个授权操作为单次写入将权限配置时间从3秒缩短到了800毫秒。3. 实战中的典型应用场景3.1 系统开发调试技巧在开发系统级输入法时我需要频繁测试WRITE_SECURE_SETTINGS权限的效果。手动操作流程应该是# 先检查当前权限状态 adb shell dumpsys package com.example.ime | grep WRITE_SECURE_SETTINGS # 授予权限需要root adb shell su -c pm grant com.example.ime android.permission.WRITE_SECURE_SETTINGS # 验证写入结果 adb shell cat /data/system/packages.xml | grep -A5 com.example.ime这里有个实用技巧通过dumpsys package命令可以验证权限是否真正生效。我遇到过因SELinux策略限制导致授权失败的情况这时候需要同时检查avc日志adb shell su -c dmesg | grep avc3.2 自动化测试中的权限管理在UI自动化测试框架中我设计过这样的权限处理方案def grant_runtime_permissions(device, package_name): # 获取应用需要的所有危险权限 cmd fadb -s {device} shell pm dump {package_name} | grep requested permission: permissions subprocess.check_output(cmd, shellTrue).decode().split(\n) for perm in permissions: if android.permission. in perm: permission perm.split(:)[-1].strip() try: device.shell(fpm grant {package_name} {permission}) except AdbError as e: if not a changeable permission type in str(e): print(fSkipping non-grantable permission: {permission}) else: raise这个方案在跨设备测试时特别有用但要注意三个坑签名权限protectionLevelsignature即使通过pm grant也无法生效某些厂商ROM会修改权限保护级别比如华为设备上的READ_CALL_LOGAndroid 11之后对限制性权限有额外验证4. 安全机制与风险防范4.1 权限保护级别的深层解析Android定义了四种关键的保护级别protectionLevel直接影响pm grant的可行性保护级别示例权限能否通过pm grant授予normalINTERNET是但无意义dangerousCAMERA是signatureBIND_ACCESSIBILITY_SERVICE否signatureOrSystemCHANGE_CONFIGURATION需系统签名在分析CustomLocale.apk案例时我发现CHANGE_CONFIGURATION的复合保护级别signature|system|development产生了有趣的行为在eng版本系统上开发模式签名的APP也能被授权而user版本则严格限制。这通过checkGrantRevokePermissions()方法中的以下代码实现if ((bp.protectionLevel PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) ! 0) { if ((mContext.getApplicationInfo().flags ApplicationInfo.FLAG_DEBUGGABLE) ! 0) { return; // 允许在调试版系统授权 } }4.2 常见错误排查指南在调试权限问题时我总结出这个检查清单基础验证确认设备已root检查命令格式pm grant package permission验证包名是否存在pm list packages | grep package权限验证查看权限定义adb shell dumpsys package permission检查保护级别查找输出中的protectionLevel系统状态检查确认SELinux模式adb shell getenforce检查进程存活状态ps -A | grep package最近遇到的一个典型案例某设备厂商修改了WRITE_SETTINGS的默认授予策略导致即使通过pm grant授权成功实际访问时仍会被拒绝。最终发现是厂商在PackageManagerService中增加了额外的校验逻辑// 某厂商ROM中的额外检查 if (android.permission.WRITE_SETTINGS.equals(permissionName)) { if (!callerPackage.equals(com.android.settings)) { throw new SecurityException(Only Settings can hold this permission); } }这类问题需要通过反编译framework.jar才能定位建议使用jadx-gui工具进行分析。

更多文章