赞
踩
ADB(一)_概况了解
ADB(二)_ADBD_main()函数代码梳理
ADB(三)_ADBD_adbd_main()函数代码梳理
ADB(四)_host端的启动流程代码梳理
ADB(五)_host端adb server相关的代码梳理
ADB(六)_调试ADB(ADB设置自身日志的代码梳理和设置ADB自身日志可见)
ADB(七)_USB连接 (ABD通过USB连接的流程分析)
我们已经知道,ADB经常使用的是USB连接Android开发设备,不过ADB不光只能使用USB来连接设备。它还可以使用WiFi来链接局域网内的设备,就这为某些设备在不方便使用USB的情况提供了巨大的便利。
今天我们主要针对host端和Android设备通过TCP连接的情况来说明,这里就当是大家已经对TCP通信有所了解,至少是知道在开发中的创建一个使用C++实现的C/S的socket通信的简单过程。
首先,我们从Android 设备端说起,因为在这个过程中,我们的Android设备就相当于一个TCP通信的Server,而我们的host端运行的adb就是通信的Client.
在正式对adbd的代码进行梳理之前,我们先对TCP通信编程的步骤进行简单的介绍,
- tcp编程的 server端
- tcp编程的 client 端
在adbd的初始化过程中,就在adbd_main()函数中是有对tcp通信初始化的,我们现在就来看看:
int adbd_main(int server_port) { ... std::string prop_port = android::base::GetProperty("service.adb. tcp.port", ""); if (prop_port.empty()) { prop_port = android::base::GetProperty("persist.adb.tcp.port", ""); } int port; if (sscanf(prop_port.c_str(), "%d", &port) == 1 && port > 0) { setup_port(port); } else if (!is_usb) { setup_port(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); // DEFAULT_ADB_LOCAL_TRANSPORT_PORT =5555; } ... return 0; }
我们可以看到,adbd会首先读取Android的系统属性"service.adb.
tcp.port",这个属性就是用于我们的adbd进行tcp通信的端口设置,如果此端口被设置,我们就会使用设置的端口来初始化我们的tcp,如果没有设置,并且当前不是使用usb通信的,那么就会使用默认的端口DEFAULT_ADB_LOCAL_TRANSPORT_PORT = 5555
来初始化tcp,不管使用设置的端口还是使用默认的端口,接下来都会调用setup_port()函数,我们就到setup_port()函数中一探究竟:
static void setup_port(int port) {
local_init(port);
setup_mdns(port);
}
setup_port()函数内部只要就是调用了两个函数,第一个就是我们的tcp传输设置的local_init()函数.第二个是Android组播域名服务设置的setup_mdns(),我们主要对第一个函数进行说明:
void local_init(int port)
{
...
func = use_qemu_goldfish() ? qemu_socket_thread : server_socket_thread;
debug_name = "server";
...
std::thread(func, port).detach();
}
local_init()函数内部也很简单,首先通过调用use_qemu_goldfish()判断是emulator还是Android设备中,当前我们分析的是Android设备端的代码,所以这里我们需要的func为server_socket_thread(),然后,启动一个新的进程专门用来执行server_socket_thread()函数,并且传入端口号.
接下来我们就要看看server_socket_thread()的实现是怎么样子的:
static void server_socket_thread(int port) { int serverfd, fd; serverfd = -1; for(;;) { if(serverfd == -1) { std::string error; serverfd = network_inaddr_any_server(port, SOCK_STREAM, &error); if(serverfd < 0) { std::this_thread::sleep_for(1s); continue; } close_on_exec(serverfd); } fd = adb_socket_accept(serverfd, nullptr, nullptr); if(fd >= 0) { ... std::string serial = android::base::StringPrintf("host-%d", fd); if (register_socket_transport(fd, serial.c_str(), port, 1) != 0) { adb_close(fd); } } } }
如上代码所示:server_socket_thread()函数主要就是处理tcp通信中server端的初始化,先概括一下函数内部的处理逻辑:
接下来,我们就对上述的三个处理部分进行详细说明:
inline int network_inaddr_any_server(int port, int type, std::string* error) {
return _fd_set_error_str(socket_inaddr_any_server(port, type), error);
}
network_inaddr_any_server()只是调用了socket_inaddr_any_server()来创建socket,socket_inaddr_any_server()函数的具体实现在/system/core/libcutils/
下,如下所示:
/system/core/libcutils/socket_inaddr_any_server_unix.cpp
int socket_inaddr_any_server(int port, int type) { struct sockaddr_in6 addr; int s, n; memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_port = htons(port); addr.sin6_addr = in6addr_any; s = socket(AF_INET6, type, 0); if (s < 0) return -1; n = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof(n)); if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { close(s); return -1; } if (type == SOCK_STREAM) { int ret; ret = listen(s, LISTEN_BACKLOG); if (ret < 0) { close(s); return -1; } } return s; }
在过去server端的socket后,我们就会调用adb_socket_accept()函数来接受请求;其实内部实现也还是调用accept()方法,如下所示:
static __inline__ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen)
{
int fd;
fd = TEMP_FAILURE_RETRY( accept( serverfd, addr, addrlen ) );
if (fd >= 0)
close_on_exec(fd);
return fd;
}
但accept()成功接受到数据,就会返回一个新的fd,这个fd就代表这这个通信连接,我们就可以在对这个fd进行write()/send()操作来发送传输数据,和read()/reve()操作来接收传输数据.
最后,我们会将代表的通信连接的fd传入到register_socket_transport()函数中进行tcp通信事件的注册.
int register_socket_transport(int s, const char* serial, int port, int local) {
atransport* t = new atransport();
...
D("transport: %s init'ing for socket %d, on port %d", serial, s, port);
if (init_socket_transport(t, s, port, local) < 0) {
delete t;
return -1;
}
...
pending_list.push_front(t);
t->serial = strdup(serial);
...
register_transport(t);
return 0;
}
register_socket_transport()函数中,
/* the fdevent select pump is single threaded */
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\n");
}
}
在register_transport,将传进来的transport封装成tmsg,然后通过transport_write_action()函数写入到transport_registration_send中,这个transport_registration_send我们多次遇到,这前面的usb的通信的梳理中已经说明,之后的处理情况就和usb类似,这里就不在赘述.
接下来我们就去看看host算的TCP初始化是怎么样子的.
host端在tcp通信中充当的就是client,client并不需要早早初始化好.一般情况需要等到server端准备就绪后,client才会去连接server并进行通信,
一般情况下,host端的tcp连接不存在的.需要我们手动键入"adb connect ip:port"来手动连接tcp.并且在连接tcp之前会手动设置端口.所以,在host连接TCP是需要先知道目标server的IP_address和端口,才能去连接server端的,我们现在就去看看源码中是怎么实现的.
在终端键入"adb connect ip_address:port"后,首先会有一段adb client和 adb server通信的过程,然后adb server 会对adb client 的请求做出相应的处理,并返回结果在终端上;这里的adb client可以理解为终端,adb server才是实际处理adb命令的真正主体.这里的tcp连接可以理解为是host端的adb server和Android设备端的adbd连接,adb server是tcp通信中的client, adbd 是server
我们就从adb server 连接TCP是开始看起:
host_service_to_socket()函数会帮助adb server处理adb client的请求,我们看当我们此时的请求为"adb connect ip_address:port"时,代码运行的状态:
asocket* host_service_to_socket(const char* name, const char* serial, TransportId transport_id) {
if (!strcmp(name, "track-devices")) {
return create_device_tracker(false);
...
} else if (!strncmp(name, "connect:", 8)) {
char* host = strdup(name + 8);
int fd = create_service_thread("connect", connect_service, host);
if (fd == -1) {
free(host);
}
return create_local_socket(fd);
}
return NULL;
}
我们就根根据上面的代码来看看,首先host_service_to_socket()函数会根据adb client的请求名称来匹配.如果当前的请求就是需要connect
Android设备时:
name
【请求名称】;connect_device
【处理函数】; host
【连接目标】传入.static int create_service_thread(const char* service_name, void (*func)(int, void*), void* cookie) { int s[2]; if (adb_socketpair(s)) { printf("cannot create service socket pair\n"); return -1; } ... stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo))); if (sti == nullptr) { fatal("cannot allocate stinfo"); } sti->service_name = service_name; sti->func = func; sti->cookie = cookie; sti->fd = s[1]; std::thread(service_bootstrap_func, sti).detach(); return s[0]; }
create_service_thread()内部主要是创建stinfo,并进行赋值,然后创建一个新的现成调用service_bootstrap_func()
static void service_bootstrap_func(void* x) {
stinfo* sti = reinterpret_cast<stinfo*>(x);
adb_thread_setname(android::base::StringPrintf("%s svc %d", sti->service_name, sti->fd));
sti->func(sti->fd, sti->cookie);
free(sti);
}
service_bootstrap_func()函数其实也没有做什么其他的,只是执行了一个函数,就是在内部调用了封装在stinfo中的方法connect_service(),
接着进入到connect_service()函数中看看:
static void connect_service(int fd, void* data) {
...
if (!strncmp(host, "emu:", 4)) {
connect_emulator(host + 4, &response);
} else {
connect_device(host, &response);
}
...
adb_close(fd);
}
进入到connect_service中,会有一个判断,就是判断请求连接的目标是emulator还是Android`s device ,由于我们是要连接Android 设备,所以会走到函数中connect_device()中;
void connect_device(const std::string& address, std::string* response) { ... std::string serial; std::string host; int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; if (!android::base::ParseNetAddress(address, &host, &port, &serial, response)) { return; } std::string error; int fd = network_connect(host.c_str(), port, SOCK_STREAM, 10, &error); ... // Send a TCP keepalive ping to the device every second so we can detect disconnects. if (!set_tcp_keepalive(fd, 1)) { D("warning: failed to configure TCP keepalives (%s)", strerror(errno)); } int ret = register_socket_transport(fd, serial.c_str(), port, 0); ... }
这个connect_device()函数主要就是处理TCP 中创建socket,然后注册一个socket传输事件;
inline int network_connect(const std::string& host, int port, int type,
int timeout, std::string* error) {
int getaddrinfo_error = 0;
int fd = socket_network_client_timeout(host.c_str(), port, type, timeout,
&getaddrinfo_error);
...
return fd;
...
}
network_connect()函数是调用socket_network_client_timeout()函数的实现在/system/core/libcutils/socket_network_client_unix.cpp
中,这主要就是对socket编程中的一些操作,然后直接表示连接的fd,我们可以通过这个fd进行write()/send()操作进行数据发送任务,或者进行read()/reve()操作进行数据接受的任务.
-然后,调用register_socket_transport()函数对当前的socket连接注册一个socket传输事件;
int register_socket_transport(int s, const char* serial, int port, int local) {
atransport* t = new atransport();
...
D("transport: %s init'ing for socket %d, on port %d", serial, s, port);
if (init_socket_transport(t, s, port, local) < 0) {
...
pending_list.push_front(t);
t->serial = strdup(serial);
...
register_transport(t);
return 0;
}
这个函数已经多次讲过.就是创建atransport实例,然后赋值初始化,将当前atransport实例装进init_socket_transport中,最后调用register_transport()注册一次传输事件,不论是usb,还是tcp传输,都是调用这个函数进行的:
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\n");
}
}
register_transport()函数的主要逻辑就是:将传进来的transport封装成tmsg,然后通过transport_write_action()函数写入到transport_registration_send中,这个transport_registration_send我们多次遇到,这前面的usb的通信的梳理中已经说明,之后的处理情况就和usb类似,这里也不在赘述.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。