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.javapublicPackageManagerService(Injectorinjector,booleanonlyCore,booleanfactoryTest){// 1. 创建 HandlerThread(后台扫描线程)mHandlerThread=newServiceThread(TAG,Process.THREAD_PRIORITY_BACKGROUND,true);mHandlerThread.start();mHandler=newPackageHandler(mHandlerThread.getLooper());// 2. 创建并加载 Settings(持久化数据)mSettings=newSettings(...);mSettings.readLPw();// 读取 /data/system/packages.xml// 3. 初始化 Installer(底层安装接口)mInstaller=newInstaller();// 4. 创建 DexOpt 优化器mPackageDexOptimizer=newPackageDexOptimizer(this);// 5. 创建 PackageParser(APK 解析器)mPackageParser=newPackageParser();// ... 大量初始化 ...}
4.2 扫描阶段(scanDirTracedLI())
// 扫描系统目录(按优先级)scanDirTracedLI(newFile("/system/framework"),...);// 框架scanDirTracedLI(newFile("/system/priv-app"),...);// 系统特权应用scanDirTracedLI(newFile("/system/app"),...);// 系统应用scanDirTracedLI(newFile("/vendor/app"),...);// 厂商应用scanDirTracedLI(newFile("/product/app"),...);// 产品应用scanDirTracedLI(newFile("/data/app"),...);// 用户应用
扫描顺序决定覆盖优先级:后扫描的目录可以覆盖先扫描目录中的同名包(版本更高时)。
五、APK 解析机制(PackageParser)
5.1 解析流程
![]()
5.2 解析结果存储
// PackageParser.Package 结构publicfinalclassPackage{publicStringpackageName;// 包名publicStringmSharedUserId;// 共享用户IDpublicApplicationInfoapplicationInfo;publicfinalArrayList<Activity>activities=newArrayList<>();publicfinalArrayList<Activity>receivers=newArrayList<>();publicfinalArrayList<Service>services=newArrayList<>();publicfinalArrayList<Provider>providers=newArrayList<>();publicfinalArrayList<Permission>permissions=newArrayList<>();publicfinalArrayList<Instrumentation>instrumentation=newArrayList<>();// ...}
六、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><!-- 包信息 --><packagename="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"><!-- 签名信息 --><sigscount="1"><certindex="1"/></sigs><!-- 权限授予 --><perms><itemname="android.permission.CAMERA"granted="true"flags="0"/><itemname="android.permission.INTERNET"granted="true"flags="0"/></perms><!-- 组件状态 --><proper-signing-keysetidentifier="1"/></package><!-- 共享用户 --><shared-username="android.uid.system"userId="1000"><sigscount="1"><certindex="1"/></sigs></shared-user></packages>
6.3 Settings 类核心结构
// Settings.javafinalclassSettings{// 所有已安装包privatefinalArrayMap<String,PackageSetting>mPackages=newArrayMap<>();// 共享用户设置privatefinalArrayMap<String,SharedUserSetting>mSharedUsers=newArrayMap<>();// 签名到索引的映射(去重存储)privatefinalArrayMap<Signature,Integer>mSignatures=newArrayMap<>();// 权限基线(权限定义)privatefinalArrayMap<String,BasePermission>mPermissions=newArrayMap<>();// 写入持久化voidwriteLPr(){...}// 写入 packages.xmlvoidreadLPw(){...}// 读取 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@OverridepublicvoidgrantRuntimePermission(StringpackageName,StringpermissionName,intuserId){synchronized(mPackages){// 1. 获取包设置PackageParser.Packagepkg=mPackages.get(packageName);BasePermissionbp=mSettings.mPermissions.get(permissionName);// 2. 检查权限是否可授予if(!bp.isRuntime()){thrownewSecurityException("Not a runtime permission");}// 3. 获取权限设置PermissionsStatepermissionsState=pkg.mExtras.permissionsState;// 4. 授予权限intresult=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.javaintperformDexOpt(PackageParser.Packagepkg,...){// 1. 检查是否需要优化(首次安装、系统更新、ART 升级)if(!needsDexOpt(pkg))returnDEX_OPT_SKIPPED;// 2. 调用 dex2oat 进行 AOT 编译// dex2oat --dex-file=app.apk --oat-file=app.odex// 3. 更新优化状态pkg.setDexOptPerformed(...);returnDEX_OPT_PERFORMED;}
十、多用户支持
10.1 用户隔离机制
// UserManagerService + PMS 协同// 每个用户独立的数据目录/data/user/0/com.example.app/// 用户0(主用户)/data/user/10/com.example.app/// 用户10(工作资料)// PMS 为每个用户维护独立的包状态classPackageSetting{// 每个用户的包状态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 获取包信息ApplicationInfoappInfo=PMS.getApplicationInfo(packageName,0,userId);// 将 ApplicationInfo 传递给 Zygote fork 出的新进程ProcessRecordapp=newProcessRecord(...,appInfo,...);
十三、PMS 的性能优化
13.1 启动优化
| 优化手段 | 说明 |
|---|
| 并行扫描 | 多线程并行扫描不同目录 |
| 缓存机制 | 解析结果缓存,避免重复解析 |
| 增量更新 | 仅扫描变更的 APK |
| 后台 dexopt | 首次启动后后台执行 AOT 编译 |
13.2 内存优化
// 使用 ArrayMap 替代 HashMap(Android 专用优化)privatefinalArrayMap<String,PackageParser.Package>mPackages;// 签名去重存储privatefinalArrayMap<Signature,Integer>mSignatures;// 组件信息延迟加载// 非系统应用的部分组件信息按需加载
十四、关键问题排查
14.1 常见日志
# 查看 PMS 相关日志adb logcat-sPackageManager:D PackageManagerService:D# 查看 packages.xmladb shellcat/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 |
十五、总结
![]()