mcpField
U
understanding-adb-architecture

understanding-adb-architecture

github.com/skydoves開発33963 回インストール22 週間前に更新
リポジトリ

understanding-adb-architecture について

Android 開発者向けに、ADB の CLI、ホスト側サーバー、デバイス側デーモンの役割を説明するスキルです。バージョンの不一致やポート競合、転送の問題を調べ、認証キーを保持する重要性も扱います。

主な機能

  1. 01ADB の三要素の構造を説明
  2. 02サーバーの起動とポートを解説
  3. 03競合する adb バイナリを診断
  4. 04環境変数とログによる調査
  5. 05RSA 認証キーの影響を説明

活用シーン

  1. 01初回のサーバー起動表示を判断
  2. 025037 番ポートやバージョン競合の調査
  3. 03CI のキーとサーバーポートの設定
  4. 04Linux の USB 転送問題の診断

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/skydoves/android-testing-skills --skill understanding-adb-architecture

インストール後、Claude Code で/understanding-adb-architectureを入力して読み込まれたか確認します。

詳細

ADB アーキテクチャを理解する — クライアント、サーバー、デーモン

ADB は 1 つのバイナリで、3 つの役割を担います。「adb の動作がおかしい」という報告の多くは、どの役割(ローカル CLI、ポート 5037 で長時間稼働するホストサーバー、またはデバイス上の adbd)に問題があるのか、あるいは 2 つの異なる adb バイナリが同じポートを奪い合っているのかを誤解したことが原因です。このスキルでは、ADB スキルセットの残りの基盤となるメンタルモデルを身につけます。

このスキルを使う場面

  • ユーザーに * daemon not running; starting now at tcp:5037 * が表示され、エラーだと思い込んでいる場合。
  • Studio にバンドルされた platform-tools の更新後、ユーザーに adb server version (XX) doesn't match this client (YY); killing... が表示される場合。
  • ユーザーが詳細な ADB ログ(ADB_TRACE)を有効にしたい、またはベンダーキーを事前インストールした CI ランナーをセットアップしたい場合。
  • ~/.android/adbkey を削除すると、ペアリング済みの他のすべてのデバイスで問題が起きる理由をユーザーが尋ねた場合。
  • Linux でポート 5037 の競合、複数の adb インストール、または libusb 関連のトランスポート障害をデバッグしている場合。

このスキルを使わない場面

  • 接続済みの特定のデバイス(USB の承認、unauthorized、no permissions)のトラブルシューティングをしている場合 — ../../devices/connecting-to-devices/SKILL.md を使用してください。
  • ワイヤレス/Wi-Fi ADB をセットアップしている場合 — ../../devices/connecting-over-wifi/SKILL.md を使用してください。
  • テストのために adb shell am instrument を実行している場合 — ../../tests/running-instrumented-tests-via-adb/SKILL.md を使用してください。

前提条件

  • Android SDK Platform-Tools がインストールされていること(以下のパス解決ルールを参照)。
  • $PATH に adb が設定されたワークステーションへのシェルアクセス。
  • 診断を行う場合:$TMPDIR(macOS/Linux)または %TEMP%(Windows)への書き込み権限。

ワークフロー

  • 1. 3 つの要素から成るモデルを理解します。 developer.android.com/tools/adb(Overview)より:

    • クライアント(adb CLI) — ターミナルから呼び出されます。コマンドをシリアライズし、ローカル TCP ソケット経由でサーバーに送信します。
    • サーバー(adb-server) — ホスト側のバックグラウンドプロセスです。多数のクライアントからのコマンドを多重化し、接続済みのトランスポートを追跡して、トラフィックを adbd に転送します。デフォルトでは localhost の TCP ポート 5037 にバインドします。
    • デーモン(adbd) — デバイス上で動作します。userdebug/eng ビルドでは init によって起動され、user ビルドではシステムによって起動されます。USB または TCP 経由でホストサーバーからコマンドを受け取り、デバイスのユーザー空間で実行します。
  • 2. 暗黙的な start-server の出力を把握します。 新しいシェルで最初の adb コマンドを実行すると、次のように表示されます。

    * daemon not running; starting now at tcp:5037
    * daemon started successfully
    

    これはエラーではなく、情報メッセージです — サーバーが動作していない場合、adb は自動的に起動します。この事実を見落とすと、デバッグに何時間も費やすことになります。

  • 3. ライフサイクルコマンドを適切に使います:

    コマンド効果
    adb start-serverポート 5037 でサーバーが動作していることを確認します。互換性のあるサーバーがすでに動作している場合は何もしません(べき等)。別のプロセスが 5037 にバインドされている場合(または互換性のない古い adb サーバーが動作している場合)、start-server は失敗します — 以下のポート競合のパターンを参照してください。
    adb kill-serverローカルサーバーを終了します。次の adb コマンドで再起動されます。
    adb reconnect「ホスト側から接続を切って、再接続を強制します。」停止した USB トランスポートに役立ちます。
    adb reconnect device「デバイス側から接続を切ります。」adbd に切断と再ハンドシェイクを要求します。
    adb reconnect offline「オフライン/未承認のデバイスをリセットして、再接続を強制します。」問題のあるトランスポートのみを対象にします。
    adb -P PORT ...サーバーポートを上書きします(デフォルトは 5037)。ANDROID_ADB_SERVER_PORT と同じです。

    停止したトランスポートの復旧手順:

    adb reconnect offline
    # 失敗した場合:
    adb kill-server && adb start-server && adb devices
    
  • 4. バイナリのパスを明示的に解決します。 adb は Android SDK Platform-Tools(android_sdk/platform-tools/)に含まれています。実際に読み込まれているものを確認します。

    adb --version
    which -a adb         # 別の場所にあるコピーを確認
    

    adb --version の出力例を読み解くと、次のとおりです。

    Android Debug Bridge version 1.0.41         # ワイヤープロトコルのバージョン(長年安定)
    Version 35.0.2-12147458                      # platform-tools のリリースと Google のビルド番号
    Installed as /opt/homebrew/bin/adb           # OS が解決した実際のファイル
    Running on Darwin 24.6.0 (arm64)
    

    クロス互換性で重要なのはワイヤープロトコルの番号です。クライアントとサーバーのバージョンが一致している必要があります。一致しない場合、最初のコマンドで古いサーバーが終了し、adb server version (XX) doesn't match this client (YY); killing... と表示されます。

  • 5. Android Studio を使う場合は、正規の adb を1つ選びます。 Studio には独自の platform-tools/ が同梱されており、自動更新されます。システムや Homebrew の adb も $PATH にある場合、次の3つの問題が発生する可能性があります。

    1. バージョンの不一致 — どちらから実行しても、最初のコマンドで稼働中のサーバーが終了します。
    2. 競合する2つのサーバーがポート5037を行き来します。
    3. デフォルトのバックエンドの違い(libusb とネイティブ)により、デバイスの検出結果が一致しません。 解決の目安:export PATH="$ANDROID_HOME/platform-tools:$PATH" を設定して CLI と Studio のバージョンを一致させてから、一度 adb kill-server を実行します。
  • 6. 環境変数を確認します(adb help からの原文):

    変数用途
    ADB_TRACEデバッグカテゴリをカンマまたはスペースで区切って指定します。トークン:all,adb,sockets,packets,rwx,usb,sync,sysdeps,transport,jdwp,services,auth,fdevent,shell,incremental
    ADB_VENDOR_KEYSRSA キーファイル/ディレクトリのパスをコロンで区切って指定します。CI で使用すると、「USB デバッグを許可しますか?」というプロンプトを省略できます。
    ANDROID_SERIALデフォルトのデバイスシリアル(-s と同等)。-s を指定すると上書きされます。
    ANDROID_ADB_SERVER_PORTサーバーポートを上書きします(デフォルトは5037)。-P PORT と同等です。
    ADB_LOCAL_TRANSPORT_MAX_PORTエミュレーターの検索対象となる最も大きい奇数ポートです。デフォルトは 5585(エミュレーター16台)です。
    ADB_MDNS_AUTO_CONNECT自動接続の対象となる mDNS サービスタイプを CSV 形式で指定します。デフォルト:adb-tls-connect
    ADB_MDNS_OPENSCREEN1/0。Openscreen の mDNS バックエンドを強制します。ADB v34 以降の Linux/Windows では Openscreen がデフォルトです — 公開ドキュメントの記載は古くなっています。
    ADB_LIBUSB1/0。libusb の USB バックエンドを強制します。
    ADB_BURST_MODE1/0。ACK なしでパケットをパイプライン処理します。実験的機能です。ADB 36.0.0 以降。

    最大限の詳細情報を出力する診断手順:

    ADB_TRACE=all adb devices -l 2>~/adb-trace.log
    

    キーを事前にインストールし、カスタムポートを使う CI ランナー:

    export ADB_VENDOR_KEYS=/etc/adb/ci-key
    export ANDROID_ADB_SERVER_PORT=5038
    export ADB_LOCAL_TRANSPORT_MAX_PORT=5617
    adb start-server
    
  • 7. 問題発生時にサーバーログを確認します。 サーバーは、コマンドごとの ADB_TRACE 出力や logcat とは別に、永続ログを保持しています。

    OSパス
    macOS$TMPDIR/adb.$UID.log(例:/var/folders/.../T/adb.501.log)
    Linux$TMPDIR/adb.$UID.log(例:/tmp/adb.1000.log)
    Windows%TEMP%\adb.log
    便利な手順:
    adb kill-server
    ADB_TRACE=adb,transport,auth adb start-server
    adb devices -l
    ls -lh "$TMPDIR/adb.$UID.log"
    
  • 8. ~/.android/ は重要なデータとして扱います。 RSA キーペアは ~/.android/adbkey(秘密鍵)と ~/.android/adbkey.pub(公開鍵)です。初めて adb を実行したときに生成されます。「USB デバッグを許可しますか?」というダイアログで許可するたびに、この公開鍵がデバイス上の /data/misc/adb/adb_keys に追加されます。ローカルの鍵を削除すると、以前ユーザーが承認したすべてのデバイスで承認が無効になります — 下記の誤った例/正しい例のペアを参照してください。

  • 9. Linux での libusb v36 のリグレッションを背景情報として把握します。 ADB v36.0.0(2025 年 4 月)では、ホットプラグ対応の libusb バックエンドが再設計されました。ADB v36.0.2(2025 年 9 月)では、不安定さを理由に Linux のデフォルト設定から libusb が元に戻されました。特定の platform-tools バージョンに固定された CI ランナーでは、この変更のどちら側に当たるかを把握する必要があります。再現性が重要な場合は、ADB_LIBUSB=0 または =1 でバックエンドを明示的に指定してください。

パターン

パターン:unauthorized または offline デバイスからの復旧 — 間違った方法と正しい方法
# WRONG
rm -rf ~/.android/adbkey ~/.android/adbkey.pub
adb kill-server
adb start-server
# WRONG because: this rotates the host RSA keypair. Every previously authorized
# device now sees an unknown public key and re-prompts the "Allow USB debugging?"
# dialog. CI runners and headless test farms break silently because nobody is
# there to tap "Allow". Worse, the key on /data/misc/adb/adb_keys for the old
# pubkey lingers as orphan data.
# RIGHT
adb reconnect offline           # try a targeted reset first
adb devices                     # confirm the state changed
# if still offline:
adb kill-server && adb start-server
# if still unauthorized: unlock the device, re-tap "Allow USB debugging?"

キーペアを再生成する必要があるのは、実際に紛失したか破損した場合だけです。その場合は、adb keygen ~/.android/adbkey で意図的に再生成し、すべてのデバイスで再認証が必要になることを受け入れます。

パターン:競合する 2 つの adb のインストール — 間違った方法と正しい方法
# WRONG
brew install android-platform-tools     # installs adb to /opt/homebrew/bin
# Studio also auto-updates ~/Library/Android/sdk/platform-tools/adb
# PATH puts /opt/homebrew/bin first.
# Studio's "Run" button uses ~/Library/Android/sdk/platform-tools/adb (different version).
# First command issued by either side prints:
#   adb server version (41) doesn't match this client (40); killing...
# WRONG because: every Run-button invocation kills the server you started,
# yanks transports out from under Logcat, and reissues "daemon not running".
# RIGHT
# Pick one canonical adb. Easiest: prefer Studio's bundled platform-tools.
export ANDROID_HOME="$HOME/Library/Android/sdk"
export PATH="$ANDROID_HOME/platform-tools:$PATH"
adb kill-server                  # clear stale state once
adb --version                    # confirm path matches Studio's
パターン:ポート 5037 がすでに使用中 — 間違った方法と正しい方法
# WRONG
# Some other tool (nc, a proxy, a stale adb-server zombie) is bound to 5037.
adb start-server   # silently fails; subsequent adb devices hangs.
# RIGHT
lsof -nP -iTCP:5037 -sTCP:LISTEN     # find the holder (macOS/Linux)
# kill the squatter, OR run a second adb server on a different port:
ANDROID_ADB_SERVER_PORT=5038 adb start-server
ANDROID_ADB_SERVER_PORT=5038 adb devices

必須ルール

  • 必須: * daemon not running; starting now at tcp:5037 * はエラーではなく、情報メッセージとして扱います。
  • 必須: $PATH の先頭に置く adb バイナリは 1 つにします。Studio に同梱された adb とシステムにインストールされた異なるバージョンの adb を混在させると、サーバーが相互に切り替わり続けます。
  • 必須: マシンを移行する際は、~/.android/adbkey と ~/.android/adbkey.pub を保持します。これらを消去すると、以前に認証済みのすべてのデバイスが気づかないうちに使えなくなります。
  • 禁止: unauthorized または offline デバイスの「修正」として ~/.android/adbkey* を削除しないでください。まず adb reconnect offline を使用します。
  • 禁止: ポート 5037 で 2 つの adb サーバーを同時に実行しないでください。シャーディングされた CI では ANDROID_ADB_SERVER_PORT(または -P PORT)を使用します。
  • 推奨: シェルのプロファイルに export PATH="$ANDROID_HOME/platform-tools:$PATH" を記述し、CLI と Studio が同じバイナリを解決するようにします。
  • 推奨: トランスポートのバグを報告する際は、$TMPDIR/adb.$UID.log(macOS/Linux)または %TEMP%\adb.log(Windows)のサーバーログと、ADB_TRACE=adb,transport,auth を指定した再現手順を添付します。

検証

  • adb --version に表示されるバイナリパスは 1 つであり、which -a adb に PATH 上で隠れているコピーが表示されません。
  • adb start-server は冪等であり、2 回実行しても何も変化しません。
  • adb kill-server && adb start-server && adb devices で、停止したトランスポートが復旧します。
  • ~/.android/adbkey と ~/.android/adbkey.pub が存在し、全ユーザーから読み取り可能な状態ではありません(chmod 600 ~/.android/adbkey)。
  • ADB_TRACE=adb adb devices -l で、エラーのない詳細なトランスポートログが出力されます。
  • 複数の adb サーバーを実行する場合は、それぞれに異なる ANDROID_ADB_SERVER_PORT の値が設定され、lsof -iTCP:5037 ではリスナーがちょうど 1 つ(または 0 個)表示されます。
  • サーバーログファイルが $TMPDIR/adb.$UID.log(macOS/Linux)または %TEMP%\adb.log(Windows)に存在し、最新のものです。

参考資料

  • ADB ユーザーガイド(アーキテクチャとライフサイクル):https://developer.android.com/tools/adb
  • Platform-tools のリリースノート(バージョンごとの差分、libusb のデフォルト設定):https://developer.android.com/tools/releases/platform-tools
  • AOSP adb のマニュアルページ(環境変数に関する正式なリファレンス):https://android.googlesource.com/platform/packages/modules/adb/+/refs/heads/main/docs/user/adb.1.md
  • Studio と AGP を使ったコマンドラインでのテスト:https://developer.android.com/studio/test/command-line
  • 情報源となる調査メモ(CORPUS §I、A1 レポート):
    • tasks/research/A1-adb-architecture-devices.md — 3 つの要素からなるモデル、環境変数の表、v36 での libusb の再変更、ADB v34 以降における Openscreen と Bonjour のデフォルト設定の切り替え、サーバーログのパス、RSA 鍵ペアの取り扱い。
    • docs/CORPUS.md §I.2(3 要素のアーキテクチャ)および §I.10(重要な調査結果:force-stop は pm clear と同じではない、終了コードは -w を指定した場合にのみ得られる)。
  • 関連スキル:
    • 1 台のデバイスに接続する:../../devices/connecting-to-devices/SKILL.md
    • ワイヤレス ADB(Android 11 以降):../../devices/connecting-over-wifi/SKILL.md
    • アプリをインストール・管理する:../../apps/installing-and-managing-apps/SKILL.md
    • am instrument を使ってインストルメンテーションテストを実行する:../../tests/running-instrumented-tests-via-adb/SKILL.md
  • 関連分野の項目:
    • Android で JUnit4 を設定する:../../../jvm-tests/runner/configuring-junit4-on-android/SKILL.md
    • AndroidJUnit4 を使ってインストルメンテーションテストを実行する:../../../instrumentation/runner/running-instrumented-tests-with-androidjunit4/SKILL.md
    • ソースセットの戦略:../../../fundamentals/strategies/organizing-test-source-sets/SKILL.md

コメント