Skip to content

08 PackageManagerService:安装、扫描与权限的档案馆 ​

本页导读:一台 Android 上「装了什么、谁能装、装完能干什么」的终极答案都归档在 PackageManagerService(PMS)。本页从 APK 物理结构讲到扫描解析链、四大组件注册、运行时权限、安装会话(PackageInstaller)、dexopt 与 RRO overlay 机制。它是第 06 页所有组件调度的前置档案馆,也是 Android 11 之后被 Mainline 动刀最多的服务之一(第 12 页)。基线 Android 16(API 36)。


一、APK 解剖:PMS 眼里的包裹 ​

部件内容PMS 关注点
AndroidManifest.xml(二进制 AXML)组件、权限、feature、split 信息解析的核心,产出 AndroidPackage
classes*.dex字节码dexopt 对象(第七节)
resources.arsc资源表资源 id 与配置解析
lib/<abi>/*.sonative 库ABI 匹配、安装解压策略
META-INF / 签名块v1/v2/v3/v4 签名身份与完整性校验
split APK(config/feature/locale)动态交付切片以 splitName 归组安装
assets/、根目录文件业务资源PMS 不解释

签名版本速记:v1 是 JAR 签名(只护 entry 清单),v2/v3 护整个文件(APK Signing Block;v3 加密钥轮换),v4 是 Merkle 树支撑流式/增量安装(Android 11+)。验签失败在安装阶段直接拒,报 INSTALL_PARSE_FAILED_NO_CERTIFICATES 类错误码。

格式小知识:Manifest 进包时已被编译成 AXML 二进制(零字符串表开销、mmap 友好),PMS 解析走 Resources.parseXml 一族;resources.arsc 同理是二进制资源表——这就是为什么「反编译看 Manifest」永远比运行时解析慢,也解释了 PMS 解析吞吐为何能扛住数百包扫描。

二、扫描:开机时 PMS 在读什么 ​

java
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java(示意骨架)
// 构造期:读 /data/system 下的持久化状态 → 比对分区包集合 → 需要时重扫描
// Android 11+ 解析链:ParsedPackageUtils/ParsingPackageUtils 产出 ParsedPackage
// 状态落盘:/data/system/packages.xml(及包列表缓存;文件集与格式以 AOSP 当前版本为准)

要点:

  • 扫描对象:/system(/system_ext,/product,/vendor...) 预置分区、/apex(APEX 内清单,第 12 页)、/data/app 用户安装;
  • 首开全扫、后续开机读缓存快照(这也是首开慢的一大项,呼应第 01 页);
  • 安装/卸载/替换会触发增量扫描:解析目标 APK 更新内存档案 + 重写状态文件;
  • 解析产物是 AndroidPackage(实现类 ParsedPackage),它替代了老 PackageParser.Package,为 Mainline 化提供稳定中间表示(API 30 起解析链重写)。

扫描的工程细节还有两处:

  • APEX 目录同样在扫描范围内,但模块内 APK 走 ApexManager 专线注册(第 12 页),不进普通安装会话;
  • 多用户语义:包「安装」是设备级,「启用/停用/可见」按用户位图管理——pm disable-user 与卸载的区别正在这里,状态文件里每个用户有自己的启用记录。

三、四大组件注册与 Intent 解析 ​

Manifest 解析出的 Activity/Service/Provider/Receiver 条目进 ComponentResolver(IntentResolver 家族),运行时按三类信息匹配:action + category + data(mimeType/scheme) 与权限门。

  • queryIntentActivities 这类查询走的是同一套解析器,Android 11(API 30)引入包可见性:默认只能「看见」声明了 <queries>/有交互关系的包,QUERY_ALL_PACKAGES 需理由——第 06 页的解析从此带上隐私滤镜;
  • 组件级安全在解析处生效:exported(Android 12 起 targetSdk31 组件必须显式声明)、permission 属性、enforcePermission;
  • persistent 包、default home/IME 等「钦定包」由 PMS 特殊标记,影响第 06 页进程档次与开机编排。

Intent 匹配的内部次序值得了解:先按 action 建索引粗筛,再 category 全含校验(默认自动加 CATEGORY_DEFAULT),然后 data 做 scheme/mimeType 精确匹配与通配展开(mimeType 的 image/* 展开在解析注册时就完成),最后按优先级/顺序/历史统计排序。dumpsys package r -a <ACTION> 可以直接问解析器「谁能接这个 Intent」。

四、权限体系:三层漏斗 ​

PMS(配合 PermissionManagerService,API 30 起独立为 Mainline 服务)按三条时间线发权限:

  1. 安装期:普通权限装即得;系统类权限看平台签名/privileged 分区与 privapp-permissions allowlist(/system/etc/permissions/*.xml、OEM allowlist);
  2. 运行期:runtime 权限弹窗(RequestPermissionsActivity,归属 permission controller Mainline 模块),授予状态按 uid 记录(Android 14 起部分授予语义 ACCESS_FINE|COARSE 三态);
  3. 动作期:AppOpsService 再管一层「权限允许但行为要记帐」(定位后台模式、剪贴板读取、相册部分访问)。

补充三个工程级细节:一次性授权与「拒绝两次再拒」逻辑是 API 30 起;自动重置未使用权限(API 30+)会清运行时授权;权限组语义在 API 30 后被拆薄,UI 与授权粒度对齐到「权限」本身。

三件顺手工具:pm grant/revoke <pkg> <perm> 调试期直改授权;appops set 与 dumpsys appops 看动作层记帐;dumpsys package 里同一权限会同时出现 granted 位与 appops 模式,两层不一致时行为以 appops 为准——「授权了却拿不到定位」多半卡在动作层。

五、安装会话:PackageInstaller 的流水线 ​

text
应用/商店/adb(adb install 也是走这套)
  → PackageInstaller.createSession(或 openSession)
  → 写入 apk/split(stage,可流式/增量,v4 签名支持逐块校验)
  → commit → PackageInstallerService 校验链:
      验签 → 解析(第二节链)→ 版本/降级/签名一致性 → 磁盘配额
    → 安装决策(是否 staged:OTA/APEX 场景延后生效)
  → 提交事务(VoldStageQueueService 与 installd 协同):
      落 /data/app、写 /data/system 状态、DexOptManager 排队 dexopt
  → 回调会话状态;完成后广播 PACKAGE_ADDED/REPLACED
  • 「install-flinger」是早期昵称,现对应 PackageInstallerService(services/core/java/com/android/server/pm/PackageInstallerService.java)+ 会话状态机;
  • staged session 同时是 APEX 升级通道(第 12 页),update_engine 把 payload 交给它暂存;
  • 卸载可带 DELETE_KEEP_DATA;「替换安装失败回滚」由会话事务保证,adb install -r 就是 replace 语义。

会话的三个入口也要分清:adb install 走 PackageInstaller 会话(脚本化友好);pm install-create-session 是裸会话原语;cmd package install-existing 直接对已落盘 APK 发起安装事务(root/系统应用工具用)。自动化测试优先用官方 PackageInstaller API,行为最接近用户安装。

顺带记住磁盘账:安装需要 /data 余量(预留阈值随版本有变,AOSP 为准),INSTALL_FAILED_INSUFFICIENT_STORAGE 时先 df /data 再怀疑包本身。

六、dexopt:装完为什么要「优化中」 ​

安装事务里 ART 编译任务被排入 DexOptHelper/后台 Job:

  • 分级:verify(只校验)、speed-profile(AOT 热点,出厂预装默认)、speed(全量 AOT,安装时常见)、optimize 依赖 profile 指导;
  • 执行者是 BackgroundDexOptService/install-time dexopt(Android 10 起安装期同步 dexopt 有预算上限,防止「装 200 个应用」卡死开机,以 AOSP 为准);
  • 编译器随 ART 在 Mainline APEX 里(第 12 页):dex2oat 产物在 /data/oat、/data/dalvik-cache;profile 文件在 /data/misc/profiles(ART 按运行热度持续回填,形成「越用越顺」的闭环);
  • 查看:adb shell dumpsys package dexopt 按包列出编译状态与 reason;reason 字段是「它为什么被编译」的审计线索(安装/升级/背景 profile 收集/bg-dexopt 周期任务)。

七、RRO overlay:不改目标包的资源换皮 ​

Runtime Resource Overlay 允许在不改目标 APK、不重签名的前提下覆盖资源:

  • overlay APK 声明 RRO targetPackage/targetId + <overlay priority>,放在 /product/overlay、/vendor/overlay 等扫描路径;
  • OverlayManagerService 维护启用集合,资源查找时按优先级链合成进目标包的 Resource 路径(对应用透明);
  • 典型用户:OEM 主题/品牌定制、AOSP 组件配置覆盖(framework-res 换配置);应用开发者拿不到启用权,这是平台/OEM 机制;
  • 与「动态加载外部 APK 资源(AssetManager.addAssetPath 黑魔法)」的区别:RRO 是受控、可审计、按用户/配置生效的正规军。

生命周期一句话:开机扫描 overlay 目录→注册进 OverlayManagerService→按启用策略(含用户设置 Settings.Secure.overlay_devices 类键,具体以 AOSP 为准)合成进目标包的资源路径链;换肤/主题应用本质是在请求系统替你启用一组 RRO。

八、实战:dumpsys package 的三段式用法 ​

bash
adb shell dumpsys package com.xxx.yyy        # 档案全量:版本/权限/组件/split/签名
adb shell dumpsys package r                  # 按 Intent 正则试解析(r = resolver)
adb shell dumpsys package dexopt             # 编译状态
adb shell pm list packages -f -3             # 第三方包列表(pm 子命令以 AOSP 为准)

三段式之外,-3 看第三方、-s 看系统、-d 看被禁用,组合 pm 的 list 子命令基本覆盖日常盘点。

排障对照:

症状高概率原因线索
INSTALL_FAILED_UPDATE_INCOMPATIBLE签名不一致(换 keystore)dumpsys package 的 signatures 段比对
INSTALL_FAILED_VERSION_DOWNGRADEversionCode 回退同上
装成功但组件 404split 未安装/可见性过滤pm path、<queries>
权限弹窗不出现未声明/被 allowlist 拒/组策略dumpsys package 的 granted/runtime 段
「解析软件包时发生错误」minSdk/ABI/签名块/增量依赖缺失PackageInstaller 错误码与 logcat
卸载后数据残留DELETE_KEEP_DATA 语义/data/data 目录 + pm install -r 语义

最后一个高频坑:adb install 成功但应用行为像旧版——多用户/工作资料下安装只作用于当前用户可见性,或 split APK 只推了 base;pm path 数一下 split 条数即可定案。

九、模块化时代的 PMS 版图 ​

Android 11 起 PMS 不是一座堡垒而是一片城区:

能力现居处模块形态
解析与包存储设置pkg 方向模块(AOSP 推进中,边界以其为准)APEX / jar
权限与 AppOpsPermissionManagerServiceMainline(permission 模块)
权限请求 UIPermission ControllerMainline 应用
角色与默认应用RoleManagerMainline(role 模块)
安装会话仍在 PMS(system_server)平台内

读 PMS 代码的现实提醒:同一功能可能「平台里留了壳、逻辑在模块里」,dumpsys package 与 dumpsys permission 要对着看;OEM 定制若只改平台壳不更模块,会出现版本错配类疑难杂症(第 12 页 VINTF 同族问题)。

十、命令行小抄 ​

bash
pm path <pkg>              # APK 落盘路径(split 会列多条)
pm dump <pkg> | head       # 等价 dumpsys package 前段
pm compile <pkg> speed     # 手动触发指定编译模式(以 am/cmd package 实现为准)
pm verify <session-id>     # 会话预校验(不提交)
pm install-create-session  # 裸会话原语,脚本化安装第一步
cmd overlay list           # RRO 启用清单(OEM 设备常有裁剪)
cmd appops get <pkg>       # 动作层记帐快照

以上子命令在不同 AOSP 版本间有增删,遇到 Unknown command 先查 pm 的帮助输出(pm 无参运行会打印支持列表)。

十一、版本注记 ​

  • Android 6(API 23):运行时权限登场,PMS 开始「分阶段发权」。
  • Android 5(API 21):ART 取代 Dalvik,dexopt 语义换代,为后来的 profile 编译体系奠基。
  • Android 8~9(API 26~28):v2/v3 签名;REQUEST_INSTALL_PACKAGES 收紧;安装未知来源改为「按来源 App 授权」。
  • Android 10(API 29):安装期 dexopt 预算;staged session 承接 APEX。
  • Android 11(API 30):解析链重写(ParsedPackage)、包可见性、一次性/自动重置权限、PermissionManagerService 入 Mainline、增量安装落地。
  • Android 12~14(API 31~34):exported 显式强制、部分授予、权限 UI 大改;PackageManager 查询 API 继续向可见性倾斜。
  • Android 15~16(API 35~36):包状态存储继续向 pkg Mainline 模块迁移(com.android.pkg 方向,模块边界以 AOSP 为准);APK v4 与流式安装进一步常态化。

本页小结 ​

本页小结:PMS 的四件事可以背下来——扫(分区与 data 的档案化)、解(Manifest 到组件表)、发(三层权限漏斗)、装(会话化事务 + dexopt)。RRO 是平台换皮的正道,不是应用的黑魔法。装不上的问题看错误码与验签,跑不起来的问题回到第 06 页的解析与可见性;权限“给了却不通”再下探 appops。

参考 ​

  • 运行时权限指南:developer.android.com/training/permissions/request-permissions
  • PackageManager 参考:developer.android.com/reference/android/content/pm/PackageManager
  • PackageManagerService 源码:cs.android.com/android/platform/frameworks/base/+/main/services/core/java/com/android/server/pm/PackageManagerService.java
  • 包可见性说明:developer.android.com/guide/packages/package-visibility
  • 应用签名官方说明:developer.android.com/studio/publish/app-signing

基于 Android 16 / API 36 · 内容为原创整理,转载请注明出处