公式ドキュメントからadbコマンドの仕組みを読み解く

# adbコマンドってなに
まずは[公式ドキュメント](https://developer.android.com/tools/adb?hl=ja)を読んでみましょう。
次の通りに説明されています。
> Android Debug Bridge (adb) is a versatile command-line tool that lets you communicate with a device.

> Android Debug Bridge（adb）は、デバイスとの通信を可能にする多機能なコマンドラインツールです。

つまり、**adbというコマンドを通してAndroidデバイスに色々させることができるよ！** というものです。

# adbコマンドでできること！
色々させることができると言いましたが、具体的にどんなことができるのでしょうか。
具体的なシチュエーションと共にいくつか紹介します。

## アプリインストール
アプリのファイル(APK)をインストールすることができます。
サッと手元でインストールして確認したい時に便利です。
```
adb install [apkファイルのパス]
```


## 文字入力
例えばメールアドレス入力欄を実装し、その動作確認を行いたい場合に毎回デバイスにメールアドレスを打ち込むのは面倒かもしれません。

そういった場合にテキスト入力のコマンドを叩くと、デバイス上で文字入力を再現してくれます。

```
adb shell input text "入力したいテキスト"
```

## 充電・給電状態を制御できる
例えばデバイスの充電が20%以下になった時アラートダイアログを出す、などのような機能を実装し、その動作確認を行いたいようなシチュエーションで便利です。

```
// OSの認識するバッテリー残量を20%にする
adb shell dumpsys battery set level 20
```

adbコマンドを使わない場合だととにかく動画を見まくるなどして充電量を20%以下まで減らさないといけませんが、上記のコマンドを使えば一発で充電20%の状態を再現できます。

ちなみに給電していない状態もコマンドで再現させることができます。

```
// OSの認識する給電状態をOFFにする
adb shell dumpsys battery set status 0
```

色々いじって楽しくなっちゃったあとは元に戻しておきましょう。

```
// 設定をリセットするコマンド
adb shell dumpsys battery reset
```

参考：
[Android 5.0 Lolipop で電池残量をエミュレートする](https://qiita.com/tetsukay/items/0e3a3e5297a8be3d8d59)
[Android 疑似的にバッテリーレベルを変更する](https://oc-technote.com/android/android%20%E7%96%91%E4%BC%BC%E7%9A%84%E3%81%AB%E3%83%90%E3%83%83%E3%83%86%E3%83%AA%E3%83%BC%E3%83%AC%E3%83%99%E3%83%AB%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B/)
[Androidエンジニアが知っておくべきコマンド〜adbコマンド編〜](https://developer.dip-net.co.jp/entry/Android%E3%82%A8%E3%83%B3%E3%82%B7%E3%82%99%E3%83%8B%E3%82%A2%E3%81%8B%E3%82%99%E7%9F%A5%E3%81%A3%E3%81%A6%E3%81%8A%E3%81%8F%E3%81%B8%E3%82%99%E3%81%8D%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%88%E3%82%99%E3%80%9Cadb)

# adbコマンドの仕組み

## ざっくり登場人物を把握しよう
[公式ドキュメント](https://developer.android.com/tools/adb?hl=ja)にadbコマンドの仕組みについて解説されています。
まずは、この仕組みを理解するにあたって必要な登場人物を紹介します。

>- A client, which sends commands. The client runs on your development machine. You can invoke a client from a command-line terminal by issuing an adb command.
> - A daemon (adbd), which runs commands on a device. The daemon runs as a background process on each device.
>- A server, which manages communication between the client and the daemon. The server runs as a background process on your development machine.

日本語に訳してみると以下の通りです。
>- コマンドを送信するクライアント。クライアントは開発マシン上で動作する。コマンドライン・ターミナルからadbコマンドを発行することで、クライアントを呼び出すことができます。
>- デバイス上でコマンドを実行するデーモン（adbd）。デーモンは、各デバイス上でバックグラウンド・プロセスとして実行されます。
>- クライアントとデーモン間の通信を管理するサーバー。サーバーは開発マシン上でバックグラウンド・プロセスとして実行されます。

登場人物を超簡潔にまとめてみます。

- **開発マシン**：adbコマンドを実行するパソコンのこと
- **コマンドライン・ターミナル**：adbコマンドをかくところ、開発マシン上にある
- **デバイス**：実機Android端末やエミュレータのこと
- **(adb)クライアント**：コマンドをサーバーに送信するやつ、開発マシン上にある
- **(adb)サーバー**：クライアントから送られてきたadbコマンドを各デバイス上のデーモンに送る
- **デーモン/adbd**：開発マシンから送られてきたコマンドをデバイス上で実行するためにあるやつ

さらに図にまとめてみました。

![スクリーンショット 2024-03-16 22.23.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/906559/4d5b4d0f-f758-d154-a319-dcb6038ca2ac.png)

では一旦このざっくりとした登場人物と流れを頭に入れた状態で、さらに詳しくadbの動作原理にdeep diveしてみます。

:::note info
この図にはまだ説明していないことも含まれています。
疑問に思うところがあっても立ち止まらず、一旦スルーして読み進めてください。
:::


## TCP/IP通信

結論からいうと、adbコマンドの仕組みの正体は **TCP/IP通信** です。

TCP/IPはネットワーク通信の規格の一つで、簡単に説明すると以下のような特徴を持っています。
- データの送り元と送り先それぞれにポートが必要
- サービスによって使うポート番号が決まっている

### データの送り元と送り先それぞれにポートが必要
ポートとは、**通信によって送られてきたデータがネットワークからコンピュータにお邪魔する際に通るドア**のようなものです。

このドアはコンピュータの中にいっぱいあり、各ドアには **ポート番号** という番号が与えられています。

ポート番号は、通信相手となるコンピュータを一意に識別するためにあります。

参考：
[ポート番号 とは](https://web.liveon.ne.jp/glossary/port_number/)
[TCPポート](https://wa3.i-3-i.info/word18121.html)

### サービスによって使うポート番号が決まっている
様々なプロトコルを提供するサービスが、TCP通信を用いてデータのやり取りを行っています。

例えばhttp通信はHTTPプロトコルを提供するサービスを用いた通信です。
そしてhttp通信の場合は80番のポートが使われると決まっています。

同様に、httpsの場合は443番のポート、sshの場合は22番のポートが使われると決まっています。

このように、TCP/IPの中でもさらに**どのサービスを使った通信なのかによって使用されるポート番号は決まっている**のです。

参考：[ポート番号一覧](https://www.vwnet.jp/mura/portnumbers/portf-h.htm)

## How adb worksを読み解いていく
adbの仕組みはTCP/IPであることを念頭におきつつドキュメントの[How adb works](https://developer.android.com/tools/adb#howadbworks)を読んでみます。

How adb worksには次の通りに説明されています。
> When you start an adb client, the client first checks whether there is an adb server process already running. If there isn't, it starts the server process. When the server starts, it binds to local TCP port 5037 and listens for commands sent from adb clients.

> adbクライアントを起動すると、クライアントはまず、adbサーバー・プロセスがすでに実行されているかどうかをチェックする。なければ、サーバー・プロセスを起動する。サーバーが起動すると、ローカルのTCPポート5037にバインドし、adbクライアントから送信されるコマンドをリッスンする。

この部分を詳しく解説していきます。

まず、上記には書かれてありませんがターミナルからadbコマンドを叩くことで、開発マシン（PC）内にあるadbクライアントが呼び出されます。

:::note info
adbコマンドによってadbクライアントが呼ばれることは、How adb worksの章の前にあるadbクライアントの紹介部分で以下のように説明されています。
> You can invoke a client from a command-line terminal by issuing an adb command.
>
> コマンドライン・ターミナルからadbコマンドを発行してクライアントを呼び出すことができる。
:::

そして、起動したクライアントは、サーバーがadb通信を行うために使いたいポートが他の誰かに使われてないかチェックします。  
これはドキュメントでいうところの`adbサーバー・プロセスがすでに実行されているかどうかをチェックする`と説明されているところに該当します。

コンピュータは、**adbサーバーとの通信の場合5037番のポートを使うと決まっています**。
ここでTCP通信の話を思い出してください。
httpの時は80番のポートを使うと決まっていましたよね。
それと同じです。adbの通信の場合は5037番のポートを使うと決まっているのです。

ですので、ここでは

**adbコマンドによって起動されたクライアントは、5037番のポートが他の誰かに使われてないかな〜と確認し、誰も使ってなかったらadbサーバを起動しますよ。**

と言っています。

では続きを読んでいきます。

> The server then sets up connections to all running devices. It locates emulators by scanning odd-numbered ports in the range 5555 to 5585, which is the range used by the first 16 emulators. Where the server finds an adb daemon (adbd), it sets up a connection to that port.
>
> Each emulator uses a pair of sequential ports — an even-numbered port for console connections and an odd-numbered port for adb connections.

> 次にサーバーは、実行中のすべてのデバイスへの接続をセットアップする。最初の16個のエミュレータが使っている5555から5585の範囲で、奇数番号のポートをスキャンしてエミュレータを見つける。サーバーはadbデーモン（adbd）を見つけると、そのポートへの接続をセットアップする。
>
> 各エミュレータは、コンソール接続用に偶数番号のポート、adb接続用に奇数番号のポートという、連続したポートのペアを使用します。

ここでも、もう一度TCP/IP通信の特徴を思い出してみましょう。
[データの送り元と送り先それぞれにポートが必要](https://qiita.com/drafts/4c292d4cb6ad7a96369e/edit#%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E9%80%81%E3%82%8A%E5%85%83%E3%81%A8%E9%80%81%E3%82%8A%E5%85%88%E3%81%9D%E3%82%8C%E3%81%9E%E3%82%8C%E3%81%AB%E3%83%9D%E3%83%BC%E3%83%88%E3%81%8C%E5%BF%85%E8%A6%81)というルールがありましたね。

これは通信相手となるコンピュータ（ドキュメントでいうところのAndroidデバイス）を一意に識別するためでした。

つまり、**5037番のポートがadbコマンドを送る対象となる全ての実機デバイスやエミュレータを一意に認識できるように、それぞれの実機デバイスやエミュレータに固有のポート番号が割り当てられる**ということです。

そして、実機デバイスはサーバープロセスが存在しない（誰にも使われていない）ポート番号が適当に割り当てられるのに対し、**エミュレータの場合は5555番から5585番の範囲で奇数番号のポートを使って識別する**と決まっているようです。

このように接続されているデバイスを全てポート番号によって区別・認識することで、[特定のデバイスにのみadbコマンドを送信する](https://developer.android.com/tools/adb?hl=ja#directingcommands)ということができるようになります。

```
// 接続しているすべてのデバイスとそのポート番号を確認する
$ adb devices
List of devices attached
emulator-5555 device
emulator-5557 device
0.0.0.0:6520  device

// ポート番号5555のエミュレータにアプリをインストールする場合
$ adb -s emulator-5555 install helloWorld.apk

// ポート番号0.0.0.0:6520の実機デバイスにアプリをインストールする場合
$ adb -s 0.0.0.0:6520 install helloWorld.apk
```

How adb worksに説明されている内容は、ざっとこんなもんです。

## adbコマンド自体は実はデバイス上で実行されていない

実はadbコマンドがデバイス上で実行されているわけではないのです。
そんなことHow adb worksのどこにも書いていなかったじゃないかと思うかもしれません。

このドキュメントの冒頭を改めて読み直してみましょう。
以下のような記述があります。

> adb provides access to a Unix shell that you can use to run a variety of commands on a device.

> dbは、デバイス上で様々なコマンドを実行するために使用できるUnixシェルへのアクセスを提供します。

これは超意訳すると、adbコマンドはshellコマンドに変換されてデバイス上で実行されるんだぜ、と言っているのです。

本当かよ、と思うかもしれませんが次のコマンドを見てください。

```
// ステータスバーを隠すadbコマンド
adb shell settings put global policy_control immersive.status=*
```
これはステータスバーを隠して全画面表示にするコマンドです。
ステータスバーというのは充電とかwi-fiとかBluetoothのマークが表示されているところです。

このコマンドに`shell`と入っているのがわかりますね。

このコマンドは実は、「ステータスバーを隠せ」という内容の**shellコマンド**を実行してくださいとadbサーバーにお願いするコマンドなのです。

このコマンドをadbサーバーが受け取り、**shellコマンドに変換してデバイスに送っています**。そして送られてきた**shellコマンドをデバイス内のデーモンが受け取り、実行している**のです。

ここまで踏まえて、もう一度一番最初の図を見て、理解をまとめてみてください。

![スクリーンショット 2024-03-16 22.23.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/906559/bc675efe-0080-5b12-0cd0-b5740d0377d0.png)


# おわり
本記事ではadbコマンドとは何かから始まり、adbコマンドでできることの具体的な事例の紹介や、adbコマンドによる通信の仕組みについても解説しましたが、いかがでしたでしょうか。

本記事が皆様の日々の開発に役立てば幸いに思います。

またこの記事についての感想やご指摘も大歓迎ですので、よろしくお願いします。