7、PMS(PackageManagerService)与APK安装流程:包管理、权限管理、签名验证
各位好,今天我们来聊聊Android系统里一个绕不开的核心组件——PackageManagerService,简称PMS。说实话,我当年刚接触Android底层时,觉得PMS就是个“装应用的”,没什么大不了。直到有一次在项目中遇到了一个诡异的权限拒绝问题,折腾了两天才发现是PMS的签名校验逻辑没走对。嗯,从那以后,我再也不敢小看它了。
PMS到底在干什么?说白了,它负责三件大事:包管理、权限管理、签名验证。这三件事贯穿了APK从安装到运行的整个生命周期。你想想看,每次你点一个安装包,系统背后要跑多少逻辑?今天我就带你一层层拆开来看。
7.1 PMS的启动与初始化
PMS是在SystemServer进程里启动的。系统启动时,SystemServer会调用PackageManagerService.main()方法。这个方法会创建一个PMS实例,然后开始扫描系统里所有的APK文件。
我个人习惯把PMS的启动分为三个阶段:
- 第一阶段:扫描系统分区——比如
/system/app、/system/priv-app这些目录。这些是系统预装的应用,权限很高。 - 第二阶段:扫描数据分区——也就是
/data/app目录。用户安装的第三方应用都在这里。 - 第三阶段:建立数据结构——把扫描到的所有包信息缓存到内存里,方便后续查询。
这里有个坑,我曾经遇到过:如果某个APK的AndroidManifest.xml格式有问题,PMS在扫描阶段就会直接跳过它。结果就是,应用明明在目录里,但系统就是找不到。嗯,排查起来挺头疼的。
7.2 APK安装流程:从拷贝到注册
APK安装,说白了就是三步:拷贝、解析、注册。我们一步步来看。
7.2.1 拷贝阶段
当用户点击安装时,系统会先把APK文件拷贝到/data/app/目录下。这个目录通常以包名-随机后缀命名,比如com.example.app-1。为什么要加随机后缀?为了防止同名包冲突。我见过有人手动改包名去覆盖安装,结果PMS直接报错——因为签名不一致。
7.2.2 解析阶段
拷贝完成后,PMS会调用PackageParser来解析APK。解析的内容包括:
- AndroidManifest.xml中的四大组件声明
- 权限请求列表
- 签名信息
- 版本号、minSdkVersion等元数据
解析完成后,PMS会生成一个Package对象,里面包含了应用的所有信息。这个对象会被缓存到内存中,同时也会写入/data/system/packages.xml文件里。下次开机时,PMS直接从文件恢复,不用重新解析。
7.2.3 注册阶段
最后一步,PMS会把解析出来的组件信息注册到系统里。比如,如果你声明了一个Activity,PMS会把它添加到ActivityManagerService的组件表中。这样,当系统要启动这个Activity时,才能找到它。
核心要点:APK安装的本质,就是把一个静态的压缩包,变成系统可以动态调用的组件集合。PMS就是那个“翻译官”。
7.3 权限管理:谁可以用什么
权限管理是PMS的另一大职责。Android的权限分为几类:
| 权限类型 | 说明 | 例子 |
|---|---|---|
| 普通权限 | 安装时自动授予,用户无需确认 | INTERNET、ACCESS_NETWORK_STATE |
| 危险权限 | 运行时需要用户手动授权 | CAMERA、READ_CONTACTS |
| 签名权限 | 只有相同签名的应用才能使用 | 系统级API调用 |
| 特权权限 | 只有系统应用才能使用 | INSTALL_PACKAGES |
我建议你在开发时,尽量使用普通权限。危险权限的运行时授权逻辑,处理不好很容易出问题。我曾经见过一个应用,在Android 11上因为权限弹窗被用户拒绝,结果直接崩溃——因为没有做权限检查。
PMS在权限管理中的核心逻辑是:检查调用方的UID和包名,然后比对权限声明。比如,应用A想调用摄像头,PMS会先看应用A有没有在Manifest里声明CAMERA权限,再看用户有没有授权。如果都通过了,才放行。
小技巧:你可以用adb shell dumpsys package命令查看当前系统里所有应用的权限状态。这个命令在调试权限问题时非常有用。
7.4 签名验证:信任的基石
签名验证,说白了就是确保APK没有被篡改。Android使用APK签名方案来验证应用的完整性。目前主流的有三种:
- v1签名(JAR签名)——基于META-INF目录下的签名文件。缺点是只验证单个文件,不验证整个APK。
- v2签名(APK签名方案v2)——在Android 7.0引入。对整个APK文件进行签名,安全性更高。
- v3签名(APK签名方案v3)——在Android 9.0引入。支持密钥轮换,方便应用更新签名。
PMS在安装APK时,会调用PackageManagerService.verifySignatures()方法进行签名验证。验证的逻辑是:
- 读取APK中的签名块
- 用公钥解密签名摘要
- 对比计算出的摘要和解密后的摘要是否一致
- 如果一致,说明APK未被篡改
这里有个重要的点:如果系统里已经安装了同一个包名的应用,新安装的应用签名必须和旧应用一致。否则PMS会直接拒绝安装。这就是为什么你不能用不同的签名去覆盖安装同一个应用。
注意:v1签名有一个安全漏洞——它不验证APK中未签名的文件。攻击者可以往APK里添加恶意文件而不影响签名。所以,从Android 11开始,系统强制要求新安装的应用必须使用v2或v3签名。
7.5 核心流程图
下面我用一张SVG图来展示PMS处理APK安装的核心流程。这张图我画了很多遍,力求简洁清晰。
7.6 避坑指南
最后,我分享几个实际项目中踩过的坑:
- 签名冲突——我曾经在调试时,用debug签名安装了一个应用,后来想用release签名覆盖安装,结果PMS直接报错。解决办法是先卸载旧版本。
- 权限降级——如果新版本的APK移除了某个权限,PMS会自动撤销该权限。但如果你在代码里还依赖这个权限,就会出问题。我建议在移除权限前,先检查代码里有没有用到。
- 多用户场景——在Android多用户模式下,每个用户都有自己的应用列表。PMS会为每个用户维护独立的权限状态。如果你在用户A下安装了应用,切换到用户B时,应用可能不可见。
调试技巧:用adb shell dumpsys package <包名>可以查看某个应用的详细信息,包括权限、签名、安装路径等。这个命令是我排查PMS相关问题的首选工具。
好了,关于PMS和APK安装流程,今天就聊到这里。记住,PMS是Android系统的“大管家”,它管着所有应用的生老病死。理解了它,你就理解了Android应用管理的底层逻辑。
公众号:蓝海资料掘金营,微信deep3321