1. 课程导入
在 Android 系统中,PackageManager 是应用生态的“户籍与准入中枢”。它负责 APK 的解析、安装、卸载、更新、权限授予、组件可见性、包信息查询以及多用户隔离等关键职责。对于系统定制开发者而言,理解 PackageManager 不只是会调用 getPackageInfo(),而是要能沿着“请求入口—服务端决策—磁盘落盘—系统状态同步”的链路,定位并修改定制点。本课程面向 ROM 定制、系统应用开发、安全加固与自动化测试工程师,目标是让你具备从 Framework 到 Native、从配置到代码的完整定制能力。
学习目标:完成本课程后,你应能独立完成以下任务:
- 读懂 PackageManager 的 Binder 接口与 AIDL 定义,区分 API 调用与系统内部调用路径。
- 掌握 PackageManagerService 的启动流程、扫描策略与包解析核心类。
- 能定制安装白名单、签名校验、权限默认授予、组件暴露策略与包可见性规则。
- 能通过日志、dumpsys、strace 与自定义埋点排查安装失败、扫描超时与权限异常。
- 能设计可回滚、可验证、符合 CTS/GTS 约束的系统定制方案。
核心概念:从“包”到“服务”的四层抽象
PackageManager 的定制难点在于它横跨四个抽象层。第一层是包描述层,以 AndroidManifest.xml 和 PackageParser 为核心,决定一个 APK 被解析成怎样的 Package 对象。第二层是服务接口层,即 IPackageManager.aidl 与 PackageManagerService,负责跨进程调用与权限检查。第三层是持久化层,包括 /data/system/packages.xml、packages.list、runtime-permissions.xml 等文件,决定重启后状态是否保留。第四层是策略与配置层,如 config.xml、sysconfig 目录、default-permissions 与 privapp-permissions,是系统定制最常改动的入口。
很多初学者把 PackageManager 等同于“安装器”,这是第一个认知误区。安装只是它的一条子路径,真正影响系统行为的是扫描、解析、权限与可见性策略。第二个误区是只改 Java 层而忽略 SELinux 与文件权限,导致定制在 userdebug 上通过、在 user 版本上失败。第三个误区是直接修改 packages.xml,这会在下次启动时被重新生成覆盖,正确做法是修改扫描逻辑或配置源。
方法流程:一次定制从需求到落地的标准路径
系统定制最怕“改完不知道影响面”。建议采用五步法:需求拆解 → 定位层级 → 最小改动 → 编译验证 → 回归复盘。例如需求是“禁止安装非白名单应用”,先判断它属于策略配置层还是服务接口层;若只是预置白名单,优先改 config.xml 或 sysconfig;若需动态拦截,则改 PackageManagerService.installPackageLI() 或 PackageInstaller 校验逻辑。最小改动意味着不破坏原有 AIDL 接口,避免影响 GMS 与三方应用兼容性。
# 典型验证命令
adb shell dumpsys package com.example.app | grep -E "versionName|userId|granted"
adb shell pm list packages -f | grep example
adb logcat -s PackageManager:I PackageInstaller:I *:S
adb shell cat /data/system/packages.xml | grep -A3 "com.example.app"
案例场景:预置应用默认授予权限
某定制项目要求预置的行业应用开机即拥有定位与存储权限,且用户不可撤销。实现路径是:在 /system/etc/default-permissions/default-permissions.xml 中声明包名与权限,并在 PackageManagerService 的 grantDefaultPermissions() 阶段生效。注意该文件只在首次启动或权限重置时读取,若设备已启动过,需要清除 runtime-permissions.xml 或恢复出厂设置验证。若权限属于 signature|privileged 级别,还需在 privapp-permissions 中显式声明,否则会触发 PrivilegedPermissionDenied 异常。
高风险提醒:直接修改 packages.xml 或 runtime-permissions.xml 属于临时手段,系统重启后可能被覆盖;在 user 版本上还会因 dm-verity 与 SELinux 导致无法开机。所有持久化定制必须落到代码或只读配置分区。
误区复盘与检查清单
| 常见误区 | 后果 | 正确做法 |
|---|---|---|
| 只改 Java 层,忽略 SELinux | user 版本安装失败或服务崩溃 | 同步补充 file_contexts 与 te 规则 |
在 onCreate 中做耗时扫描 | 系统启动超时、Watchdog 重启 | 使用异步扫描或增量扫描策略 |
| 硬编码包名与路径 | 多项目复用困难、易漏改 | 通过 config.xml 或 sysconfig 配置化 |
| 忽略多用户与隔离存储 | 副用户下权限异常 | 按 userId 维度验证并处理 UserManager 切换 |
| 未回归 CTS/GTS | 认证失败、无法过 GMS | 定制后执行 cts-tradefed 相关包 |
本课程后续将沿着这张路线图逐层展开:先建立包解析与扫描的底层认知,再进入安装、权限、可见性与多用户的定制实战,最后以性能优化与自动化验证收束。建议你在学习每节时,同步在 AOSP 源码中定位对应类与方法,并用 dumpsys 与日志验证自己的理解,这样才能把“知道”变成“能改、敢改、改得稳”。