PMS 全称是 PackageManagerService ,是 Android 系统中负责应用包管理 的核心系统服务,运行在 SystemServer 进程中。没有它,系统无法知道安装了哪些应用、每个应用有什么组件、需要什么权限。它是 AMS 启动 Activity/Service 时查询目标组件信息的数据源 ,也是权限系统的核心支撑 。
一、 核心职责
职责
说明
APK 安装/卸载/更新
处理 adb install、应用商店安装、系统更新等
包信息解析
解析 AndroidManifest.xml,提取组件、权限、声明
权限管理
检查/授予运行时权限、签名验证
组件查询
提供 queryIntentActivities()、resolveService() 等查询
签名验证
验证 APK 签名一致性,防止篡改
共享库管理
管理共享库(shared libraries)依赖
用户隔离
多用户场景下包的隔离管理
二、 在 SystemServer 中的启动位置
// SystemServer.startBootstrapServices()
mPackageManagerService = PackageManagerService.main(
mSystemContext, installer, domainVerificationService, ...);
PMS 属于 Bootstrap 阶段 启动的服务,因为它被 AMS、WMS 等众多后续服务依赖。
三、与 PackageManager 的关系
对比
PackageManager
PackageManagerService
所在进程
应用进程
SystemServer 进程
实现方式
抽象类,应用侧接口
具体实现,服务端逻辑
通信方式
通过 Binder 调用 PMS
直接操作底层数据
典型方法
getPackageInfo()、getInstalledPackages()
实际执行查询逻辑
应用进程通过 Context.getPackageManager() 获取的是 ApplicationPackageManager,它内部持有 PMS 的 Binder 代理,所有调用最终跨进程到 SystemServer 的 PMS。
四、 PMS 启动流程详解
4.1 构造阶段(PackageManagerService())
// PackageManagerService.java
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
// 1. 创建 HandlerThread(后台扫描线程)
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true);
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
// 2. 创建并加载 Settings(持久化数据)
mSettings = new Settings(...);
mSettings.readLPw(); // 读取 /data/system/packages.xml
// 3. 初始化 Installer(底层安装接口)
mInstaller = new Installer();
// 4. 创建 DexOpt 优化器
mPackageDexOptimizer = new PackageDexOptimizer(this);
// 5. 创建 PackageParser(APK 解析器)
mPackageParser = new PackageParser();
// ... 大量初始化 ...
}
4.2 扫描阶段(scanDirTracedLI())
// 扫描系统目录(按优先级)
scanDirTracedLI(new File("/system/framework"), ...); // 框架
scanDirTracedLI(new File("/system/priv-app"), ...); // 系统特权应用
scanDirTracedLI(new File("/system/app"), ...); // 系统应用
scanDirTracedLI(new File("/vendor/app"), ...); // 厂商应用
scanDirTracedLI(new File("/product/app"), ...); // 产品应用
scanDirTracedLI(new File("/data/app"), ...); // 用户应用
扫描顺序决定覆盖优先级 :后扫描的目录可以覆盖先扫描目录中的同名包(版本更高时)。
五、APK 解析机制(PackageParser)
5.1 解析流程
5.2 解析结果存储
// PackageParser.Package 结构
public final class Package {
public String packageName; // 包名
public String mSharedUserId; // 共享用户ID
public ApplicationInfo applicationInfo;
public final ArrayList<Activity> activities = new ArrayList<>();
public final ArrayList<Activity> receivers = new ArrayList<>();
public final ArrayList<Service> services = new ArrayList<>();
public final ArrayList<Provider> providers = new ArrayList<>();
public final ArrayList<Permission> permissions = new ArrayList<>();
public final ArrayList<Instrumentation> instrumentation = new ArrayList<>();
// ...
}
六、Settings 与持久化存储
6.1 持久化文件
文件路径
作用
/data/system/packages.xml
所有已安装包的信息、权限授予状态
/data/system/packages-backup.xml
packages.xml 备份
/data/system/packages.list
包名到 UID/GID 的映射列表
/data/system/users/
每个用户的包状态(是否启用、是否停止)
6.2 packages.xml 结构
<?xml version='1.0' encoding='utf-8'?>
<packages>
<!-- 包信息 -->
<package name="com.example.app"
codePath="/data/app/com.example.app-1"
nativeLibraryPath="/data/app/..."
primaryCpuAbi="arm64-v8a"
publicFlags="..."
privateFlags="..."
ft="..."
it="..."
ut="..."
version="100"
userId="10123">
<!-- 签名信息 -->
<sigs count="1">
<cert index="1" />
</sigs>
<!-- 权限授予 -->
<perms>
<item name="android.permission.CAMERA" granted="true" flags="0" />
<item name="android.permission.INTERNET" granted="true" flags="0" />
</perms>
<!-- 组件状态 -->
<proper-signing-keyset identifier="1" />
</package>
<!-- 共享用户 -->
<shared-user name="android.uid.system" userId="1000">
<sigs count="1">
<cert index="1" />
</sigs>
</shared-user>
</packages>
6.3 Settings 类核心结构
// Settings.java
final class Settings {
// 所有已安装包
private final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();
// 共享用户设置
private final ArrayMap<String, SharedUserSetting> mSharedUsers = new ArrayMap<>();
// 签名到索引的映射(去重存储)
private final ArrayMap<Signature, Integer> mSignatures = new ArrayMap<>();
// 权限基线(权限定义)
private final ArrayMap<String, BasePermission> mPermissions = new ArrayMap<>();
// 写入持久化
void writeLPr() { ... } // 写入 packages.xml
void readLPw() { ... } // 读取 packages.xml
}
七、权限管理机制
7.1 权限类型
类型
说明
示例
Normal
安装时自动授予,无需用户确认
INTERNET、ACCESS_NETWORK_STATE
Dangerous
运行时动态申请,需用户授权
CAMERA、LOCATION、READ_CONTACTS
Signature
仅与定义者同签名的应用可获取
BIND_WALLPAPER
Privileged
仅系统特权应用(priv-app)可获取
WRITE_SECURE_SETTINGS
Internal
仅系统应用可获取
INTERACT_ACROSS_USERS
7.2 运行时权限申请流程
7.3 权限授予源码
// PackageManagerService.java
@Override
public void grantRuntimePermission(String packageName, String permissionName, int userId) {
synchronized (mPackages) {
// 1. 获取包设置
PackageParser.Package pkg = mPackages.get(packageName);
BasePermission bp = mSettings.mPermissions.get(permissionName);
// 2. 检查权限是否可授予
if (!bp.isRuntime()) {
throw new SecurityException("Not a runtime permission");
}
// 3. 获取权限设置
PermissionsState permissionsState = pkg.mExtras.permissionsState;
// 4. 授予权限
int result = permissionsState.grantRuntimePermission(bp, userId);
// 5. 持久化
mSettings.writeLPr();
// 6. 发送广播通知
mHandler.post(() -> {
sendPackageChangedBroadcast(packageName, ...);
});
}
}
八、签名验证机制
8.1 签名验证时机
时机
验证内容
安装时
验证 APK 签名完整性
更新时
验证新旧 APK 签名一致
共享 UID
验证同 UID 的所有包签名一致
权限声明
验证权限定义者的签名
8.2 签名存储优化
PMS 使用 签名索引去重 来节省内存:
// 多个包可能使用相同签名(如同一开发者)
// PMS 只存储一份签名对象,通过索引引用
// 首次遇到签名:
mSignatures.put(signature, index=1); // 存储实际签名
// 后续相同签名:
// 只存储索引引用,不重复存储签名对象
九、DexOpt 与 ART 优化
9.1 优化类型
类型
说明
存储位置
dexopt
Dalvik 时代的优化(odex)
/data/dalvik-cache/
dex2oat
ART 时代的 AOT 编译(oat)
/data/app/.../oat/
vdex
验证后的 dex(Android 8+)
/data/app/.../oat/
cdex
压缩 dex(Android 10+)
/data/app/.../oat/
9.2 优化触发时机
// PackageDexOptimizer.java
int performDexOpt(PackageParser.Package pkg, ...) {
// 1. 检查是否需要优化(首次安装、系统更新、ART 升级)
if (!needsDexOpt(pkg)) return DEX_OPT_SKIPPED;
// 2. 调用 dex2oat 进行 AOT 编译
// dex2oat --dex-file=app.apk --oat-file=app.odex
// 3. 更新优化状态
pkg.setDexOptPerformed(...);
return DEX_OPT_PERFORMED;
}
十、多用户支持
10.1 用户隔离机制
// UserManagerService + PMS 协同
// 每个用户独立的数据目录
/data/user/0/com.example.app/ // 用户0(主用户)
/data/user/10/com.example.app/ // 用户10(工作资料)
// PMS 为每个用户维护独立的包状态
class PackageSetting {
// 每个用户的包状态
int[] enabledState; // 是否启用
int[] stoppedState; // 是否强制停止
boolean[] hidden; // 是否隐藏
}
10.2 应用克隆/双开
部分 OEM 系统利用多用户机制实现应用双开 :
创建独立用户空间(如 User 999)
在该用户空间安装相同 APK
两个用户空间的包数据完全隔离
十一、PackageInstaller 与 Session 安装
11.1 现代安装流程(Android 7+)
11.2 Session 安装的优势
传统安装
Session 安装
一次性写入完整 APK
支持流式写入(分片传输)
安装失败需清理残留
原子提交,失败自动回滚
不支持多 APK(split)
原生支持 base + split APK
无进度反馈
支持安装进度回调
十二、PMS 与 AMS 的交互
12.1 组件启动时的查询
12.2 应用进程创建时的包信息传递
// AMS 创建进程时,通过 PMS 获取包信息
ApplicationInfo appInfo = PMS.getApplicationInfo(packageName, 0, userId);
// 将 ApplicationInfo 传递给 Zygote fork 出的新进程
ProcessRecord app = new ProcessRecord(..., appInfo, ...);
十三、PMS 的性能优化
13.1 启动优化
优化手段
说明
并行扫描
多线程并行扫描不同目录
缓存机制
解析结果缓存,避免重复解析
增量更新
仅扫描变更的 APK
后台 dexopt
首次启动后后台执行 AOT 编译
13.2 内存优化
// 使用 ArrayMap 替代 HashMap(Android 专用优化)
private final ArrayMap<String, PackageParser.Package> mPackages;
// 签名去重存储
private final ArrayMap<Signature, Integer> mSignatures;
// 组件信息延迟加载
// 非系统应用的部分组件信息按需加载
十四、关键问题排查
14.1 常见日志
# 查看 PMS 相关日志
adb logcat -s PackageManager:D PackageManagerService:D
# 查看 packages.xml
adb shell cat /data/system/packages.xml | grep "your.package.name"
# 查看应用权限
adb shell dumpsys package your.package.name
14.2 常见问题
问题
原因
排查方向
安装失败 INSTALL_FAILED_UPDATE_INCOMPATIBLE
签名不一致
检查 debug/release 签名
安装失败 INSTALL_FAILED_SHARED_USER_INCOMPATIBLE
sharedUserId 签名不匹配
检查 AndroidManifest
权限未生效
权限组变更或用户拒绝
检查 packages.xml 权限状态
组件找不到
组件未声明或 exported=false
检查 AndroidManifest.xml
十五、总结