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 记录还在)。

这就是最直观的验证~

相关推荐
爱笑鱼1 小时前
Binder(八):远端进程死了,BinderProxy 为什么还能收到通知?
android
zhangphil1 小时前
Android ContentProvider/ContentResolver读图片,跨进程 IPC慢
android
yueqc12 小时前
Android .so 文件压缩
android·so·包体积
龚礼鹏2 小时前
深入解析 Android Automotive (AAOS) 启动流程与 CarService 核心机制(基于 Android 16 最新源码视角)
android
rosmis2 小时前
agent各指标定义
android·java·开发语言
风样滴男人哟4 小时前
PHP特性之反射类ReflectionClass机制
android·开发语言·php
小孔龙4 小时前
RenderNode 与 DisplayList:Android 硬件加速的绘制记录与复用
android·性能优化
qizayaoshuap5 小时前
鸿蒙 ArkTS 实战:搜索列表 城市实时过滤(示例 94)
android·华为·harmonyos
朝星5 小时前
Framework筑基之Handler消息机制5(应用层)
android
2601_965798475 小时前
ForumLab Review: Fast PHP Script for SEO Forum Sites
android·adb·php