Android随笔-PMS

📅 2026/7/9 3:21:27 👁️ 阅读次数 📝 编程学习
Android随笔-PMS

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 的关系

对比PackageManagerPackageManagerService
所在进程应用进程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.xmlpackages.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安装时自动授予,无需用户确认INTERNETACCESS_NETWORK_STATE
Dangerous运行时动态申请,需用户授权CAMERALOCATIONREAD_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 优化类型

类型说明存储位置
dexoptDalvik 时代的优化(odex)/data/dalvik-cache/
dex2oatART 时代的 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_INCOMPATIBLEsharedUserId 签名不匹配检查 AndroidManifest
权限未生效权限组变更或用户拒绝检查packages.xml权限状态
组件找不到组件未声明或 exported=false检查AndroidManifest.xml

十五、总结