包更新、卸载与状态变更
2026/8/9大约 4 分钟PMS 专题Android 14PMS更新卸载
包更新、卸载与状态变更
上一章我们看了数据落位。这一章回答:包更新时旧版本去哪了,卸载、禁用、隐藏分别改变 什么,状态变更如何广播给系统?
更新会替换代码并保留兼容的数据身份;卸载会移除安装状态并按选项清理数据;禁用或隐藏 主要改变当前用户可见的包状态。三者产生的广播、包表变化和恢复方式都不同。
更新、卸载与禁用改变的状态不同
| 常见误解 | 正确理解 |
|---|---|
| 更新就是覆盖原目录 | 更新生成新的 /data/app 目录,旧版本用于回滚,提交后替换 |
| 禁用和卸载一样 | 禁用保留包与数据但停用组件;卸载删除包与数据 |
| 卸载一定清空一切 | 系统卸载默认删除数据,但部分场景(如保留数据升级)有保留策略 |
核心结论
- 更新流程:安装新目录 → 校验 → 切换注册 → 广播 REPLACED;旧目录进入回滚候选。
- 卸载流程:删除包目录与所有用户数据 → 从包表移除 → 广播 PACKAGE_REMOVED。
- 禁用/启用:只改状态位,包与数据保留,广播 PACKAGE_CHANGED。
- 版本降级、签名不一致、数据兼容校验会阻断更新。
- 系统预装包更新为“系统包 + 用户更新”两层,卸载更新可回退系统版本。
状态变更主链
逐步解释:
- 更新:新版本装好后切换注册,用户数据保留,广播替换事件。
- 卸载:删除包与数据,包表移除,广播移除事件。
- 禁用/启用:只改状态位,广播变更事件。
系统包与用户更新
系统预装包(system/priv-app)被用户更新后,PMS 同时记录“系统版本 + 用户更新”两层: 用户更新被卸载时,回退到系统版本而不是完全消失。这就是 pm uninstall 对系统应用常 表现为“恢复出厂版本”的原因。
源码证据
阅读目标:确认更新与卸载的注册入口。
正文指针:PackageManagerService.java deletePackage()/deletePackageVersioned() 与安装期的 REPLACED 处理;PackageInstallerService.java 的卸载会话。
// PackageManagerService.java(伪代码,行号以 r75 为准)
void deletePackage(String packageName, ...) {
// 删除包目录与用户数据,更新包表,发送 PACKAGE_REMOVED
}这段代码证明: 卸载是包表维护 + 文件清理 + 广播的完整动作;更新则是先走安装管线, 提交成功后切换注册并广播 REPLACED。
验证与排障
环境:开发设备或模拟器;以下命令不需要 root。
adb shell pm uninstall -k <包名>
adb shell pm install-existing <包名>
adb shell pm disable-user <包名>
adb shell dumpsys package <包名> | grep -E "enabled|versionName"-k 卸载时保留数据;install-existing 恢复已卸载的系统包;disable-user 禁用; dumpsys package 看版本与 enabled 状态。先确认“版本被替换了没、状态是否 enabled”, 再判断是更新失败、卸载误删还是禁用导致的。
常见误区
- “更新覆盖旧目录”:新目录安装成功后才切换,旧版本保留用于回滚。
- “禁用等于卸载”:禁用不删数据,组件仍存在只是停用。
- “卸载系统应用就永远没了”:系统包支持回退到出厂版本。
- “更新失败不会影响旧版本”:更新失败时旧版本通常仍可用(回滚机制)。
延伸问题
- 版本降级为什么默认被禁止,什么时候允许?
- 卸载保留数据(-k)在什么场景使用?
- A/B 分区与包级更新的关系是什么?
ACTION_PACKAGE_REPLACED与ACTION_MY_PACKAGE_REPLACED有什么区别?
源码入口
| 文件 | 关键位置 | 作用 |
|---|---|---|
PackageManagerService.java | deletePackageVersioned() | 卸载入口 |
PackageInstallerService.java | 卸载会话 | 卸载流程 |
PackageManagerService.java | 更新提交处理 | 切换注册与广播 |
PackageManagerShellCommand.java | pm disable/uninstall | 命令行入口 |
公共路径:frameworks/base/services/core/java/com/android/server/pm/。行号以 r75 检索为准。
需要从错误码反查具体阶段时,见 PMS 排障。