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,这会在下次启动时被重新生成覆盖,正确做法是修改扫描逻辑或配置源。

PackageManager 系统定制四层架构与实战路线 ① 包描述层 AndroidManifest.xml PackageParser Package / Activity / Service ② 服务接口层 IPackageManager.aidl PackageManagerService 权限检查 / Binder 调用 ③ 持久化层 packages.xml packages.list runtime-permissions.xml ④ 策略配置层 config.xml sysconfig / privapp default-permissions 启动扫描链路: SystemServer → PackageManagerService.main() → scanDirTracedLI() → parsePackage() → scanPackageLI() → 写入 packages.xml → 通知 ActivityManager / Launcher 实战路线图 · 基础 1. 环境搭建:AOSP 源码 + userdebug 2. 读懂 IPackageManager.aidl 3. 跟踪 install / scan 日志 4. 使用 dumpsys package 分析状态 5. 修改 config.xml 验证白名单 6. 编译刷机并回归 CTS 基础项 实战路线图 · 进阶 1. 定制签名校验与安装白名单 2. 默认权限与特权权限配置 3. 包可见性 queries 策略定制 4. 多用户与隔离存储适配 5. 增量扫描与启动性能优化 6. 编写自动化验证脚本 常见排障入口 logcat -s PackageManager dumpsys package <pkg> adb shell pm list packages -f /data/system/packages.xml SELinux avc: denied 日志 strace -p <system_server>

方法流程:一次定制从需求到落地的标准路径

系统定制最怕“改完不知道影响面”。建议采用五步法:需求拆解 → 定位层级 → 最小改动 → 编译验证 → 回归复盘。例如需求是“禁止安装非白名单应用”,先判断它属于策略配置层还是服务接口层;若只是预置白名单,优先改 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 层,忽略 SELinuxuser 版本安装失败或服务崩溃同步补充 file_contexts 与 te 规则
在 onCreate 中做耗时扫描系统启动超时、Watchdog 重启使用异步扫描或增量扫描策略
硬编码包名与路径多项目复用困难、易漏改通过 config.xml 或 sysconfig 配置化
忽略多用户与隔离存储副用户下权限异常按 userId 维度验证并处理 UserManager 切换
未回归 CTS/GTS认证失败、无法过 GMS定制后执行 cts-tradefed 相关包

本课程后续将沿着这张路线图逐层展开:先建立包解析与扫描的底层认知,再进入安装、权限、可见性与多用户的定制实战,最后以性能优化与自动化验证收束。建议你在学习每节时,同步在 AOSP 源码中定位对应类与方法,并用 dumpsys 与日志验证自己的理解,这样才能把“知道”变成“能改、敢改、改得稳”。