2012年01月17日
Androidのadbのメモ(1) adb serverの観察
adbのadb serverの動きをstrace, gdbで観察しました。Android 4.0.3を使用しています。
adbの登場人物
- adb client
- adb server
- adb deamon
上の2つはホスト側で、最後のものはターゲット側で動作します。
Todo: そのうち図を描く。
adb client
adb shell や adb logcat などのadbのコマンドはadb serverを介してターゲットのadbdと通信します。
adb server
adb serverはひとつのホストでひとつだけ動作します。adb serverは必要に応じて起動されますが、起動のみを行う場合は adb start-server を実行します。
adb start-server を実行したときのstraceのログ
一度 adb kill-server でadb serverを止めて、straceのログをファイルに保存するようにしながら、adb start-server を実行します。数秒待ってからコントロールCで止めます。
$ adb kill-server $ strace -ff -o /tmp/adb_strace adb start-server [ Process PID=10474 runs in 32 bit mode. ] * daemon not running. starting it now on port 5037 * * daemon started successfully * ^C$
これで4つのログファイルが生成されました。
10474のプロセスは最初execve "adb start-server" から開始しています。10475のプロセスをforkした後、そのプロセスから"OK"の応答を確認したら"* daemon started successfully *\n"とstdoutに書いて終了しています。
10475のプロセスは最初exeve "adb fork-server server" から開始され、最後はselectで待ち状態になっています。2つのsocketpairと127.0.0.1:5037のポートを待っています。"/tmp/adb.log" にログを書き込みます。
10476は10475のプロセスから生成されたスレッドです。/dev/bun/usb/のディレクトリをポーリングしながら監視しています。
10477も10475のプロセスから生成されたスレッドです。port 5555, 5557, 5559, .. 5585 に接続を試みた後に終了しています。
キーボードからコントロールCを入力してSIGINTのシグナルを発行しましたが、この時点で動作していたのは10475と10476の2つだけでした。
ソースコードと見比べる
このログの結果と system/core/adb のソースコードをつき合わせて推察すると
adb serverをforkしてexecしているのは、adb.c のlaunch-server
10476でUSBのポーリングをしていたスレッドはusb_linux.cのdevice_poll_thread. コメントで /* XXX use inotify */ 確かにポーリングするのは美しくない。ターゲットで/dev/input/以下のデバイスファイルを監視しているところでは確かinotify系のシステムコールが使われていた。
このスレッドはusb_initで生成される。
10477でportをチェックしていたスレッドはtransport_local.cのclient_socket_thread. ここのコメントによれば、すでに動いているemulatorを探すとのこと。このスレッドはlocal_initで生成される。
usb_init, local_initはどちらもadb_mainから呼ばれる。
10475でselectを呼んでいたところは、fdevent.cのfdevent_process
gdbでスタックトレースを確認
ここまであたりをつけてから、gdbで実際にそれを確認してみます。
adb serverを起動してから、そのプロセスにgdbでアタッチしてスタックトレースを確認しました。実際の操作はこちら。gdb_adb_server0.txt
selectで待っているスレッドのスタックトレース
#0 0xf7fdf430 in __kernel_vsyscall () #1 0xf7d9aa81 in select () from /lib32/libc.so.6 #2 0x0805f3ea in fdevent_process () at system/core/adb/fdevent.c:378 #3 0x0805fc95 in fdevent_loop () at system/core/adb/fdevent.c:689 #4 0x0804c37b in adb_main (is_daemon=1, server_port=5037) at system/core/adb/adb.c:979 #5 0x080538b2 in adb_commandline (argc=0, argv=0xffffcfc8) at system/core/adb/commandline.c:915 #6 0x0804b28f in main (argc=3, argv=0xffffcfc4) at system/core/adb/adb.c:1279
USBのポーリングをしているスレッドのスタックトレース
#0 0xf7fdf430 in __kernel_vsyscall () #1 0xf7d6b096 in nanosleep () from /lib32/libc.so.6 #2 0xf7d6aec0 in sleep () from /lib32/libc.so.6 #3 0x0805ed24 in device_poll_thread (unused=0x0) at system/core/adb/usb_linux.c:666 #4 0xf7f6c96e in start_thread () from /lib32/libpthread.so.0 #5 0xf7da1b5e in clone () from /lib32/libc.so.6
emulatorのポートをチェックするスレッドはすぐに終了してしまうので、このプロセスの最初の段階からgdbで追いかける必要があります。gdbでforkされた子プロセスのほうを追いかけるときは、set follow-fork-mode childとします。実際の操作はこちら。gdb_adb_server1.txt
実際にclient_socket_threadに来て、(void) local_connect(port); をループの中で実行したあとにこの関数をぬけていることが確認できました。
これでadb serverの定常状態ではどこを実行しているのかが理解できました。
関連するページ
Android Builders SummitでADBの話をしました
Androidのadbのメモ(1) adb serverの観察
Androidのadbのメモ(5) adb shell lsを実行したときのログ
Androidのemulator consoleに簡単にコマンドを送る方法
Androidのadbのメモ(6) 直接adb serverと通信するrubyスクリプト
Androidのadbのメモ(7) Androidデバイス側でadbを動かす
Androidのadbのメモ(8) Android以外でadbを使う実験
Androidのadbのメモ(9) Android端末同士をadbでつなぐ
Androidのadbのメモ(10) adbdの起動のトリガー
Androidのadbのメモ(11) adbdのsecureモード