fastapple's blog

時系列関係なく、情報を追記・分割・統合などします。ブログに記載の内容のうち、引用ではなく、私自身が記載している文章・コードなどについては、自由にご利用ください。

minimal_adb_fastbootを入れてみた。(そしてpowershellでの、Wi-Fi経由のadb接続の半自動化)


Android SDKを導入しないつもりはないんだが、SSD換装してからAndroid SDKを入れていなかった。で、adbを使いたいので、minimal adb and fastbootというのを入れてみることにした。SDKは、それを使おうと思ったときにまた入れればいいかなと思う。

ここでバージョン1.4.3をダウンロードできた。
devs-lab.com

そしたら、exe形式のインストーラが付いている。いくつか質問がでたが、あまり考えずにyで進む。すぐに完了した。C:\adbのフォルダができ、その下にadb.exeとfastboot.exeが出来る。インストール時に、C:\adbにPATHが通される。

インストールされたらしい。ここから、おもむろにpowershellのコンソールを立ちあげて色々やってみる。

まずはADBのバージョンを確認してみる。

PS C:\adb> adb version
Android Debug Bridge version 1.0.32
Revision eac51f2bb6a8-android
PS C:\adb>

はい。バージョンは、1.0.32のようだ。

続けて、つながってるデバイスの一覧を表示する。

PS C:\adb> adb devices
List of devices attached
* daemon not running. starting it now on port 5037 *
* daemon started successfully *
BH11111111      device

はい。上のデバイスのIDは念のためちょっと変更しました。まず、デーモンが起動し、その後、デバイスがアタッチされる。※もちろん、AndroidデバッグモードでUSB接続すること。わからなければググろう。

さて、デバイスが何台もつながっている場合は別として、1台であれば、次のコマンドでAndroidを再起動できる。

PS C:\adb> adb reboot

非常に簡単。しかし、再起動後、Androidunauthorizedで認識されなくなってしまっている。

PS C:\adb> adb devices
List of devices attached
BH11111111      unauthorized

この場合は、デーモンの再起動をしてやればいい。

PS C:\adb> adb kill-server
PS C:\adb> adb start-server
* daemon not running. starting it now on port 5037 *
* daemon started successfully *
PS C:\adb> adb devices
List of devices attached
BH11111111      device

再起動後、きっちり認識されていることがわかる。よくみると、adb devicesのときにデーモンが起動していなければ起動するようなので、上のadb start-sesrverは冗長かもしれない。

さて、IPアドレスが知りたくなってきた。まずは本題と関係ないが、自分のPCのIPアドレスをしらべる。

PS C:\adb> get-netipaddress

結果、知る必要のないIPアドレスまでたくさんでてきた。が、192.168.0.4というのを見つけた。DHCPとなっている。これが知りたかったアドレスだ。(自分の環境の場合)
ADBで同じようにわらわらでてくるコマンドは以下の通り。

PS C:\adb> adb shell ip addr show

わらわらでてきたのを眺めていると、inet 192.168.0.2/24 brd 192.168.0.255 scope global wlan0というのをみつけた。これでしょう。

上記のコマンドを加工する記事が、以下のQiitaの記事である。
qiita.com

でも今回は、powershellでやりたい。powershellgrep的なコマンドであるselect-stringを駆使する方式をさぐる。select-stringはslsというエイリアスがある。grepというエイリアス名は作らなかったが、それより文字数のすくないslsというを登録してやったぜ!というMSの意地が垣間見えるエイリアス名だ。これを使いましょう。参考にしているQiitaの記事では、127.0.0.1の行をあとから抜く感じにしているが、インターフェース、wlan0を指定する方向にしよう。wlan0の行がほしいIPアドレスであることが前提。でもさ、powershellgrepっぽいことをしたあと、IPの部分だけ抜くには、さらにawkっぽいこともしないといけないんだね。

えらい苦労した。こんな感じだ。

PS C:\adb> ( adb shell ip addr show | sls "wlan0" | sls -pattern "\d+\.\d+\.\d+\.\d+" ) -match "\d+\.\d+\.\d+\.\d+"
True
PS C:\adb> $Matches.Values
192.168.0.2
PS C:\adb>

まずwlan0で切り出して、それだと他の変な行も捕捉されるので、さらにIPアドレス的な正規表現で行を切り出します。そんで、そいつを -match で評価してやると、-matchに指定した正規表現の部分に当たる文字列が、$Matchesというオブジェクトに格納されるんだよね。そして、あとはその$MatchesオブジェクトのValueメンバを.Valuesメソッドで取得する。という理解であっているだろうか。長かった。

せっかくこんなことをしたのは、Wi-Fi経由でadbを使えるようにしたいというのがある。このコマンド使えば、DHCPでもすぐにIPアドレスを調べられるもんね。じゃあ上記のIPアドレスをもつAndroidWi-Fi経由でADB操作可能にするには?

PS C:\adb> adb tcpip 5555
restarting in TCP mode port: 5555
PS C:\adb> adb connect 192.168.0.2
connected to 192.168.0.2:5555
PS C:\adb> adb devices
List of devices attached
BH11111111      device
192.168.0.2:5555        device

5555というのは別に何番ポートでもいいんだけど(5555~5585までの奇数番号でないとだめらしい…。)、これでTCPモードでAndroidをアタッチできるね。もちろんUSBでつないでいるので、そっちもまだ表示されている。それでは、USBケーブルを抜いてから、再度デバイスの一覧を表示してみる。

PS C:\adb> adb devices
List of devices attached
192.168.0.2:5555        device

オッケー。まだある。これだよね。これで、このあと無事Wi-Fi経由でadb rebootによるrebootもできた。ただ、一度rebootしてしまうと、今度はまたUSBケーブルをつないで同じことをしないといけない。これは面倒くさいので、PowerShellのfunctionにして、profileとかから読まれるようにしておく。ここではwadbという短いなまえにしてみた。なんでもいいとは思う。

#USBでつないだAndroidに対して、一気にWi-Fi経由のadbを有効にする
function wadb
{
	adb kill-server
	adb devices
	( adb shell ip addr show | sls "wlan0" | sls -pattern "\d+\.\d+\.\d+\.\d+" ) -match "\d+\.\d+\.\d+\.\d+"
	adb tcpip 5555
	adb connect $Matches.Values
	adb devices
}

やっつけなので、エラー処理とかしてないので注意。ちなみに複数デバイスがリストされた状態でadbコマンドを打つにはadb -s オプションでデバイスを指定する必要がある。以下のような感じ。

PS C:\adb> adb -s BH11111111 reboot

ちなみに一晩おいたあとWi-Fi経由で操作しようとしたらデバイスが一覧から消えていた。なにかをキッカケにはずれてしまったのだろう。よくわからん。

さて、ここまでで結構よくなったけど、USBにAndroidが接続された時点で、上記が実行されれば尚いい。これはWMIを使って、USBがささったことを検知すればいいんだけど結構調べるのに苦労した。ミソとしては、WMIObjectの使い方。USBデバイスが増えるとWMIObjectが増えることになるので、それを利用すればいい。実験してみる。

まずは、USBでAndroidを接続する前のWMIObjectを取得する。win32_pnpentityというのは、pnpentityに関するWMIObjectの集合と考えておく。
$before = get-wmiobject win32_pnpentity
で、USBでAndroidを刺したあと、もう一度実施。$afterへ格納する
$after = get-wmiobject win32_pnpentity
で、これを比べてみる。
diff $before $after
そうすると、おそらく3つくらいのUSBデバイスが増えていることがわかる。

PS C:\adb> diff $before $after                                                                                        
                                                                                                                      
InputObject                                                                                             SideIndicator 
-----------                                                                                             ------------- 
\\DESKTOP-XXX\root\cimv2:Win32_PnPEntity.DeviceID="USB\\VID_0FCE&略" =>            
\\DESKTOP-XXX\root\cimv2:Win32_PnPEntity.DeviceID="USB\\VID_0FCE&略\\BH11111111"              =>            
\\DESKTOP-XXX\root\cimv2:Win32_PnPEntity.DeviceID="USB\\VID_0FCE&略" =>            

この中で、汎用的に使えるものを探していく。一番上にでてきたやつの詳細を知りたい場合は、以下のようにする。

PS C:\adb> get-wmiobject win32_pnpentity -filter "DeviceID='USB\\VID_0FCE&略'"

すると、ずらっと詳細が出力されるが、
Name : ADB Interface
ということで、とてもよいなまえだったりする。このWMIObjectがふえたかどうかをキッカケに判定すればいい。

次のようにする。

$query = "SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_PnPEntity' AND TargetInstance.Name = 'ADB Interface'"
register-wmievent -query $query -sourceidentifier AndroidMonitor -Action { wadb; [console]::Beep(1320,2000) }

調査の賜物なのでちょっと解説。1行目で、WQLというWMI用のクエリ文を$query変数へ代入している。 __InstanceCreationEventというのが便利なやつで、こいつはWMIObjectの生成などを検知することができる。WITHIN 句ではチェックのポーリング間隔を秒数で指定する。だいたい5秒が一般的のようだ。さらにWHERE TargetInstance ISA 'Win32_PnPEntity' の部分で、pnpentityに関するWMIObjectの集合を対象に監視することを指定している。その中で、さらにどういう名前のものに絞って監視するか?というのが、最後のAND TargetInstance.Name = 'ADB Interface'の部分だ。

2行目で、このクエリをWMIイベントとして登録する。-sourceidentifier句でWMIイベントの登録名をつけてやる。なんでもいい。今回は、AndroidMonitorとした。最後に、-Action句で、やりたい内容を記載する。今回は、USBでAndroid機が刺さったら、wadbコマンド(上でつくったやつ)を叩いて、USBでAndroidが刺さったらすぐにWi-Fiでもadbが有効になるようにした。ちなみに、[console]::Beep(1320,2000)というのは、BEEP音を1320Hzで2000ミリ秒間鳴らすということで、こんなこと別にする必要はないのだが、認識したことがわかりやすいように付けている。※ちなみに、デバッグプリント的な感覚で、Action句にecho文をかいていたが、このecho文の出力がコンソールにされなくて、どこがおかしいのかかなり悩んでしまった。どうやら、WMIイベントのAction句でのコンソール出力をするには、工夫がいりそうである。Action自体が走っていないわけではなかった。


ちなみに、登録されているWMIイベントの監視の一覧の表示や登録された監視を削除する場合、それぞれ以下のコマンドで可能だ。

#登録確認
get-eventsubscriber
#削除方法(登録名AndroidMonitorを削除する場合)
unregister-event AndroidMonitor

まとめ

例えば、wadb.ps1という名前でps1スクリプトファイルを以下のような感じで作成し、起動プロファイルなどから、読み込むようにしておけばいいだろう。

wadb.ps1

#USBでつないだAndroidに対して、一気にWi-Fi経由のadbを有効にする
function wadb
{
	adb kill-server
	adb devices
	( adb shell ip addr show | sls "wlan0" | sls -pattern "\d+\.\d+\.\d+\.\d+" ) -match "\d+\.\d+\.\d+\.\d+"
	adb tcpip 5555
	adb connect $Matches.Values
	adb devices
}

#USBでAndroidを接続しただけで、Wi-Fi経由のadbを実行する。
function start-wadb
{

	#get-wmiobject win32_pnpentity -filter "name='ADB Interface'"
	$query = "SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_PnPEntity' AND TargetInstance.Name = 'ADB Interface'"
	$null = register-wmievent -query $query -sourceidentifier AndroidMonitor -Action { wadb; [console]::Beep(1320,2000) }

	#登録確認
	#get-eventsubscriber
	#削除方法
	#unregister-event AndroidMonitor

}

start-wadb

で、あとは、Frepなどを入れることでAndroid自動化の道が開けるかもしれない。

さて、たまにUSBケーブルを抜いたとたんに、折角Wi-Fiでアタッチしたデバイスが表示されなくなるということがあった。
これは、どうやらMTPモードと充電のみのモードを切り替えた際に、デバイスがデタッチされてしまっているようにみえる。
なので、最初から充電のみのモードだけでやっていれば回避できるようだ。

<長い追記>

ここをみると、/system/build.propというのを編集すれば事前のUSB接続が不要になるようだが、rootが必要そうだ。
http://ameliaws09.blogspot.jp/2011/09/wifi2.html

もし、
si env:ADBHOST 192.168.0.2
などのコマンドで、環境変数ADBHOSTに対して、デバイスのIPを先に紐付けていた場合、adb devicesには、

emulator-5554 device

というように表示されるようになる。
すごく大雑把にいうと、こちらの方が、adb killserverとadb start-serverで、(USB再接続なしに)deviceが復活する可能性が高い気がするので、
バイスのIPが固定であるなら、なるべくこちらをつかうことにしたい。

これは、si env:ADBHOST 192.168.0.2のように一手間かけるだけなので、IPを固定にする手間とどちらをとるか、
トレードオフといったところだろう。

ちなみに、gi env:ADBHOSTで現在の環境変数の値を参照出来る。