ByteScope

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 denieduid の切り替えは成功し、アプリのホームへ入るところで失敗しました。まれで、たいていはデータディレクトリの所有者かモードが、ヘルパーが直前に行う確認のどれかを満たさなかったという意味です。あなたのアクセス権についてではなく、ディスク上のディレクトリについての言明として読んでください。

バージョンとメーカーに関する注意

  • これはマニフェストで debuggable を宣言したアプリでしか動かず、実際には自分のアプリの debug ビルドを意味します。Play ストアのアプリは拒否され、その拒否は不具合ではなくセキュリティモデルです。
  • コマンドはアプリのホームディレクトリで始まるので、`databases/app.db` のような相対パスを使います。他のアプリのディレクトリに向ける手段はありません。
  • アプリが開いている最中のデータベースを複製すると、書きかけの状態を写し取ることがあります。中身が重要なら先にアプリを止めてください。
  • 関門は決まった順に確認されます。呼び出し側の uid、次にカーネルのコマンドラインのスイッチ、最後にパッケージ自身。だから最初に返ってくる行が、いまどこに立っているかを教えてくれますし、手前の関門を通るまで後ろの関門と議論しても意味がありません。
  • uid を切り替えた後、ヘルパーはアプリのデータディレクトリをもう一度検証します。絶対パスで、正しく所有されていて、グループや他者からアクセスできず、`..` を含まないこと。その段階での拒否は、あなたのアクセス権ではなくディスク上のディレクトリを語っていて、あなたのコマンドが走る前に中断します。

これには UI があります

Android ADB Toolbox はこのコマンドを USB 経由で実行し、返ってきたものを解析します。Chromium 系ブラウザだけで、SDK も不要、どこにもアップロードしません。

Android ADB Toolbox を開く

関連コマンド

run-as と同じ作業で出てくるコマンド。

コマンド何をするか
logcatシステムログを流し読みします。端末で起きていることすべての実況です。
dumpsys dropboxクラッシュ、ANR、tombstone を保持するプラットフォームのリングバッファ。root なしで ANR トレースを読む方法です。
pm pathインストール済みパッケージを構成する APK ファイルの絶対パスを表示します。

他のシステムとログコマンド

コマンド何をするか
top1 回分のプロセス表:CPU 使用率、メモリ、状態、コマンドライン。
getpropシステムプロパティを表示します。端末自身が語る「これは何か」です。

Web ADB ツール群のパーサを書きながら、AOSP・toybox・カーネルのソースに突き合わせて確認しています。バージョンやメーカーで本当に挙動が変わるところは、世界の半分の端末で間違いになる数値を出す代わりに、そう書いてあります。

よくある質問

adb shell のコマンドはどう実行しますか?

端末で開発者向けオプションと USB デバッグを有効にし、ケーブルを繋いだうえで、platform-tools を入れた機械から adb shell <コマンド> を実行します。adb shell だけを実行すれば対話プロンプトが出て、接頭辞なしで打てます。スクリーンショットのようにバイナリを出力するコマンドでは adb shell ではなく adb exec-out を使ってください。素のシェルサービスは端末を割り当て、それが改行のバイトを書き換えてデータを壊します。

adb shell のコマンドに root は必要ですか?

このリファレンスにあるものには不要です。すべて shell ユーザーとして動き、自分の Android ユーザー向けのパッケージ管理、ほとんどの dumpsys サービスの読み取り、設定プロバイダへの書き込み、入力の注入、共有ストレージの読み取りができます。root が必要なのはこのリファレンスがあえて避けていること、つまり他のアプリのプライベートデータの読み取り(debuggable なビルドに対する run-as を除く)、システムパーティションへの書き込み、/data/anr の直接読み取りです。

自分の端末では出力が違って見えるのはなぜ?

Android のバージョンか、メーカーのどちらかです。一部のフラグやフィールドは特定のリリースから入ったもので、それはコマンドごとに注記しています。残りはメーカーによる改変で、いちばん影響が大きいのは dumpsys です。ダンプはデバッグ出力で、そのテキストはサービスの作者が最後に印字した内容そのもの、しかもメーカーはそれを変えて自分の変更をバックポートします。フィールドは位置ではなく名前で読み、見慣れない形は失敗ではなく差分として扱ってください。

端末ではなくブラウザから実行できますか?

多くのコマンドは可能です。このサイトの Web ADB ツール群は、Chromium 系のデスクトップブラウザから WebUSB で端末と話し、SDK のインストールも不要、どこにもアップロードしません。各ページは、該当するツールがあればそこへリンクしています。知っておく価値のある制限が 2 つあります。ADB インターフェイスを保持できるプログラムは同時に 1 つだけなので、デスクトップの adb server は先に止める必要があります。そして adb forward と adb reverse はブラウザでは一切動きません。

打つより押したい場合は、Web ADB Toolkit がこの種のコマンドをブラウザから USB 経由で実行します。あるいは全コマンドを見る。