一、引言:为什么你必须搞懂 App 安装流程?
在日常开发中,我们其实频繁“被动依赖”安装机制,但很少主动理解它:
- 插件化 / 热修复为什么绕不开安装流程?
- 为什么有的 APK 安装失败提示
INSTALL_FAILED_*? - 为什么 split APK / 动态特性安装这么复杂?
- 为什么有的文件明明存在,却访问不到?
👉 本质问题是:App 的“存在”并不只是文件拷贝,而是系统级注册 + 权限体系接入 + 运行环境准备
这背后的核心角色就是:PMS(PackageManagerService)
二、背景知识:你需要先知道这些
1. PMS 是什么?
PackageManagerService 是 Android 系统中负责:
- App 安装 / 卸载
- 包信息管理(PackageInfo)
- 权限分配
- 四大组件注册
👉 可以把它理解为:
📦 系统的“应用注册中心 + 包管理数据库”
2. 安装的本质不是 copy
很多人误以为:
安装 = 把 APK 拷贝到
/data/app
但实际上:
✔ 文件落地只是第一步
✔ 更关键的是:
- 解析 AndroidManifest.xml
- 注册组件(Activity / Service)
- 分配 UID
- 权限校验
- 写入系统 Package 数据
3. 安装入口
用户点击安装后,入口通常是:
PackageInstaller.Session.commit()
最终会走到:
PackageManagerService.installPackageLI()
三、核心原理解析:安装流程全景图
我们先用一句话总结:
PMS 安装 App = 校验 → 解析 → 拷贝 → 注册 → 持久化
展开来看:
Step 1:安装请求进入 PMS
来源可能是:
- adb install
- 应用市场
- PackageInstaller
最终都会进入:
PackageManagerService#installPackageTracedLI
Step 2:APK 校验(安全第一)
关键校验包括:
✔ 签名校验
- 新安装:记录签名
- 升级安装:必须签名一致
compareSignatures()
👉 不一致直接:
INSTALL_FAILED_UPDATE_INCOMPATIBLE
✔ 权限校验
- 是否请求了系统权限
- 是否允许安装来源
✔ 完整性校验
- APK 是否损坏
- 文件是否合法
Step 3:解析 APK(最关键一步)
PackageParser.parsePackage()
会解析:
- AndroidManifest.xml
- 四大组件
- 权限声明
- intent-filter
👉 生成核心对象:
PackageParser.Package
💡 类比一下:
APK 就像一份“简历”,PMS 在这里读简历并建立档案
Step 4:dex 优化(编译)
dexopt
作用:
- 将 dex 编译为 oat / odex
- 提升运行速度
Android 版本不同:
- Dalvik:dex → odex
- ART:AOT / JIT 混合
Step 5:安装目录创建 + 文件拷贝
/data/app/<package>/
包括:
- base.apk
- split apk(如果有)
- lib 目录(native so)
Step 6:分配 UID
Settings.getPackageLPw()
系统会为每个 App 分配:
uid = 10000+
👉 这个 UID 是:
- Linux 进程隔离的核心
- 权限隔离的基础
Step 7:注册组件(系统可见)
把解析出来的组件注册到系统:
mActivities
mServices
mReceivers
mProviders
👉 从这一刻开始:
- Activity 才能被启动
- Service 才能被绑定
Step 8:更新系统数据(持久化)
关键文件:
/data/system/packages.xml
保存:
- 包名
- uid
- 权限
- 路径
👉 系统重启后能恢复
Step 9:发送安装完成广播
Intent.ACTION_PACKAGE_ADDED
四、源码关键路径解析
简化调用链:
installPackageTracedLI
→ installPackageLI
→ scanPackageNewLI
→ parsePackage
→ collectCertificates
→ scanPackageDirtyLI
→ register components
→ assign uid
重点函数:
1. parsePackage()
负责:
- Manifest 解析
- 组件抽取
2. scanPackageNewLI()
核心逻辑:
- 注册组件
- 更新 Settings
3. commitPackageSettings()
写入:
packages.xml
五、实战示例:监听 App 安装
我们可以监听安装广播:
class InstallReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val packageName = intent.data?.schemeSpecificPart
if (intent.action == Intent.ACTION_PACKAGE_ADDED) {
println("App installed: $packageName")
}
}
}
注册:
<receiver android:name=".InstallReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<data android:scheme="package"/>
</intent-filter>
</receiver>
场景:自动初始化 SDK
比如:
- 统计 SDK
- 插件加载
可以在安装后触发初始化逻辑
六、常见误区 / 踩坑总结
❌ 误区 1:安装只是拷贝文件
✔ 实际是:
系统级注册行为 + 权限体系接入
❌ 误区 2:APK 解压就能运行
错误!
必须经过:
- PMS 注册
- UID 分配
否则无法启动
❌ 误区 3:签名不重要
错误!
👉 签名决定:
- 是否能升级
- 是否共享 UID
- 权限继承
❌ 误区 4:删除文件就等于卸载
rm -rf /data/app/xxx
👉 会导致:
- 系统记录还在
- 出现“幽灵应用”
七、性能优化 & 最佳实践
1. 使用 Split APK / App Bundle
减少安装体积:
- 按需下载
- 减少 dex 数量
2. 减少 dex 数量
👉 dex 越多:
- dexopt 越慢
- 安装时间越长
3. 避免滥用权限
权限越多:
- PMS 校验越复杂
- 用户信任下降
4. 合理使用 native 库
只保留必要 ABI:
ndk {
abiFilters "arm64-v8a"
}
5. 优化首次安装时间
- 使用 R8 压缩代码
- 避免大资源文件
- 减少 class 数量
八、总结:一句话看懂 PMS 安装
最后帮你提炼一个面试级总结:
PMS 安装 App 的本质,是把一个 APK 从“文件”转化为“系统认可的应用实体”。
核心过程可以记住 5 步:
- 校验(签名 / 权限)
- 解析(Manifest → Package)
- 拷贝(安装目录)
- 注册(组件 + UID)
- 持久化(packages.xml)
最后一句话
如果你把 Android 系统想象成一个“操作系统级容器平台”,那么:
PMS 就是它的“应用调度中心”,而安装流程就是“应用上线流程”。