pm path 和 dumpsys package 的区别

要搞懂这个问题,我们得先拆两个关键: "这两个 adb 命令到底在问 PMS 要什么""隐藏的安装包到底'藏'在了哪里" 。下面用 "小白能懂的源码逻辑" 一步步讲透。

先铺垫:什么是 "隐藏的安装包"?

不是说应用藏在手机某个文件夹里找不到,而是指:PMS(PackageManagerService,Android 管理应用的 "大管家")里有这个包的 "身份记录",但这个包没有 "可用的 APK 文件"

比如常见场景:

  • 你手动删了 /data/app/com.myapp 下的 APK,但没执行 adb uninstall(PMS 没来得及删记录);
  • 应用安装到一半失败了,APK 没了,但 PMS 已经记了 "有个叫 com.myapp 的包";
  • 系统隐藏应用(比如通过工具把应用设为 "未启用",APK 被移走但记录留着)。

第一步:搞懂两个命令的 "本质区别"

adb shell pm pathadb shell dumpsys package 看似都是 "查应用",但它们向 PMS "要的东西完全不一样"------ 这是结果不同的核心。

我们先把两个命令的 "底层调用链路" 简化(跳过复杂的跨进程通信,只看关键逻辑):

命令 对应 PMS 的核心操作 核心目的
pm path com.myapp 调用 PackageManager.getPackageInfo() → 取 ApplicationInfo.sourceDir 找这个应用的 APK 文件路径(必须是 "能正常读取的 APK 文件")
dumpsys package com.myapp 调用 PackageManagerService.dump() → 遍历 PMS 的 "包记录列表" 把 PMS 里所有关于这个包的 "历史 / 当前记录" 全吐出来(不管 APK 在不在)

第二步:深入源码逻辑,看 PMS 怎么 "回应" 这两个命令

PMS 是 Android 系统的核心服务,它内部维护着一个 "账本"------ 记录所有和应用相关的信息(包名、APK 路径、权限、数据目录等),这个 "账本" 主要存在两个地方:

  1. 内存里的 mPackages 集合(所有解析过的包的实时记录);
  2. 磁盘上的 packages.xml 文件(开机时会读这个文件,把历史安装记录加载到 mPackages)。

场景 1:adb shell pm path com.myapp 为什么找不到?

pm path 的目的是 "要 APK 的路径",所以 PMS 会做一个严格的 "有效性检查"------没有可用的 APK,就说 "找不到"

我们看它的源码逻辑(简化后,对应 frameworks/base/cmds/pm/src/com/android/commands/pm/Pm.java):

java 复制代码
// pm path 命令的核心代码
private void runPath() {
    String packageName = mArgs[0];
    // 1. 向PMS要"这个包的详细信息(PackageInfo)"
    PackageInfo pkgInfo = mPackageManager.getPackageInfo(packageName, 0);
    if (pkgInfo == null) {
        // 没拿到信息 → 输出"找不到"
        System.err.println("package: not found");
        return;
    }
    // 2. 从PackageInfo里拿APK的路径(sourceDir就是APK所在位置)
    String apkPath = pkgInfo.applicationInfo.sourceDir;
    // 3. 关键检查:APK文件是否真的存在?
    if (new File(apkPath).exists()) {
        System.out.println("package:" + apkPath);
    } else {
        // 文件不存在 → 还是输出"找不到"
        System.err.println("package: not found");
    }
}

翻译
pm path 就像你问 PMS:"我要找 com.myapp 的安装包文件,你告诉我它在哪?"

PMS 会先查自己的 "账本"(mPackages):

  • 如果账本里根本没有 com.myapp → 说 "没听过这个包";

  • 如果账本里有,但查了一下 "记录的 APK 路径"(比如 /data/app/com.myapp/base.apk),发现文件没了 → 说 "找不到";

  • 只有 "账本有记录,且 APK 文件真的在",才会告诉你路径。

而 "隐藏的安装包" 正好是 "账本有记录,但 APK 没了",所以 pm path 必然找不到。

场景 2:adb shell dumpsys package com.myapp 为什么能找到?

dumpsys package 的目的是 "调试用的信息_dump"------PMS 会把 "所有和这个包相关的记录,不管有用没用,全给你列出来"。它的逻辑完全不关心 "APK 在不在",只关心 "我有没有这个包的记录"。

看它的源码逻辑(简化后,对应 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java):

java 复制代码
// dumpsys package 命令的核心dump方法
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    // 1. 解析参数,找到要查的包名com.myapp
    String targetPackage = getTargetPackage(args);
    // 2. 从PMS的"账本"(mPackages)里捞这个包的记录
    PackageParser.Package pkg = mPackages.get(targetPackage);
    if (pkg == null) {
        pw.println("No package info for " + targetPackage);
        return;
    }
    // 3. 不管APK在不在,把所有记录全打印出来:
    pw.println("Package name: " + pkg.packageName);
    pw.println("Previous APK path: " + pkg.applicationInfo.sourceDir); // 哪怕文件没了,也打印路径
    pw.println("Data directory: " + pkg.applicationInfo.dataDir);     // 数据目录还在就打印
    pw.println("Is enabled: " + pkg.applicationInfo.enabled);         // 哪怕禁用了也打印
    // ... 还有权限、版本号等几十项信息
}

翻译
dumpsys package 就像你问 PMS:"把你知道的关于 com.myapp 的所有事,哪怕是陈芝麻烂谷子的记录,都告诉我"。

PMS 只要在 "账本"(mPackages)里查到这个包名,不管:

  • APK 文件是不是被删了(会打印 "以前的 APK 路径");

  • 应用是不是被禁用了(会打印 "Is enabled: false");

  • 安装是不是失败了(会打印 "安装状态:未完成");

都会把记录全列出来 ------ 所以 "隐藏的安装包"(有记录没 APK)自然能被找到。

第三步:总结底层原理(一句话说透)

两个命令的 **"查询目的不同"→ 调用 PMS 的接口不同 → 检查的条件不同 **:

  • pm path 是 "要能用的 APK 路径",必须满足 "PMS 有记录 + APK 文件存在",缺一不可;

  • dumpsys package 是 "要所有记录",只要 "PMS 有这个包的记录"(不管 APK 在不在),就会显示。

而 "隐藏的安装包" 正好是 "PMS 有记录,但 APK 没了"------ 所以前者找不到,后者能找到。

再补个小实验,帮你彻底理解

  1. 正常安装 com.myapp:adb install myapp.apk

  2. 执行 adb shell pm path com.myapp → 能看到 /data/app/com.myapp-xxx/base.apk(APK 存在);

  3. 手动删 APK:adb shell rm /data/app/com.myapp-xxx/base.apk(此时 PMS 还没删记录);

  4. 再执行 adb shell pm path com.myapp → 输出 "not found"(APK 没了);

  5. 执行 adb shell dumpsys package com.myapp → 能看到包名、以前的 APK 路径(虽然文件没了)、数据目录等信息(PMS 记录还在)。

这就是最直观的验证~

相关推荐
柿蒂38 分钟前
从动态缩放自定义View,聊聊为什么不要把问题复杂化
android·ai编程·android jetpack
kerli40 分钟前
kotlin协程系列:callbackFlow
android·kotlin
没有了遇见2 小时前
Android 原生定位实现(替代融合定位收费,获取经纬度方案)
android·kotlin
一枚小小程序员哈2 小时前
基于Android的车位预售预租APP/基于Android的车位租赁系统APP/基于Android的车位管理系统APP
android·spring boot·后端·struts·spring·java-ee·maven
诸神黄昏EX2 小时前
Android SystemServer 系列专题【篇四:SystemServerInitThreadPool线程池管理】
android
是店小二呀3 小时前
【C++】智能指针底层原理:引用计数与资源管理机制
android·java·c++
DoubleYellowIce4 小时前
一次混淆XLog导致的crash分析记录
android
你听得到114 小时前
弹窗库1.1.0版本发布!不止于统一,更是全面的体验升级!
android·前端·flutter
RainyJiang5 小时前
布局与测量性能优化:让Compose从"嵌套地狱"到"扁平化管理"
android·android jetpack