am broadcast
端末を変えるブロードキャスト intent を送ります。SystemUI の demo mode などプラットフォームのレシーバをシェルから動かす方法です。
- コマンド
- adb shell am broadcast
- コマンド
- アクティビティと intent(am)
- リスク
- 端末を変える
構文
am broadcast -a <action> [-e <key> <value>] […]フラグと引数
| トークン | 意味 |
|---|---|
| -a <action> | ブロードキャストの action。 |
| -e <key> <value> | 文字列の extra を 1 つ。繰り返せます。 |
使用例
settings put global sysui_demo_allowed 1まずゲートを開けます。この設定が off の間、SystemUI は demo のブロードキャストを全部無視します。買ったばかりの端末では off です。
am broadcast -a com.android.systemui.demo -e command enterdemo mode に入ります。他の demo コマンドより先に実行する必要があります。
am broadcast -a com.android.systemui.demo -e command notifications -e visible false自分の通知アイコンを隠します。スクリーンショットで実際に効くのはここです。
am broadcast -a com.android.systemui.demo -e command exitステータスバーを現実に返します。
出力の読み方
出力例
Broadcasting: Intent { act=com.android.systemui.demo (has extras) }
Broadcast completed: result=0`Broadcast completed: result=0` は intent が配送されたという意味です。誰かがそれに反応したという意味では **ありません**。レシーバは無視して構わないし、demo mode のゲートが閉じているとき、あるいはメーカーがレシーバを削除しているときの SystemUI はまさにそうします。確かめるのはこの行ではなく端末の画面です。
出力フィールド
| フィールド | 意味 |
|---|---|
| Broadcasting: Intent { … } | プラットフォームが解釈した intent。 |
| Broadcast completed: result=0 | 配送されました。何かが応答した証拠ではありません。 |
| Permission Denial | このビルドでは shell ユーザーがそのブロードキャストを送れません。 |
必要な権限
認可済みの `adb` 接続以外は何も要りません。root も `adb root` も `su` も、USB デバッグより先の開発者向けオプションも不要です。`am` は `instrument` 以外をすべて `cmd activity "$@"` に渡す 5 行のシェルスクリプト(AOSP の `cmds/am/am.sh`)なので、intent は `shell` ユーザーの資格で送られます。その資格でできないのが「保護されたブロードキャスト」の送信です。`ActivityManagerService` がシステムの呼び出し元と認めるのは `ROOT_UID`、`SYSTEM_UID`、`PHONE_UID`、`BLUETOOTH_UID`、`NFC_UID`、`SE_UID`、`NETWORK_STACK_UID` だけで、shell はそのどれでもありません。どこかのパッケージが `<protected-broadcast>` として宣言した action は、配送される前に拒否されます。`com.android.systemui.demo` はその一覧に載っていません。ケーブルから demo mode が動くのは、それだけが理由です。しかも demo のゲートは権限とは別物で、付与される能力ではなく `settings put` で書き込む Global 設定です。スクリプトに組み込む前に知っておきたい点があと 2 つあります。1 つは、この呼び出しがブロックすること。`--async` を付けないと `runSendBroadcast` は結果レシーバの中でタイムアウトなしの `wait()` に入るので、完了しないレシーバがいるとエラーを返さずシェルが固まります。もう 1 つは、重要な行が両方のストリームに散らばること。下の拒否は標準エラーに来るのに、サブコマンドの打ち間違いは標準出力に来ます。`2>&1` で集めて、綺麗に見える実行を信じる前に最初の 1 行を読んでください。
エラーメッセージの読み解き
| メッセージ | 意味 |
|---|---|
| Permission Denial: not allowed to send broadcast android.intent.action.BOOT_COMPLETED from pid=4821, uid=2000 | `ActivityManagerService` が、どのレシーバにも intent を見せる前に投げた `SecurityException` です。その action がどこかのパッケージの `<protected-broadcast>` 一覧に載っていて、shell はシステムの呼び出し元ではないからです。これを解除するフラグはありません。`--receiver-permission` も `--user` も、debuggable ビルドの root も効きません。一覧全体は `dumpsys package protected-broadcasts` が印字するので、action を打ち間違えたと思う前にそちらを確認してください。 |
| Exception occurred while executing 'broadcast': | `BasicShellCommandHandler.exec` が `Throwable` を捕まえ、空行とこのバナーとスタックトレースを標準エラーに書きました。原因を名乗るのは次の行です。`java.lang.IllegalArgumentException: Unknown option: --async` は、そのリリースがこのフラグを知らないという意味で、`--async` は tag android-11.0.0_r1 の `ActivityManagerShellCommand` には無く、android-12.0.0_r1 以降にあります。`No intent supplied` は `-a` の action を丸ごと書き忘れたということです。 |
| Unknown command: brodcast | `handleDefaultCommands` がサブコマンドを認識しませんでした。1 行に罠が 2 つあります。まず、これは標準エラーではなく **標準出力** に出るので、標準エラーだけを見ているスクリプトは綺麗な実行として記録します。次に、戻り値は -1 で、何ひとつ送られていません。端末の画面から結論しようとしていたことは、すべて 1 つ前の状態についての話です。 |
| cmd: Can't find service: activity | `cmd` がサブコマンドを渡すべき `activity` サービスを見つけられず、ブロードキャストはキューにすら入りませんでした。`system_server` がまだ公開していない起動途中なら想定内です。端末が壊れたと考えず、起動が終わってから送り直してください。 |
何が変わるか、そして戻る道
ブロードキャスト自体は何も永続的に変えませんが、受け取った側は変えられます。名前を挙げるべき例が SystemUI の demo mode です。ステータスバーを偽の時刻と偽のバッテリーで固定し、`exit` コマンドを誰かが送るまで端末はその状態のままなので、使う人は「端末が壊れた」と思い込みます。exit コマンドは常に手元に置いてください。
バージョンとメーカーに関する注意
- demo mode は `global sysui_demo_allowed` で塞がれていて、既定値は 0 です。虚空にブロードキャストする前に設定を読んでください。
- `enter` が最初の demo コマンドである必要があります。それなしでは他は無視されます。
これには UI があります
Android ADB Toolbox はこのコマンドを USB 経由で実行し、返ってきたものを解析します。Chromium 系ブラウザだけで、SDK も不要、どこにもアップロードしません。
関連コマンド
am broadcast と同じ作業で出てくるコマンド。
| コマンド | 何をするか |
|---|---|
| am start | コンポーネント指定または intent 指定でアクティビティを起動します。ディープリンクの解決を確かめる最短経路です。 |
| settings put | 設定プロバイダに値を書きます。開発者向けオプションのほとんどの裏にある仕組みです。 |
| screencap | スクリーンショットを撮ります。端末上のファイルに書くか、PNG として標準出力に流します。 |
他のアクティビティと intent(am)コマンド
| コマンド | 何をするか |
|---|---|
| am force-stop | あるアプリのプロセスとサービスをすべて終了させます。 |
Web ADB ツール群のパーサを書きながら、AOSP・toybox・カーネルのソースに突き合わせて確認しています。バージョンやメーカーで本当に挙動が変わるところは、世界の半分の端末で間違いになる数値を出す代わりに、そう書いてあります。