Android 权限数据涉及的持久化文件

📅 2026/8/5 10:39:20
Android 权限数据涉及的持久化文件
Android 系统的权限数据主要通过以下几个持久化文件进行管理packages.xml保存 APK 安装包的基本信息、组件声明及权限声明。runtime-permissions.xml保存用户对运行时权限的授予状态可通过dumpsys package package_name查看。appops.xml保存 AppOps应用操作权限的控制状态。default-permissions.xml保存系统默认的权限授予规则即“白名单”策略。1. 问题场景假设系统中预置了一个 APK该应用申请了后台定位权限。按照 Android 原生设计此类权限需要用户通过系统设置页面手动开启。但如果希望该预置应用不走原生界面而是通过配置白名单默认授予该权限直接修改default-permissions.xml并推送到系统目录后可能会发现配置并未生效应用的runtime-permission.xml并未更新即使多次重启系统也是如此(解决方式删除runtime-permission.xml 再重启车机即可)。注这里所说的“白名单”是工程上的习惯叫法在 Android 源码中对应的是DefaultPermissionGrantPolicy它描述了系统默认的权限授予策略其中就包括default-permissions.xml等配置文件。2. 权限加载流程要理解为何配置未生效需要先了解 Android 系统启动过程中权限数据的加载顺序。Android 系统启动时system_server进程会按顺序拉起各个核心服务。其中PackageManagerService以下简称 PMS负责包管理与权限控制。其启动流程可参考 Android 系统启动流程 以及frameworks/base/services/core/java/com/android/server/SystemService.java中的时序图下图来自 gccbuaa 的博客2.1 权限文件的生成与加载流程下面我们沿着 PMS 的启动过程追踪权限文件是如何被读取和写入的。2.1.1 SystemConfig 初始化在startBootstrapServices()阶段通过SystemConfig.getInstance()读取系统中预置的配置文件。初始化核心服务其中就包括 PMS。private void startBootstrapServices(NonNull TimingsTraceAndSlog t) { // 读取系统配置包括权限白名单 SystemServerInitThreadPool.submit(SystemConfig::getInstance, TAG_SYSTEM_CONFIG); // 初始化 PackageManagerService mPackageManagerService PackageManagerService.main(mSystemContext, installer, mFactoryTestMode ! FactoryTest.FACTORY_TEST_OFF, mOnlyCore); ... }在startOtherServices()阶段PMS 进入systemReady()状态。mPackageManagerService.systemReady();2.1.2 PackageManagerService 初始化PMS 的主入口public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { ... PackageManagerService m new PackageManagerService(injector, onlyCore, factoryTest); ... }在 PMS 构造函数中public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) { ... // 1. 获取 PermissionManagerService mPermissionManagerService (IPermissionManager) ServiceManager.getService(permissionmgr); // 2. 读取 runtime-permissions.xml如果存在 mFirstBoot !mSettings.readLPw(mInjector.getUserManagerInternal().getUsers( /* excludePartial */ true, /* excludeDying */ false, /* excludePreCreated */ false)); // 3. 扫描系统目录中的 APK scanDirTracedLI(partition.getOverlayFolder(), ...); scanDirTracedLI(frameworkDir, ...); scanDirTracedLI(partition.getPrivAppFolder(), ...); scanDirTracedLI(partition.getAppFolder(), ...); scanDirTracedLI(sAppInstallDir, ...); // 4. 将扫描结果写入持久化文件 mSettings.writeLPr(); ... }关键点说明读取 runtime-permissions.xmlmFirstBoot !mSettings.readLPw(...);这里会判断runtime-permissions.xml是否存在。若存在则直接读取其中的权限状态isPermissionUpgradeNeeded 通过比对 fingerprint 来判断是否需要重新授权若不存在首次启动则走默认初始化流程。扫描 APK 并更新内存状态private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime, PackageParser2 packageParser, ExecutorService executorService) { ... addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags, currentTime, null); ... }commitReconciledScanResultLocked(reconcileResult.get(pkgName), mUserManager.getUserIds()); private void commitPackageSettings(AndroidPackage pkg, ...) { mSettings.insertPackageSettingLPw(pkgSetting, pkg); // 将配置插入内存中的 Settings 对象 }写入持久化文件void writeLPr() { ... writeKernelMappingLPr(); writePackageListLPr(); // 写入 packages.xml writeAllUsersPackageRestrictionsLPr(); writeAllRuntimePermissionsLPr(); // 写入 runtime-permissions.xml ... }重点关注writeAllRuntimePermissionsLPr()void writeAllRuntimePermissionsLPr() { mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId); }这是一个异步写入过程public void writePermissionsForUserAsyncLPr(int userId) { mHandler.sendMessageDelayed(message, writeDelayMillis); }最终由 Handler 处理private final class MyHandler extends Handler { public void handleMessage(Message message) { writePermissionsSync(userId); } }实际写入函数此时写入状态为空壳private void writePermissionsSync(int userId) { // 将内存中的权限状态同步到 runtime-permissions.xml }2.1.3 PermissionManagerService 的默认授权流程在PermissionManagerService.systemReady()中会尝试为系统应用授予默认权限但这个过程是有条件的并非每次启动都会执行。permissionManagerService.this.systemReady(); private void systemReady() { if (判断isPermissionUpgradeNeeded的状态) { mDefaultPermissionGrantPolicy.grantDefaultPermissions(userId); } }grantDefaultPermissions()主要包括public void grantDefaultPermissions(int userId) { grantPermissionsToSysComponentsAndPrivApps(pm, userId); // 给系统组件和特权应用授权 grantDefaultSystemHandlerPermissions(pm, userId); // 给系统处理器授权 grantDefaultPermissionExceptions(pm, userId); // 处理例外规则 }其中grantPermissionsToSysComponentsAndPrivApps()会根据default-permissions.xml中配置的白名单为应用授权。2.2 关键结论Android 重启时并非所有配置都会重新加载。如果系统中已存在runtime-permissions.xml系统会优先读取该文件中的历史授权状态而不会重新根据default-permissions.xml进行默认授权。因此如果你修改了default-permissions.xml并推送到系统目录然后重启设备runtime-permissions.xml中对应的权限配置通常不会发生变化。这正是为什么“白名单”配置看似未生效的根本原因。3. 参考链接【底层机制】【Android】Android 系统的启动流程 - 详解 - gccbuaa - 博客园