10、PackageManagerService(PMS):APK解析、权限管理、安装与卸载流程
各位好,今天我们来聊聊Android系统里一个重量级角色——PackageManagerService,简称PMS。说实话,PMS是我在系统开发中打交道最多的服务之一。你每次安装一个App、打开一个应用、甚至只是查看一下应用列表,背后都有PMS在默默工作。
PMS到底负责什么?简单说,它管理着系统中所有APK的“户口本”。谁安装了、谁卸载了、谁有什么权限、谁依赖谁——这些信息全在PMS手里。我习惯把PMS比作Android系统的“物业公司”,它管着每个应用的“入住”和“退租”。
核心职责一句话:PMS负责APK的解析、权限的授予与检查、应用的安装与卸载,以及所有包信息的维护。
10.1 APK解析:PMS是怎么读懂一个APK的?
APK本质上是个压缩包,但PMS要从中提取出大量结构化信息。这个过程我称之为“APK的体检”。
PMS解析APK的核心路径是这样的:
- 读取AndroidManifest.xml——这是APK的“身份证”,所有关键信息都在这里
- 解析四大组件——Activity、Service、BroadcastReceiver、ContentProvider
- 提取权限声明——应用声明了哪些权限,需要哪些权限
- 解析签名信息——验证APK的签名是否合法
- 收集资源与so库——记录APK的资源路径和native库路径
嗯,这里要注意:解析过程是在PackageParser类中完成的。我曾在项目中遇到过一个问题——某个APK的AndroidManifest.xml格式有轻微错误,导致PMS解析失败,整个系统启动卡在“正在优化应用”界面。后来发现是某个标签的属性值多了一个空格。你想想看,一个空格就能让系统起不来,这就是Android的严谨之处。
避坑指南:我曾经在定制ROM时发现,如果APK的AndroidManifest.xml中android:name属性写成了全小写,PMS解析时不会报错,但后续通过PackageManager.getActivityInfo()获取信息时会返回null。所以,组件名称的大小写一定要和代码中一致。
10.2 权限管理:PMS的“门禁系统”
权限管理是PMS最核心的功能之一。说白了,它就是Android系统的“门禁系统”——每个应用想访问敏感资源,都得经过PMS的检查。
权限分为几类:
| 权限类型 | 特点 | 举例 |
|---|---|---|
| 普通权限(Normal) | 安装时自动授予,无需用户确认 | INTERNET、ACCESS_NETWORK_STATE |
| 危险权限(Dangerous) | 运行时需用户授权,可撤销 | CAMERA、ACCESS_FINE_LOCATION |
| 签名权限(Signature) | 只有相同签名的应用才能获取 | 系统级API调用 |
| 特权权限(Privileged) | 系统应用专属,位于/system/priv-app | INSTALL_PACKAGES |
PMS在权限检查时,会走一套完整的流程:
// 权限检查的核心逻辑(简化版)
int checkUidPermission(String permName, int uid) {
// 1. 获取uid对应的包名列表
String[] pkgNames = getPackagesForUid(uid);
// 2. 遍历每个包,检查是否拥有该权限
for (String pkgName : pkgNames) {
PackageSetting ps = mSettings.getPackageSetting(pkgName);
if (ps != null && ps.grantedPermissions.contains(permName)) {
return PackageManager.PERMISSION_GRANTED;
}
}
// 3. 检查是否为系统权限
if (isSystemPermission(permName, uid)) {
return PackageManager.PERMISSION_GRANTED;
}
return PackageManager.PERMISSION_DENIED;
}
我个人习惯把权限检查分为两个阶段:安装时检查和运行时检查。安装时检查主要针对普通权限和签名权限,运行时检查则针对危险权限。Android 6.0之后引入的运行时权限模型,说白了就是把“门禁”的开关从安装时挪到了运行时,让用户有更多控制权。
注意:权限的授予状态存储在/data/system/packages.xml中。如果你在调试时手动修改了这个文件,记得重启SystemServer,否则PMS不会感知到变化。我曾经因为忘记重启,排查了半天权限问题,最后发现是缓存没刷新。
10.3 安装流程:一个APK的“入住手续”
APK安装流程,我把它分为四个阶段:
- 拷贝阶段——将APK文件复制到/data/app/目录下
- 解析阶段——PMS解析APK,提取包信息
- 优化阶段——dex2oat编译,生成odex文件
- 注册阶段——将包信息写入系统数据库,更新组件信息
安装的入口是PackageInstaller,它通过Binder调用PMS的installStage()方法。PMS会创建一个InstallParams对象,然后交给InstallHandler处理。整个过程是异步的,所以安装大应用时不会阻塞系统。
来看看核心代码路径:
// PMS中的安装入口
public void installStage(String packageName, File stagedFile,
String installerPackageName, int installFlags) {
// 创建安装参数
InstallParams params = new InstallParams(stagedFile, installerPackageName,
installFlags, null, null);
// 提交到安装队列
mInstallQueue.add(params);
// 唤醒安装线程
mInstallHandler.sendEmptyMessage(INSTALL_START);
}
我记得有一次,客户反馈说某个应用安装后无法打开。排查后发现是dex2oat优化阶段出了问题——APK中包含了一个超大dex文件,导致编译超时。解决方案是在build.prop中调整了dalvik.vm.dex2oat-timeout参数。嗯,这种问题在低端设备上尤其常见。
关键点:安装过程中,PMS会检查APK的签名是否与已安装版本一致。如果签名不一致,即使包名相同,也会安装失败。这是Android防止应用被恶意替换的重要机制。
10.4 卸载流程:一个APK的“退租手续”
卸载流程相对简单,但同样需要谨慎处理。PMS卸载一个应用时,主要做以下几件事:
- 删除/data/app/下的APK文件
- 删除/data/data/下的应用数据目录
- 从packages.xml中移除包信息
- 通知其他组件(如Launcher)刷新界面
- 清理权限授予记录
卸载的入口是deletePackage()方法。PMS会先检查调用者是否有卸载权限(需要DELETE_PACKAGES权限或系统应用),然后执行卸载操作。
// 卸载核心逻辑(简化版)
public void deletePackage(String packageName, int flags) {
// 1. 检查调用者权限
if (!checkCallingPermission(DELETE_PACKAGES)) {
throw new SecurityException("No permission to delete packages");
}
// 2. 获取包设置信息
PackageSetting ps = mSettings.getPackageSetting(packageName);
if (ps == null) {
return; // 包不存在
}
// 3. 删除应用数据
deleteApplicationData(packageName);
// 4. 删除APK文件
deletePackageFile(ps.codePath);
// 5. 从系统中移除包信息
removePackageFromSettings(packageName);
// 6. 发送广播通知
sendPackageRemovedBroadcast(packageName);
}
这里有个坑:如果应用有persistent属性(即android:persistent="true"),PMS卸载时会特殊处理——先杀掉进程,再删除数据。我曾在项目中遇到过,一个persistent应用卸载后,它的进程还在运行,导致系统认为应用还在,重新安装时报错“已存在”。后来发现是卸载时没有正确清理进程。
个人经验:调试卸载问题时,可以查看/data/system/packages.xml中是否还有残留的包信息。如果手动清理,记得同时删除/data/data/和/data/app/下的对应目录,否则重新安装时会出现签名冲突。
10.5 PMS的知识体系总览
为了让大家更直观地理解PMS的整体架构,我画了一张图:
从这张图可以看出,PMS的四大功能模块都依赖于底层的持久化存储。每次系统启动时,PMS都会从packages.xml中恢复所有包信息。这也是为什么系统启动后,你之前安装的应用都还在——PMS把它们的“户口”都记在文件里了。
好了,关于PMS的APK解析、权限管理、安装与卸载流程,我就讲到这里。这些内容在实际的系统开发中非常实用,尤其是做定制ROM或系统应用开发时,理解PMS的工作原理能帮你少走很多弯路。