调试与日志:PMS 相关 logcat 标签、dumpsys package 命令详解
做 Android 系统开发,说白了就是跟各种服务打交道。而 PackageManagerService(PMS)这家伙,绝对是绕不开的大佬。你想想看,应用安装、卸载、权限管理、组件查询……哪样不得经过它?
但 PMS 这货又特别「闷」。出了问题,它不会直接告诉你「我这儿卡住了」或者「这个包信息丢了」。你得学会跟它「对话」。怎么对话?就是靠 logcat 和 dumpsys。
我个人习惯,遇到 PMS 相关的问题,第一件事就是打开 logcat,第二件事就是跑 dumpsys package。这两板斧下去,80% 的问题都能定位到根因。今天我就把这两招的细节掰开揉碎了讲给你听。
一、PMS 的 logcat 标签:读懂它的「自言自语」
PMS 在运行时会输出大量日志。但日志量太大,你不可能全看。关键是知道该过滤哪些标签。
常用的 PMS 相关 logcat 标签,我整理了一张表:
| 标签名 | 日志级别 | 典型场景 |
|---|---|---|
| PackageManager | D / W / E | 应用安装、卸载、查询等常规操作 |
| PackageParser | D / W / E | 解析 AndroidManifest.xml 时的错误或警告 |
| PackageInstaller | D / I / E | 安装会话的创建、提交、失败原因 |
| PMS | V / D / W | PMS 内部状态变化,如扫描、权限检查 |
| Settings | D / W / E | 包设置文件的读写、数据损坏修复 |
| IntentResolver | D / W | Intent 匹配 Activity、Service 时的冲突或异常 |
嗯,这里要注意:PackageManager 和 PMS 是两个不同的标签。前者是 Framework 层对外接口的日志,后者是 PMS 服务内部的日志。调试时我通常两个都看。
举个例子,有一次我遇到一个应用安装后无法启动的问题。logcat 里只看到一行:
W/PackageManager: Package com.example.app has no activities
我当时就纳闷了,明明 AndroidManifest 里有声明 Activity 啊。后来加上 PackageParser 标签一看,真相大白:
E/PackageParser: <activity> tag requires 'android:name' attribute
原来是开发者在写布局文件时,Activity 的 name 属性漏掉了。你看,光看一个标签是不够的,得组合着来。
logcat -s PackageManager:PMS:PackageParser。如果问题跟安装流程相关,再加一个 PackageInstaller。
二、dumpsys package:PMS 的「体检报告」
logcat 是看 PMS 在做什么,而 dumpsys package 是看 PMS 当前的状态是什么。这俩是互补的。
命令很简单:
adb shell dumpsys package
但输出内容极其庞大,动辄几千行。你不能从头看到尾,得学会「精准下刀」。
2.1 只看某个包的信息
我最常用的变体是这个:
adb shell dumpsys package com.example.app
它会输出该包的所有信息,包括:
- 版本信息:versionCode、versionName
- 安装路径:codePath、resourcePath
- 权限列表:grantedPermissions、requestedPermissions
- 组件信息:activities、services、receivers、providers
- 签名信息:signatures
我曾经遇到一个诡异的问题:应用升级后,某个权限明明在清单里声明了,但运行时就是拿不到。我跑了一下 dumpsys package,发现 grantedPermissions 列表里确实没有这个权限。再一看 requestedPermissions,有!这说明权限声明没问题,但系统没授予。最后定位到是权限策略组(permission policy)在作怪。
2.2 查看所有已安装的包
有时候你需要快速知道系统里装了哪些包:
adb shell dumpsys package packages
输出会列出所有包名和对应的 userId。我一般配合 grep 用:
adb shell dumpsys package packages | grep "com.tencent"
2.3 查看权限相关的信息
权限问题是 PMS 调试的重灾区。你可以用:
adb shell dumpsys package permissions
它会列出所有已定义的权限,以及每个权限被哪些应用申请了、被哪些应用授予了。输出格式大致如下:
Permission [android.permission.INTERNET] (4b1c2d3):
sourcePackage=android
enabled=true
grantedToUser:0
com.android.chrome
com.example.app
注意看 grantedToUser:0 下面的列表,这就是当前用户(用户 0)下,哪些应用被授予了这个权限。如果某个应用不在列表里,那它肯定拿不到这个权限。
dumpsys package permissions 输出为空的情况。别慌,这通常是因为 PMS 的权限数据还没加载完,或者权限数据库损坏了。重启一下设备通常能解决。如果重启还不行,那就得考虑清除 /data/system/package.xml 和 package-restrictions.xml 了——不过这是最后的手段,操作前一定要备份。
2.4 查看共享库和特性
有些应用依赖特定的共享库(shared library)或系统特性(feature)。你可以用:
adb shell dumpsys package shared-libraries
adb shell dumpsys package features
这两个命令在排查「应用兼容性」问题时特别有用。比如某个应用在设备 A 上能装,在设备 B 上装不了,很可能就是设备 B 缺少某个共享库或特性。
三、核心逻辑:PMS 调试知识体系
说了这么多,我画了一张图来总结 PMS 调试的核心逻辑。你一看就明白了:
说白了,调试 PMS 就两步:先判断问题是「动态行为」还是「静态状态」。动态行为看 logcat,静态状态看 dumpsys。两者结合,没有搞不定的问题。
四、实战技巧:组合拳才是王道
光知道命令还不够,得会用。我分享几个实战中总结出来的组合拳:
4.1 安装失败排查
应用安装失败,是最常见的 PMS 问题。我的排查流程是这样的:
- 先看 logcat,过滤
PackageInstaller和PackageManager,找到失败原因。常见的有:签名不一致、版本号更低、磁盘空间不足。 - 如果 logcat 里没有明确错误,再用
dumpsys package查看目标包的状态。有时候是旧包没卸载干净,导致新包安装冲突。 - 最后检查
dumpsys package permissions,看是不是权限策略阻止了安装。
我曾经遇到一个案例: 某款应用在系统应用升级时总是失败。logcat 里只报了一个模糊的 INSTALL_FAILED_INTERNAL_ERROR。我查了半天,最后用 dumpsys package 对比了新旧版本的签名信息,发现签名证书居然不一样!原来是开发团队换了签名密钥,但忘了通知我们。嗯,从那以后,我每次升级系统应用都会先检查签名一致性。
4.2 权限异常排查
应用运行时提示「权限被拒绝」,但清单里明明声明了。怎么办?
- 用
dumpsys package 包名查看grantedPermissions列表。如果权限不在列表里,说明系统没授予。 - 用
dumpsys package permissions查看该权限的全局授予情况。有时候是权限被系统策略强制拒绝了。 - 如果以上都正常,那就得看 logcat 里有没有
PermissionController或PermissionManager的日志。权限授予流程涉及多个模块,PMS 只是其中一环。
五、总结
调试 PMS,说白了就是两件事:看它做了什么(logcat),看它现在是什么状态(dumpsys)。
我个人觉得,很多开发者太依赖 logcat,忽略了 dumpsys 的价值。其实 dumpsys 才是 PMS 的「全息影像」,它能告诉你 PMS 内部所有数据结构的当前值。而 logcat 只是告诉你「发生了什么变化」。两者缺一不可。
最后送大家一句话:遇到 PMS 问题别慌,先跑 dumpsys package 看看,再翻 logcat 找线索。这套组合拳打下来,大部分问题都能迎刃而解。
公众号:蓝海资料掘金营,微信deep3321