android6.0 adbd深さ分析(一)adb駆動初期化、adbノードスレッド読み出し
adbdは前に一度見たことがありますが、コードが複雑すぎると感じました.それから、adb client adb server adbdが織り交ぜて疲れているように見えます.最近、プロジェクトはそれを大体見終わって、整理して、adbdから多くのことを学ぶことができるような気がします.ここでまとめて、adbdのコードです.
私は分析しただけで分かったので,すべてがそろっているはずがない.また,主に通信面や命令処理などに重点を置いている.
一、adb主関数
まず、主関数を見てみましょう.
ADB_HOSTマクロはPC上なのか携帯電話上なのかを直接区別するために使用され、pc上の直接はadb_を使用します.commandline関数は様々なコマンドを処理して、私たちは見ないで、私たちは主にadbdを分析します.
adbdは主にadb_を呼び出したmainメソッド
SOcketpairが呼び出され、一端にデータがあるとtransportが呼び出されます.registration_func関数、transport_を見てみましょう.registration_recvはデータが来るのでtransportも見てみましょうregistration_sendはいつデータを送信しますか.
二、usb、adbの駆動初期化
次にadb駆動ノードの初期化を見てみましょう
上のadbを見続けますmainのusb_init関数:
こちらで呼び出したのはusbですadb_init()
この関数でandroidを開きます.adb_enableノードはenableadb usbにすぎず、その後スレッドを開いてusbを呼び出します.adb_open_thread
この関数では主にadbノードを開きregister_を呼び出すusb_Transport関数はusb転送を登録します.
この関数はinit_を先に呼び出しましたusb_Transport関数はatransportを初期化しusb_handleも与えましたregisterを見てみましょうTransport関数.
この関数はatransportをカプセル化して伝わりましたtransport_を見てみましょうwrite_Action関数、最初のパラメータtransport_を見てみましょう.registration_sendは私たちの前のsockpairのsend端です
transport_write_Action関数はtransportをtransport_に送ることですregistration_recv端子.
これによりadb駆動ノードが読み出されると、駆動伝送されたtransportがtransport_に伝達されるregistration_recv端子、次にこのコードを見てみましょう.
三、オープンスレッドadbデータを受け入れる
前に分析した関数を覚えていますか?transport_registration_recvにデータがある場合はtransport_が呼び出されますregistration_func関数
まずtransportを呼び出しましたread_アクションでtransport_を読み込むregistration_recvのデータ、つまり以前のtransport_registration_sendからのadb駆動ノードのデータ.そしてtという変数に保存します.
次にtransportを見てみましょうregistration_func関数の別のコード
上のコードはsocketpairのペアを確立し、2つのスレッドを開きました.この2つのスレッドを見てみましょう.
3.1 output_thread adbドライバデータの受信
まずアウトプットを見てみましょうthreadこのスレッド:
このスレッドは主にadb駆動からデータを読み出し、socketpairの一端にadb駆動から読み出したデータを書き込む.
まずreadを見てみましょうfrom_remoteという関数は、adb駆動からデータを読み出す方法について説明します.
前にregister_usb_Transportの時にinitを呼び出しましたusb_transportは、transportのいくつかの関数などを初期化します.
前にusb_adb_Init関数には次のコードがあります.
したがって、最後にreadが呼び出されたのはusb_です.adb_read関数、すなわちadb駆動の内容を読む.
usb_adb_read関数はadb_を呼び出すことですreadはadb駆動データを読み出し、adb_readとは、h->fdからadb駆動データを読み出すことである.このh->fdは前のusb_ですadb_open_thread関数で/dev/android_を開くadb(adb駆動ノード).
3.2 output_threadデータ送信後、データ処理
output_threadでadb駆動のデータを読み込んだらwrite_を呼び出すpacket(t->fd,t->serial,&p)関数は、データネットワークsocketpairの片側を書きます.
これにより、socketpairの反対側にデータがあり、反対側にtransport_が呼び出されます.socket_events関数はデータを処理します
四、まとめ
主にadb駆動ノードの初期化を解析し,駆動ノードのオンに成功するとスレッドをオンにしてadb駆動ノードの内容を読み出す.
データの処理部分は次のブログで分析を続けます.
私は分析しただけで分かったので,すべてがそろっているはずがない.また,主に通信面や命令処理などに重点を置いている.
一、adb主関数
まず、主関数を見てみましょう.
int main(int argc, char **argv) {
#if ADB_HOST
// adb client/server
adb_sysdeps_init();
adb_trace_init();
D("Handling commandline()
");
return adb_commandline(argc - 1, const_cast(argv + 1));
#else
// adbd
while (true) {
static struct option opts[] = {
{"root_seclabel", required_argument, nullptr, 's'},
{"device_banner", required_argument, nullptr, 'b'},
{"version", no_argument, nullptr, 'v'},
};
int option_index = 0;
int c = getopt_long(argc, argv, "", opts, &option_index);
if (c == -1)
break;
switch (c) {
case 's':
root_seclabel = optarg;
break;
case 'b':
adb_device_banner = optarg;
break;
case 'v':
printf("Android Debug Bridge Daemon version %d.%d.%d %s
",
ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION,
ADB_REVISION);
return 0;
default:
break;
}
}
close_stdin();
adb_trace_init();
/* If adbd runs inside the emulator this will enable adb tracing via
* adb-debug qemud service in the emulator. */
adb_qemu_trace_init();
D("Handling main()
");
return adb_main(0, DEFAULT_ADB_PORT);
#endif
ADB_HOSTマクロはPC上なのか携帯電話上なのかを直接区別するために使用され、pc上の直接はadb_を使用します.commandline関数は様々なコマンドを処理して、私たちは見ないで、私たちは主にadbdを分析します.
adbdは主にadb_を呼び出したmainメソッド
int adb_main(int is_daemon, int server_port)
{
#if !ADB_HOST
int port;
char value[PROPERTY_VALUE_MAX];
umask(000);
#endif
atexit(adb_cleanup);
#if defined(_WIN32)
SetConsoleCtrlHandler( ctrlc_handler, TRUE );
#else
// No SIGCHLD. Let the service subproc handle its children.
signal(SIGPIPE, SIG_IGN);
#endif
init_transport_registration();
#if ADB_HOST
HOST = 1;
#ifdef WORKAROUND_BUG6558362
if(is_daemon) adb_set_affinity();
#endif
usb_init();
adbを見てmainコードinit_を見てみましょうtransport_registration関数void init_transport_registration(void)
{
int s[2];
if(adb_socketpair(s)){//socketpair
fatal_errno("cannot open transport registration socketpair");
}
D("socketpair: (%d,%d)", s[0], s[1]);
transport_registration_send = s[0];
transport_registration_recv = s[1];
fdevent_install(&transport_registration_fde,
transport_registration_recv,
transport_registration_func,
0);
fdevent_set(&transport_registration_fde, FDE_READ);
}
SOcketpairが呼び出され、一端にデータがあるとtransportが呼び出されます.registration_func関数、transport_を見てみましょう.registration_recvはデータが来るのでtransportも見てみましょうregistration_sendはいつデータを送信しますか.
二、usb、adbの駆動初期化
次にadb駆動ノードの初期化を見てみましょう
上のadbを見続けますmainのusb_init関数:
void usb_init()
{
if (access(USB_FFS_ADB_EP0, F_OK) == 0)
usb_ffs_init();
else
usb_adb_init();
}
こちらで呼び出したのはusbですadb_init()
static void usb_adb_init()
{
usb_handle* h = reinterpret_cast(calloc(1, sizeof(usb_handle)));
if (h == nullptr) fatal("couldn't allocate usb_handle");
h->write = usb_adb_write;
h->read = usb_adb_read;
h->kick = usb_adb_kick;
h->fd = -1;
adb_cond_init(&h->notify, 0);
adb_mutex_init(&h->lock, 0);
// Open the file /dev/android_adb_enable to trigger
// the enabling of the adb USB function in the kernel.
// We never touch this file again - just leave it open
// indefinitely so the kernel will know when we are running
// and when we are not.
int fd = unix_open("/dev/android_adb_enable", O_RDWR);// android_adb_enable enableadb usb
if (fd < 0) {
D("failed to open /dev/android_adb_enable
");
} else {
close_on_exec(fd);
}
D("[ usb_init - starting thread ]
");
adb_thread_t tid;
if(adb_thread_create(&tid, usb_adb_open_thread, h)){
fatal_errno("cannot create usb thread");
}
}
この関数でandroidを開きます.adb_enableノードはenableadb usbにすぎず、その後スレッドを開いてusbを呼び出します.adb_open_thread
static void *usb_adb_open_thread(void *x)
{
struct usb_handle *usb = (struct usb_handle *)x;
int fd;
while (true) {
// wait until the USB device needs opening
adb_mutex_lock(&usb->lock);
while (usb->fd != -1)
adb_cond_wait(&usb->notify, &usb->lock);
adb_mutex_unlock(&usb->lock);
D("[ usb_thread - opening device ]
");
do {
/* XXX use inotify? */
fd = unix_open("/dev/android_adb", O_RDWR);// adb
if (fd < 0) {
// to support older kernels
fd = unix_open("/dev/android", O_RDWR);
}
if (fd < 0) {
adb_sleep_ms(1000);
}
} while (fd < 0);
close_on_exec(fd);
usb->fd = fd;// usb
D("[ usb_thread - registering device ]
");
register_usb_transport(usb, 0, 0, 1);
}
// never gets here
return 0;
}
この関数では主にadbノードを開きregister_を呼び出すusb_Transport関数はusb転送を登録します.
void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable)
{
atransport *t = reinterpret_cast(calloc(1, sizeof(atransport)));
if (t == nullptr) fatal("cannot allocate USB atransport");
D("transport: %p init'ing for usb_handle %p (sn='%s')
", t, usb,
serial ? serial : "");
init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
if(serial) {
t->serial = strdup(serial);
}
if(devpath) {
t->devpath = strdup(devpath);
}
adb_mutex_lock(&transport_lock);
t->next = &pending_list;
t->prev = pending_list.prev;
t->next->prev = t;
t->prev->next = t;
adb_mutex_unlock(&transport_lock);
register_transport(t);
}
この関数はinit_を先に呼び出しましたusb_Transport関数はatransportを初期化しusb_handleも与えましたregisterを見てみましょうTransport関数.
static void register_transport(atransport *transport)
{
tmsg m;
m.transport = transport;
m.action = 1;
D("transport: %s registered
", transport->serial);
if(transport_write_action(transport_registration_send, &m)) {
fatal_errno("cannot write transport registration socket
");
}
}
この関数はatransportをカプセル化して伝わりましたtransport_を見てみましょうwrite_Action関数、最初のパラメータtransport_を見てみましょう.registration_sendは私たちの前のsockpairのsend端です
transport_write_Action関数はtransportをtransport_に送ることですregistration_recv端子.
static int
transport_write_action(int fd, struct tmsg* m)
{
char *p = (char*)m;
int len = sizeof(*m);
int r;
while(len > 0) {
r = adb_write(fd, p, len);
if(r > 0) {
len -= r;
p += r;
} else {
if((r < 0) && (errno == EINTR)) continue;
D("transport_write_action: on fd %d, error %d: %s
",
fd, errno, strerror(errno));
#if !ADB_HOST
__android_log_print(ANDROID_LOG_INFO, __FUNCTION__,
"transport_write_action: on fd %d, error %d: %s
",
fd, errno, strerror(errno));
#endif
return -1;
}
}
return 0;
}
これによりadb駆動ノードが読み出されると、駆動伝送されたtransportがtransport_に伝達されるregistration_recv端子、次にこのコードを見てみましょう.
三、オープンスレッドadbデータを受け入れる
前に分析した関数を覚えていますか?transport_registration_recvにデータがある場合はtransport_が呼び出されますregistration_func関数
void init_transport_registration(void)
{
int s[2];
if(adb_socketpair(s)){
fatal_errno("cannot open transport registration socketpair");
}
D("socketpair: (%d,%d)", s[0], s[1]);
transport_registration_send = s[0];
transport_registration_recv = s[1];
fdevent_install(&transport_registration_fde,
transport_registration_recv,
transport_registration_func,
0);
fdevent_set(&transport_registration_fde, FDE_READ);
}
transportを見てみましょうregistration_funcという関数static void transport_registration_func(int _fd, unsigned ev, void *data)
{
tmsg m;
adb_thread_t output_thread_ptr;
adb_thread_t input_thread_ptr;
int s[2];
atransport *t;
if(!(ev & FDE_READ)) {
return;
}
if(transport_read_action(_fd, &m)) {
fatal_errno("cannot read transport registration socket");
}
t = m.transport;
まずtransportを呼び出しましたread_アクションでtransport_を読み込むregistration_recvのデータ、つまり以前のtransport_registration_sendからのadb駆動ノードのデータ.そしてtという変数に保存します.
次にtransportを見てみましょうregistration_func関数の別のコード
if (t->connection_state != CS_NOPERM) {
/* initial references are the two threads */
t->ref_count = 2;
if(adb_socketpair(s)) {// socketpair
fatal_errno("cannot open transport socketpair");
}
D("transport: %s socketpair: (%d,%d) starting", t->serial, s[0], s[1]);
t->transport_socket = s[0];
t->fd = s[1];
fdevent_install(&(t->transport_fde),
t->transport_socket,// transport_socket , transport_socket_events
transport_socket_events,
t);
fdevent_set(&(t->transport_fde), FDE_READ);
if(adb_thread_create(&input_thread_ptr, input_thread, t)){
fatal_errno("cannot create input thread");
}
if(adb_thread_create(&output_thread_ptr, output_thread, t)){
fatal_errno("cannot create output thread");
}
}
上のコードはsocketpairのペアを確立し、2つのスレッドを開きました.この2つのスレッドを見てみましょう.
3.1 output_thread adbドライバデータの受信
まずアウトプットを見てみましょうthreadこのスレッド:
static void *output_thread(void *_t)
{
atransport *t = reinterpret_cast(_t);
apacket *p;
D("%s: starting transport output thread on fd %d, SYNC online (%d)
",
t->serial, t->fd, t->sync_token + 1);
p = get_apacket();
p->msg.command = A_SYNC;
p->msg.arg0 = 1;
p->msg.arg1 = ++(t->sync_token);
p->msg.magic = A_SYNC ^ 0xffffffff;
if(write_packet(t->fd, t->serial, &p)) {
put_apacket(p);
D("%s: failed to write SYNC packet
", t->serial);
goto oops;
}
D("%s: data pump started
", t->serial);
for(;;) {
p = get_apacket();//
if(t->read_from_remote(p, t) == 0){// adb
if(write_packet(t->fd, t->serial, &p)){// socketpair
put_apacket(p);
D("%s: failed to write apacket to transport
", t->serial);
goto oops;
}
} else {
D("%s: remote read failed for transport
", t->serial);
put_apacket(p);// , ,
break;
}
}
D("%s: SYNC offline for transport
", t->serial);
p = get_apacket();
p->msg.command = A_SYNC;// adb
p->msg.arg0 = 0;
p->msg.arg1 = 0;
p->msg.magic = A_SYNC ^ 0xffffffff;
if(write_packet(t->fd, t->serial, &p)) {
put_apacket(p);
D("%s: failed to write SYNC apacket to transport", t->serial);
}
oops:
D("%s: transport output thread is exiting
", t->serial);
kick_transport(t);
transport_unref(t);
return 0;
}
このスレッドは主にadb駆動からデータを読み出し、socketpairの一端にadb駆動から読み出したデータを書き込む.
まずreadを見てみましょうfrom_remoteという関数は、adb駆動からデータを読み出す方法について説明します.
前にregister_usb_Transportの時にinitを呼び出しましたusb_transportは、transportのいくつかの関数などを初期化します.
void init_usb_transport(atransport *t, usb_handle *h, int state)
{
D("transport: usb
");
t->close = remote_close;
t->kick = remote_kick;
t->read_from_remote = remote_read;
t->write_to_remote = remote_write;
t->sync_token = 1;
t->connection_state = state;
t->type = kTransportUsb;
t->usb = h;
#if ADB_HOST
HOST = 1;
#else
HOST = 0;
#endif
}
read_from_remote関数はremote_ですread関数:static int remote_read(apacket *p, atransport *t)
{
if(usb_read(t->usb, &p->msg, sizeof(amessage))){// adb
D("remote usb: read terminated (message)
");
return -1;
}
if(check_header(p)) {//
D("remote usb: check_header failed
");
return -1;
}
if(p->msg.data_length) {
if(usb_read(t->usb, p->data, p->msg.data_length)){
D("remote usb: terminated (data)
");
return -1;
}
}
if(check_data(p)) {//
D("remote usb: check_data failed
");
return -1;
}
return 0;
}
前にusb_adb_Init関数には次のコードがあります.
static void usb_adb_init()
{
usb_handle* h = reinterpret_cast(calloc(1, sizeof(usb_handle)));
if (h == nullptr) fatal("couldn't allocate usb_handle");
h->write = usb_adb_write;
h->read = usb_adb_read;
h->kick = usb_adb_kick;
h->fd = -1;
したがって、最後にreadが呼び出されたのはusb_です.adb_read関数、すなわちadb駆動の内容を読む.
usb_adb_read関数はadb_を呼び出すことですreadはadb駆動データを読み出し、adb_readとは、h->fdからadb駆動データを読み出すことである.このh->fdは前のusb_ですadb_open_thread関数で/dev/android_を開くadb(adb駆動ノード).
static int usb_adb_read(usb_handle *h, void *data, int len)
{
int n;
D("about to read (fd=%d, len=%d)
", h->fd, len);
n = adb_read(h->fd, data, len);
if(n != len) {
D("ERROR: fd = %d, n = %d, errno = %d (%s)
",
h->fd, n, errno, strerror(errno));
for (int i = 0; i < n; i++) {
char print = (char)*((char*)data + i);
LOG("%x ", print);
}
return -1;
}
D("[ done fd=%d ]
", h->fd);
return 0;
}
3.2 output_threadデータ送信後、データ処理
output_threadでadb駆動のデータを読み込んだらwrite_を呼び出すpacket(t->fd,t->serial,&p)関数は、データネットワークsocketpairの片側を書きます.
これにより、socketpairの反対側にデータがあり、反対側にtransport_が呼び出されます.socket_events関数はデータを処理します
static void transport_socket_events(int fd, unsigned events, void *_t)
{
atransport *t = reinterpret_cast(_t);
D("transport_socket_events(fd=%d, events=%04x,...)
", fd, events);
if(events & FDE_READ){
apacket *p = 0;
if(read_packet(fd, t->serial, &p)){
D("%s: failed to read packet from transport socket on fd %d
", t->serial, fd);
} else {
handle_packet(p, (atransport *) _t);
}
}
}
四、まとめ
主にadb駆動ノードの初期化を解析し,駆動ノードのオンに成功するとスレッドをオンにしてadb駆動ノードの内容を読み出す.
データの処理部分は次のブログで分析を続けます.