run-as
読み取りのみあるアプリ自身の uid でコマンドを実行します。root なしで debuggable ビルドのプライベートファイルを読む方法です。
- コマンド
- adb shell run-as
- コマンド
- システムとログ
- リスク
- 読み取りのみ
構文
run-as <package> <command> [<args>]フラグと引数
| トークン | 意味 |
|---|---|
| <package> | 身元を借りるアプリ。インストール済みで、マニフェストで debuggable と宣言されている必要があります。 |
| --user <id> | パッケージのどの Android ユーザーのコピーになるか。付けなければヘルパーは呼び出し側のユーザーを使い、普通のケーブル越しならそれは主ユーザーです。同じパッケージが仕事用プロファイルにも存在するときは明示してください。 |
| <command> | パッケージ名より後ろはすべてアプリとして実行され、頼まない限り間にシェルは入りません。だから同じ行に書いたリダイレクトは、アプリではなく `shell` uid の「あなたの」シェルが行います。アプリのデータベースを共有ストレージに書き出すのが通るのは、まさにそのためです。 |
使用例
run-as com.example.debug idプローブ:実際になった uid を印字するので、答えが単に無言ではなく検証可能になります。
run-as com.example.debug ls databases/アプリの SQLite ファイルを一覧します。作業ディレクトリは既にアプリのホームです。
run-as com.example.debug cat databases/app.db > /sdcard/app.db取り出せる場所にデータベースを複製します。
run-as --user 0 com.example.debug id同じプローブを、名指しした Android ユーザー 1 つに向けます。仕事用プロファイルにも存在するパッケージのために。
run-as com.example.debug sh -c 'ls -l files cache'アプリの身元の内側でシェルを 1 つ走らせます。1 コマンドでは足りないときのために。自分のシェルがそのまま渡すよう、全体を引用してください。
出力の読み方
実行したコマンドが印字するものがそのまま出ます。拒否は `run-as` 自身から来て、3 つのうちどれが起きたかを教えます。パッケージが debuggable でない、パッケージが不明、あるいはそもそもこのビルドにヘルパーがない。
出力フィールド
| フィールド | 意味 |
|---|---|
| uid=10234(u0_a234) … | `id` のプローブが成功:あなたはいまそのアプリです。 |
| …is not debuggable | リリースビルドです。root なしにできることはなく、これはプラットフォームが正しく働いている姿です。 |
| unknown package | 打ち間違い、またはこのユーザーにアプリがインストールされていません。 |
| run-as: not found | ビルドにヘルパーがありません。まれですが起こります。 |
| package not an application | 名前はプラットフォームが知っているものの、インストールされたアプリではないので、借りる uid がありません。 |
| run-as is disabled from the kernel commandline | このイメージが起動したときヘルパーが切られていました。要求ではなくビルドの性質です。 |
必要な権限
特殊なので、失敗の行が意味を持つ前にここを読んでください。`/system/bin/run-as` は setuid root のヘルパーです。特権を持って始まり、誰が何を頼んでいるかを確認してから、対象アプリの uid と gid に落ちてあなたのコマンドを実行します。そうなるかどうかを決める関門は 3 つで、プラットフォームのソースを読む限り Android 11 から 15 まで変わっていません。呼び出し側は `shell` か `root` でなければならず、他の uid は最初の確認を越えられません。これがアプリの中に持ち込めない理由です。ビルドは、カーネルのコマンドラインでヘルパーを無効にしていてはいけません。そしてパッケージは、あなたが名指しした Android ユーザーにインストールされていて、自分のマニフェストで debuggable と印されていなければなりません。実務上は、自分でビルドした何かの debug ビルドという意味です。uid を切り替えた後、ヘルパーはアプリのデータディレクトリへ入る前にもう一度それを検証します。パスは絶対で、そのアプリの uid と gid が所有していて、他者から読み書きできず、`..` の要素を含まないこと。どれか 1 つでも外れれば、あなたのコマンドが走る前に中断します。だから root も `adb root` も開発者向けオプションで有効にするものも要りませんし、同じ理由でリリースビルドを口説き落とすこともできません。それが必要な端末は root が必要な端末で、このページのどのフラグもその代わりにはなりません。
エラーメッセージの読み解き
| メッセージ | 意味 |
|---|---|
| run-as: package not debuggable: com.example | アプリのマニフェストが自分を debuggable と宣言していません。これは欠陥ではなく設計どおりに働いているプラットフォームで、ストアのビルドは root の有無に関係なくどの端末でも断られます。文言そのものに注意してください。Android 11 から 15 はどれも `package not debuggable` と印字しますが、ずっと古いビルドは同じ拒否を、パッケージが debuggable でないという文章として書いていました。古い言い回しで照合しているものは、最近の拒否を「認識できないもの」に分類してしまいます。 |
| run-as: unknown package: com.example | パッケージの一覧にその名前がありませんでした。打ち間違いか、尋ねているのとは別の Android ユーザーにアプリが入っているかのどちらかで、`pm list packages` がどちらかを決めます。しかも記憶ではなくプラットフォームに基づいて決めます。 |
| run-as: only 'shell' or 'root' users can run this program | 呼び出し側の uid がどちらでもありません。ケーブルからではなくアプリの中から実行したときに見かけます。ヘルパーはパッケージを見る前に呼び出し側を確認するので、この行はパッケージが存在するかどうかについて何も語りません。 |
| run-as: package not an application: com.example | 名前はプラットフォームが知っている何かに解決されましたが、それはインストールされたアプリではないので、なれるアプリの uid がありません。`unknown package` とは別物で、その区別こそが役に立つ部分です。 |
| run-as: run-as is disabled from the kernel commandline | このビルドはヘルパーを切った状態で起動しました。アプリも、パッケージ名も、あなた自身の uid も答えを変えません。その起動の性質であり、越える道は別のイメージだけです。 |
| run-as: couldn't chdir to package's data directory '/data/user/0/com.example': Permission denied | uid の切り替えは成功し、アプリのホームへ入るところで失敗しました。まれで、たいていはデータディレクトリの所有者かモードが、ヘルパーが直前に行う確認のどれかを満たさなかったという意味です。あなたのアクセス権についてではなく、ディスク上のディレクトリについての言明として読んでください。 |
バージョンとメーカーに関する注意
- これはマニフェストで debuggable を宣言したアプリでしか動かず、実際には自分のアプリの debug ビルドを意味します。Play ストアのアプリは拒否され、その拒否は不具合ではなくセキュリティモデルです。
- コマンドはアプリのホームディレクトリで始まるので、`databases/app.db` のような相対パスを使います。他のアプリのディレクトリに向ける手段はありません。
- アプリが開いている最中のデータベースを複製すると、書きかけの状態を写し取ることがあります。中身が重要なら先にアプリを止めてください。
- 関門は決まった順に確認されます。呼び出し側の uid、次にカーネルのコマンドラインのスイッチ、最後にパッケージ自身。だから最初に返ってくる行が、いまどこに立っているかを教えてくれますし、手前の関門を通るまで後ろの関門と議論しても意味がありません。
- uid を切り替えた後、ヘルパーはアプリのデータディレクトリをもう一度検証します。絶対パスで、正しく所有されていて、グループや他者からアクセスできず、`..` を含まないこと。その段階での拒否は、あなたのアクセス権ではなくディスク上のディレクトリを語っていて、あなたのコマンドが走る前に中断します。
これには UI があります
Android ADB Toolbox はこのコマンドを USB 経由で実行し、返ってきたものを解析します。Chromium 系ブラウザだけで、SDK も不要、どこにもアップロードしません。
関連コマンド
run-as と同じ作業で出てくるコマンド。
| コマンド | 何をするか |
|---|---|
| logcat | システムログを流し読みします。端末で起きていることすべての実況です。 |
| dumpsys dropbox | クラッシュ、ANR、tombstone を保持するプラットフォームのリングバッファ。root なしで ANR トレースを読む方法です。 |
| pm path | インストール済みパッケージを構成する APK ファイルの絶対パスを表示します。 |
他のシステムとログコマンド
Web ADB ツール群のパーサを書きながら、AOSP・toybox・カーネルのソースに突き合わせて確認しています。バージョンやメーカーで本当に挙動が変わるところは、世界の半分の端末で間違いになる数値を出す代わりに、そう書いてあります。