pm list packages
read-onlyLists installed packages, optionally with the APK path, uid, version code and installer.
- Command
- adb shell pm list packages
- Commands
- Packages (pm)
- Risk
- read-only
Syntax
pm list packages [-f] [-U] [--show-versioncode] [-i] [-s | -3 | -e | -d | -u] [--user <id>] [<name filter>]Flags and arguments
| Token | Meaning |
|---|---|
| -f | Also print the APK path the package was installed from. |
| -UAndroid 8.0+ | Also print the uid. |
| --show-versioncodeAndroid 8.0+ | Also print the version code. |
| -i | Also print the installer package. One extra binder call per package. |
| -s | System packages only. |
| -3 | Third-party packages only. |
| -e | Packages currently enabled for the queried user. |
| -d | Packages currently disabled for the queried user. |
| -u | Include packages uninstalled with data kept, which makes this list a superset of the default one. |
| --user <id> | Ask about one Android user. Without it the shell command queries every user, so a package disabled for user 0 but enabled in a work profile lands in both the -e and -d lists. |
Examples
pm list packages -3Everything you installed yourself.
pm list packages -f -U --show-versioncodeThe full inventory in one pass: path, uid and version code per package.
pm list packages -d --user 0What is currently disabled for the primary user.
pm list packages -uIncludes packages removed with `pm uninstall -k`, which is how you find what can still be restored.
Reading the output
Sample output
package:/data/app/~~kO7bJ9w==/com.example-Ay8s2Q==/base.apk=com.example versionCode:4711 installer=com.android.vending uid:10234One line per package, built left to right by the platform: the literal `package:` prefix, the APK path when you asked for it, then the package name, then the optional suffixes. Read it from the right — peel off `uid:`, `installer=`, `stopped=` and `versionCode:` in turn and what remains is the name, because a modern APK path contains `=` characters of its own.
Output fields
| Field | Meaning |
|---|---|
| package: | Fixed prefix on every line. |
| <path>= | The APK path, present only with -f. Ends at the last `=`. |
| versionCode:<n> | The long version code, with --show-versioncode. |
| stopped=<bool> | Whether the package is in the stopped state. |
| installer=<pkg> | Who installed it, with -i. Preceded by two spaces, not one, and printed as the four letters `null` for a preinstalled app. |
| uid:<n>[,<n>] | The uid, with -U. A comma-separated list when the package exists for more than one Android user. |
What access it needs
Nothing beyond an authorised `adb` connection — no root, no `adb root`, no `su`. `pm` is a one-line shell script that runs `cmd package "$@"` (AOSP `cmds/pm/pm.sh`), so the listing is answered with the identity of the `shell` user on the other end of the cable, and every flag on this page is read-only: nothing here installs, removes or disables anything. The access question that does bite is which stream you keep. `BasicShellCommandHandler.exec` writes its failure banner and the stack trace to stderr, so a listing collected with `2>/dev/null` turns a refused call into an empty list, which reads exactly like a phone with no apps on it. Collect with `2>&1` and check the first line before believing a short answer.
Failure messages, decoded
| Message | Meaning |
|---|---|
| Error: Unknown option: -U | Android 7.1 and earlier do not know `-U` or `--show-versioncode`. `runListPackages` prints this and returns without listing a single package, so the result is empty rather than merely missing a column — re-run without the flag instead of concluding the phone has no apps. |
| Exception occurred while executing 'list': | `BasicShellCommandHandler.exec` caught a `Throwable` and wrote this line plus the stack trace to stderr. The line after it names the cause: a `java.lang.SecurityException` means the call was refused, not that nothing is installed. You only see any of it if you kept stderr. |
| cmd: Can't find service: package | `cmd` could not find the `package` service to hand the subcommand to. Expected while the device is still booting, before `system_server` has published it — wait for boot to finish and ask again rather than treating it as a broken device. |
Version and vendor notes
- `-U` and `--show-versioncode` arrived in Android 8.0. An older build answers an unknown option with `Error: Unknown option: -U` and then lists nothing at all, so an empty result means the command failed, not that the phone has no apps.
- On Android 10 and later the APK path contains several `=` characters (`/data/app/~~kO7bJ9w==/com.foo-Ay8s2Q==/base.apk`), so the path and the name are split on the last one.
- A name appearing in both the `-e` and `-d` lists is not a contradiction: the enabled state is per Android user and the command defaults to all of them. Pass `--user 0`.
We have a UI for this
Android Debloat Tool runs this command over USB and parses what comes back — a Chromium browser, no SDK, nothing uploaded.
Related commands
Commands that turn up in the same session as pm list packages.
| Command | What it does |
|---|---|
| pm path | Prints the absolute paths of the APK files that make up an installed package. |
| pm uninstall | Removes a package, or removes it for one Android user only — which is how a preinstalled app is disposed of without root. |
| pm disable-user | Switches a package off for one Android user without removing it — the reversible alternative to uninstalling. |
| dumpsys package | Everything the package manager knows about one app: version, paths, flags, install source and per-user state. |
More Packages (pm) commands
| Command | What it does |
|---|---|
| pm clear | Wipes an app's data — or, on Android 13 and later, only its cache. |
| pm trim-caches | Asks the system to drop cached files until the given amount of free space exists. |
| pm install | Installs one APK that is already on the device, which is what `adb install` does under the hood. |
| pm install-create | Opens an install session so several APKs — a base plus its splits — are installed as one atomic unit. |
Checked against AOSP, toybox and kernel sources while writing the parsers behind our Web ADB tools. Where a behaviour genuinely varies by Android version or manufacturer, this page says so instead of giving a number that would be wrong on half the phones out there.