pm path
読み取りのみインストール済みパッケージを構成する APK ファイルの絶対パスを表示します。
- コマンド
- adb shell pm path
- コマンド
- パッケージ(pm)
- リスク
- 読み取りのみ
構文
pm path [--user <id>] <package>フラグと引数
| トークン | 意味 |
|---|---|
| --user <id> | Android ユーザーを 1 人に限定します。古いビルドはこのフラグを拒否するので、その場合は外して再実行します。 |
使用例
pm path com.example分割インストールなら base APK に加えて split ごとに 1 行出ます。
pm path --user 0 com.example仕事用プロファイルではなくプライマリユーザーの分。
出力の読み方
出力例
package:/data/app/~~kO7bJ9w==/com.example-Ay8s2Q==/base.apk
package:/data/app/~~kO7bJ9w==/com.example-Ay8s2Q==/split_config.arm64_v8a.apk1 ファイル 1 行の `package:` 行です。1 行なら通常の APK、複数行なら分割インストールで、base だけ取り出してもどこにもインストールできないアプリになります。すべてが APK とは限りません。Play 経由のインストールは `.dm` という dex メタデータも書き込み、これはアプリではなくインストーラのものです。
出力フィールド
| フィールド | 意味 |
|---|---|
| package:<path> | パッケージを構成するファイル 1 つにつき 1 本の絶対パス。 |
| base.apk | 本体の APK。 |
| split_*.apk | 設定ごとの split:ABI、画面密度、言語。 |
| *.dm | インストーラが書いた dex メタデータで、アプリの一部ではありません。 |
必要な権限
認可済みの `adb` 接続だけで足ります。root も `adb root` も `su` も不要です。`pm` は `cmd package "$@"` という 1 行のシェルスクリプト(AOSP の `cmds/pm/pm.sh`)なので、問い合わせはケーブルの向こうの `shell` ユーザーの資格で処理され、`path` はパッケージデータベースを読むだけです。インストールも移動も削除もしません。ただし、この後で効いてくるアクセスの事実が 2 つあります。1 つは `--user <id>` で、これは他人の Android ユーザーについて尋ねる操作なので、shell にその境界を越えさせないビルドはパスの代わりに `SecurityException` を返します。もう 1 つは、APK の在り処を教えてもらえることと、その APK を読めることは別だという点です。`/data/app/**` を shell ユーザーが辿れるかどうかは仕様上の保証ではないため、堅牢化されたビルドは何の問題もないパスを表示しておきながら、その後の pull を拒否できます。`parsePmPathOutput` が拒否と空の答えを区別しているのはまさにそのためで、APK Extractor もその違いを隠さずに見せます。
エラーメッセージの読み解き
| メッセージ | 意味 |
|---|---|
| Error: Unknown option: --user | このビルドの `pm path` は `--user` を受け付けません。この一族のオプション拒否はすべてそうですが、`package:` 行を 1 本も出す前に打ち切られるので、答えは「空」ではなく「無い」です。アプリが未インストールだと結論する前に、フラグを外して聞き直してください。どのリリースからこのフラグが通るようになったかは本リポジトリで確認できていないので、バージョンは不明として端末に答えさせてください。 |
| Exception occurred while executing 'path': | `ShellCommand` のラッパーが `Throwable` を捕まえ、このバナーとスタックトレースを標準エラーに書きました。原因を名乗るのはその下の行で、そこに `java.lang.SecurityException` があれば shell が問い合わせてはいけないユーザー id だったということです。`findPmPathFailure` がパスを読む前にこのバナーを探すのは、標準エラーを捨ててしまうと「拒否された問い合わせ」と「未インストール」が見分けられなくなるからです。 |
| cmd: Can't find service: package | `cmd` がサブコマンドを渡すべき `package` サービスを見つけられませんでした。`system_server` がまだ公開していない起動途中なら想定内です。端末が壊れたと考えず、起動が終わるのを待ってください。 |
バージョンとメーカーに関する注意
- 存在しないパッケージでは何も出力せず終了コード 1 になるので、空の結果は「失敗」ではなく「未インストール」を意味します。
- shell ユーザーが実際に `/data/app/**` を読めるかは保証されていません。多くのビルドでは辿れて読めるため APK の取り出しは古くからの定番ですが、堅牢化されたビルドは拒否します。
これには UI があります
APK Extractor はこのコマンドを USB 経由で実行し、返ってきたものを解析します。Chromium 系ブラウザだけで、SDK も不要、どこにもアップロードしません。
関連コマンド
pm path と同じ作業で出てくるコマンド。
| コマンド | 何をするか |
|---|---|
| pm list packages | インストール済みパッケージを一覧表示します。APK パス、uid、バージョンコード、インストーラも同時に取得できます。 |
| dumpsys package | パッケージマネージャが知っているすべて:バージョン、パス、flags、インストール元、ユーザーごとの状態。 |
| pm install-create | インストールセッションを開き、base とその split をまとめて 1 つの操作としてインストールします。 |
他のパッケージ(pm)コマンド
| コマンド | 何をするか |
|---|---|
| pm uninstall | パッケージを削除します。ユーザー単位の削除なら、root なしでプリインストールアプリを片付けられます。 |
| pm disable-user | パッケージを削除せずに、指定した Android ユーザーで無効にします。アンインストールより安全で、確実に戻せます。 |
| pm clear | アプリのデータを消去します。Android 13 以降ならキャッシュだけを消すこともできます。 |
| pm trim-caches | 指定した空き容量に達するまで、システムにキャッシュファイルを捨てさせます。 |
| pm install | すでに端末上にある APK を 1 つインストールします。`adb install` が内部でやっていることです。 |
Web ADB ツール群のパーサを書きながら、AOSP・toybox・カーネルのソースに突き合わせて確認しています。バージョンやメーカーで本当に挙動が変わるところは、世界の半分の端末で間違いになる数値を出す代わりに、そう書いてあります。