http://blog.youkuaiyun.com/yinlijun2004/article/details/7008952
Android Debug Bridge (adb) 是一个android开发人员必会的多功能的调试工具,确实它的名字一样,它在开发者和目标机器之间,架起了一座bridge。
adb的用法很简单,只要看完SDK文档关于ADB的部分,(android-sdk-linux_86/docs/guide/developing/tools/adb.html),再稍加练习,基本上就满上就能很熟练的使用了。但是对它的实现感兴趣,最好的途径就是阅读源代码,它android 2.2的位置是:
- system/core/adb
1、 client,运行于开发机器,你可以在shell中调用adb命令,其它的Android工具比如ADT插件和DDMS也包含adb client。
2、 server,作为后台进程同样运行于开发机器,server负责管理client和运行于目标机器或者emulator的守护进程之间的通信,就像一座桥一样。
3、 daemon,运行于目标机或者emulator的守护进程。
上面这段话是SDK里面翻译过来的,我是看adb的代码看的有点迷糊,才去看sdk的,再返回来看代码的时候思路清晰很多。
adb的功能强大,而且支持多平台,但是它的代码却非常精简,只有1.5万行左右,代价就是比较晦涩难懂(看懂以前),代码里面随处可见的各种宏让人眼花缭乱,其中一个重要的宏ADB_HOST,是用来区分本地主机和目标机器的。
client和server调用的是adb
- LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter
- LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE -DSH_HISTORY
- LOCAL_MODULE := adb
而emulator/device调用adbd
- LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
- LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
- LOCAL_MODULE := adbd
1、 在HOST端,adb会fork出一个守护进程(不是adbd),即server,而父进程继续处理client请求,所有的client通过TCP端口号5037进行与server通信,而server创建local socket与remote socket,前者用于和client通信,后者用与远端进行通信,emulator通过TCP,real device则通过usb。
2、在emulator/device端,adbd也创建local socket和remote socket,前者与通过jdwp与Java虚拟机进层通信,后者通过TCP/USB与HOST通信。
因此整个流程应该是这样的,
1、client调用某个adb命令
2、adb进程fork出一个子进程作为server
3、server查找当前连接的emulator/device
4、server接收到来自client请求
5、server处理请求,将本地处理不了的请求发给emulator/device
6、位于emulator/device的adbd拿到请求后交给对应的java虚拟机进程。
7、adbd将结果发回给server
8、server讲结果发回给client
如下图:
___________________________________
| |
| ADB Server (host) |
| |
Debugger <---> LocalSocket <-------------> RemoteSocket |
| ^^ |
|___________________________||_______|
||
Transport ||
(TCP for emulator - USB for device) ||
||
___________________________||_______
| || |
| ADBD (device) || |
| VV |
JDWP <======> LocalSocket <------------> RemoteSocket |
| |
|___________________________________|
我分析代码的喜欢从main函数开始,因为还不知道代码结构的情况下,这是最直接的方法。所以先看adb.c的main函数
- int main(int argc, char **argv)
- {
- adb_trace_init();
- #if ADB_HOST
- adb_sysdeps_init();
- return adb_commandline(argc - 1, argv + 1);
- #else
- if((argc > 1) && (!strcmp(argv[1],"recovery"))) {
- adb_device_banner = "recovery";
- recovery_mode = 1;
- }
- start_device_log();
- return adb_main(0);
- #endif
- }
宏ADB_HOST用来区别编译adb和adbd,参见上一篇博客http://blog.youkuaiyun.com/yinlijun2004/article/details/7008952。
现在用一个常用命令“adb devices”用来捋顺代码流程,adb_trace_init用于log tag初始化,在host端,输入命令"adb devices"之后,进入adb_commandline函数。
adb_commandline首先解析参数,判断有没有指定transport type,即指定与哪个设备通信,emulator 或者 device,指定设备的方法是
- -d
- -e
- -s <serial number>
然后调用adb_set_transport将type,serial赋值给全局变量,
- void adb_set_transport(transport_type type, const char* serial)
- {
- __adb_transport = type;
- __adb_serial = serial;
- }
这两个全局变量由client保存,将用来告诉server,与何种设备通信,用何种方式传输通信。
接下来,adb_commandline用来判断server守护进程是否已经启动,
- if ((argc > 0) && (!strcmp(argv[0],"server"))) {
- if (no_daemon || is_daemon) {
- r = adb_main(is_daemon);
- } else {
- r = launch_server();
- }
- if(r) {
- fprintf(stderr,"* could not start server *\n");
- }
- return r;
- }
在这里我们的client第一次执行“adb device”,因此会去启动server,在launch_server中,执行fork()操作,生成一对管道用于父子进程的通信。子进程调用execl,执行adb fork-server server,父进程等待来自子进程的OK应答。
- // child side of the fork
- // redirect stderr to the pipe
- // we use stderr instead of stdout due to stdout's buffering behavior.
- adb_close(fd[0]);
- dup2(fd[1], STDERR_FILENO);
- adb_close(fd[1]);
- // child process
- int result = execl(path, "adb", "fork-server", "server", NULL);
- // this should not return
- fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
这里子进程将STDERR_FILENO重定向到管道的写端fd[1];然后讲管道关闭,这样所有对stderr的操作都将写入父进程,fprintf语句只有在execl执行失败时执行。
- // parent side of the fork
- char temp[3];
- temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
- // wait for the "OK\n" message
- adb_close(fd[1]);
- int ret = adb_read(fd[0], temp, 3);
- adb_close(fd[0]);
- if (ret < 0) {
- fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", errno);
- return -1;
- }
- if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
- fprintf(stderr, "ADB server didn't ACK\n" );
- return -1;
- }
- setsid();
父进程从管道的读端读取子进程发过来的应答,如果非“OK”,代表创建server失败,返回,setsid用于避免父进程退出时子进程也退出,即server真正成为一个守护进程。
花开两朵各表一只,先看fork出来的子进程,即守护进程server,前面说到,它的启动command是adb fork-server server,我们在回到adb的main函数,它用走到了adb_commandline里面来,这时候它解析参数以后,is_daemon就变成1了,因此执行adb_daemon(is_daemon)。
- init_transport_registration();
- ADB_HOST
- HOST = 1;
- usb_vendors_init();
- usb_init();
- local_init(ADB_LOCAL_TRANSPORT_PORT);
- if(install_listener("tcp:5037", "*smartsocket*", NULL)) {
- exit(1);
- }
- e
adb_daemon首先初始化transport registrantion,等待注册transport时间的到来,transport是用来与远端设备进行通信的,对HOST来说远端设备就是device/emulator,反之亦然。注册信息本身,是用通过一个socket对transport_registration_send,transport_registration_recv来传递的,这属于线程之间的通信。
首先初始化本地USB,监听本地usb的情况,如果有用于ADB的USB设备,则注册一个type为kTransportUsb的transport,
具体调用流程:usb_init->client_socket_thread出一个device_poll_thread线程,在device_poll_thread中:
- for (;;) {
- sleep(5);
- kick_disconnected();
- scan_usb_devices();
- }
scan_usb_devices->check_device->register_device->register_usb_transport->init_usb_transport->register_transport
在init_usb_transport中,
- void init_usb_transport(atransport *t, usb_handle *h, int state)
- {
- D("transport: usb\n");
- 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
- }
接着然后试图连接5555-55585之间的端口,这个时候如果已经有emulator在运行,即调用socket_network_client成功,则注册一个type为kTransportLocal的transport,
调用流程:local_init->adb_thread_create出一个client_socket_thread线程,在client_socket_thread中,尝试连接5555-55585的本地端口
client_socket_thread->socket_loopback_client
如果socket_loopback_client返回值大于0,说明已连接上emulator,
则调用:register_socket_transport->init_socket_transport->register_transport
在init_socket_transport中
- int init_socket_transport(atransport *t, int s, int port, int local)
- {
- int fail = 0;
- t->kick = remote_kick;
- t->close = remote_close;
- t->read_from_remote = remote_read;
- t->write_to_remote = remote_write;
- t->sfd = s;
- t->sync_token = 1;
- t->connection_state = CS_OFFLINE;
- t->type = kTransportLocal;
- #if ADB_HOST
- if (HOST && local) {
- adb_mutex_lock( &local_transports_lock );
- {
- int index = (port - ADB_LOCAL_TRANSPORT_PORT)/2;
- if (!(port & 1) || index < 0 || index >= ADB_LOCAL_TRANSPORT_MAX) {
- D("bad local transport port number: %d\n", port);
- fail = -1;
- }
- else if (local_transports[index] != NULL) {
- D("local transport for port %d already registered (%p)?\n",
- port, local_transports[index]);
- fail = -1;
- }
- else
- local_transports[index] = t;
- }
- adb_mutex_unlock( &local_transports_lock );
- }
- #endif
- return fail;
- }
注意看ADB_HOST里面的东西,如果是在HOST端,则将transport添加到列表里面,因为adb device就是从这个列表里面读信息的。
再看register_transport,它将transport信息,一个tmsp的结构体,写入transport_registration_send
- struct tmsg
- {
- atransport *transport;
- int action;
- };
action为0表示移除该transport,1表示添加。
则接收端的描述符transport_registration_recv会收到对应的信息,它的处理回调函数是transport_registration_func,在transport_registration_func中,首先读取出待注册的transport的地址,在这里创建套接字对,一个是fd,负责从远端读入,或者写入远端。transport_socket负责跟本地(emulator或者device)交互,同时启动两个线程output_thread,调用read_from_remote从远端读入,还有input_thread,调用write_to_remote写入远端。
以output_thread为例,
- 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, &p)) {
- put_apacket(p);
- D("from_remote: failed to write SYNC apacket to transport %p", t);
- goto oops;
- }
首先向fd写入一个包含A_SYNC命令的信息包,用于同步,transport_socket的处理回调函数transport_socket_events会执行,继而调用handle_packet处理信息包
- case A_SYNC:
- if(p->msg.arg0){
- send_packet(p, t);
- if(HOST) send_connect(t);
- } else {
- t->connection_state = CS_OFFLINE;
- handle_offline(t);
- send_packet(p, t);
- }
- return;
handle_packet判断是A_SYNC同步命令,则同时将信息包发送给远端,并发送一个连接请求给远端,里面包含adb版本,最大载荷等信息。send_package讲信息包写回给transport_socket。
回过头来output_thread线程回收到这些信息包,并将这些包写入远端。
写的太深入了,回到adb_main函数,初始化完可能USB和emulator的transport之后,执行下面这段代码
- if(install_listener("tcp:5037", "*smartsocket*", NULL)) {
- exit(1);
- }
listener是一个很重要的概念,它绑定到一个本地端口,即local socket,负责与client通信(稍候将看到),并且创建一个连接到远端的remote socket,smartsocket是一个特殊的socket,它其实类似一个接线员的角色,它分析后看你要连接到哪个remote socket,然后帮你连上。注意这里的第三个参数NULL,因为接线员还来不及分析你的adb命令参数,不知道你要往哪个remote上连,所以这里为NULL,等分析好了,确定要连接那个remote socket,smartsocket的任务也完成了。
- struct alistener
- {
- alistener *next;
- alistener *prev;
- fdevent fde;
- int fd;
- const char *local_name;
- const char *connect_to;
- atransport *transport;
- adisconnect disconnect;
- };
- l->fd = local_name_to_fd(local_name);
- close_on_exec(l->fd);
- if(!strcmp(l->connect_to, "*smartsocket*")) {
- fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
- }
接下来,adb_main执行下面代码,
- if (is_daemon)
- {
- // inform our parent that we are up and running.
- f defined(HAVE_FORKEXEC)
- fprintf(stderr, "OK\n");
- if
- start_logging();
- }
接下来,server调用fdevent_loop进入事件循环。
- for(;;) {
- fdevent_process();
- while((fde = fdevent_plist_dequeue())) {
- unsigned events = fde->events;
- fde->events = 0;
- fde->state &= (~FDE_PENDING);
- dump_fde(fde, "callback");
- fde->func(fde->fd, events, fde->arg);
- }
- }
- struct fdevent
- {
- fdevent *next;
- fdevent *prev;
- int fd;
- unsigned short state;
- unsigned short events;
- fd_func func;
- void *arg;
- };
如果有相关事件的到达则调用fun进行处理。
adb_main,即server已经启动完成,再回到client的adb_commandline函数,我们继续adb device命令的解析,
- if(!strcmp(argv[0], "devices")) {
- char *tmp;
- snprintf(buf, sizeof buf, "host:%s", argv[0]);
- tmp = adb_query(buf);
- if(tmp) {
- printf("List of devices attached \n");
- printf("%s\n", tmp);
- return 0;
- } else {
- return 1;
- }
- }
它调用adb_query函数,参数是"host:devices“,它表示需要发往server的请求,这些请求分两种query型和command型,分别调用adb_query和adb_command
- char *adb_query(const char *service)
- {
- char buf[5];
- unsigned n;
- char *tmp;
- D("adb_query: %s\n", service);
- int fd = adb_connect(service);
- if(readx(fd, buf, 4)) goto oops;
- if(readx(fd, tmp, n) == 0) {
- }
- }
可以看到,它连接到server,返回一个描述符,然后直接从该描述符里面读取结果就可以了。看起来很简单,adb_connect把下面很复杂的东西都包装起来了。
adb_connect包装了_adb_connect函数,包装了一些adb server是否已经成功启动,查询adb server版本信息的工作,在_adb_connect中
调用socket_loopback_client(ADB_PORT, SOCK_STREAM);尝试连接ADB_PORT,也就是5037,记住刚才adb server已经调用socket_loopback_server(port, SOCK_STREAM);这样,client和service之间就可以开始通信了。请求信息“host:devices”将写入adb server,来看adb server的处理函数ss_listener_event_func
ss_listener_event_func创建一个local socket读取该信息,
- fd = adb_socket_accept(_fd, &addr, &alen);
- if(fd < 0) return;
- adb_socket_setbufsize(fd, CHUNK_SIZE);
- s = create_local_socket(fd);
- if(s) {
- connect_to_smartsocket(s);
- return;
- }
先看create_local_socket,这个socket负责与client通信,回调处理函数是local_socket_event_func。
- asocket *create_local_socket(int fd)
- {
- asocket *s = calloc(1, sizeof(asocket));
- if(s == 0) fatal("cannot allocate socket");
- install_local_socket(s);
- s->fd = fd;
- s->enqueue = local_socket_enqueue;
- s->ready = local_socket_ready;
- s->close = local_socket_close;
- fdevent_install(&s->fde, fd, local_socket_event_func, s);
- return s;
- }
也就是由local_socket_event_func来读取“host:devices”串,然后调用s->peer->enqueue(s->peer, p);交给对断处理。
那local socket的对端是谁,看connect_to_smartsocket
- void connect_to_smartsocket(asocket *s)
- {
- D("Connecting to smart socket \n");
- asocket *ss = create_smart_socket(smart_socket_action);
- s->peer = ss;
- ss->peer = s;
- s->ready(s);
- }
这里明白了local socket的对端就是smart socket(remote socket的一种),与local socket交互。
- asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act))
- {
- asocket *s = calloc(1, sizeof(asocket));
- if(s == 0) fatal("cannot allocate socket");
- s->id = 0;
- s->enqueue = smart_socket_enqueue;
- s->ready = smart_socket_ready;
- s->close = smart_socket_close;
- s->extra = action_cb;
- return s;
- }
这两个socket结对以后,调用local socket的ready回调函数,也就是local_socket_ready
- static void local_socket_ready(asocket *s)
- {
- fdevent_add(&s->fde, FDE_READ);
- }
那local socket调用的s->peer->enqueue(s->peer, p);就是smart_socket_enqueue
在smart_socket_enqueue中,将刚刚读取到的package插入到package列表中,然后解析service,即发过来的“host:devices”
- #if ADB_HOST
- service = (char *)p->data + 4;
- if(!strncmp(service, "host-serial:", strlen("host-serial:"))) {
- char* serial_end;
- service += strlen("host-serial:");
- // serial number should follow "host:"
- serial_end = strchr(service, ':');
- if (serial_end) {
- *serial_end = 0; // terminate string
- serial = service;
- service = serial_end + 1;
- }
- } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) {
- ttype = kTransportUsb;
- service += strlen("host-usb:");
- } else if (!strncmp(service, "host-local:", strlen("host-local:"))) {
- ttype = kTransportLocal;
- service += strlen("host-local:");
- } else if (!strncmp(service, "host:", strlen("host:"))) {
- ttype = kTransportAny;
- service += strlen("host:");
- } else {
- service = NULL;
- }
- s2 = create_host_service_socket(service, serial);
- if(s2 == 0) {
- D( "SS(%d): couldn't create host service '%s'\n", s->id, service );
- sendfailmsg(s->peer->fd, "unknown host service");
- goto fail;
- }
- adb_write(s->peer->fd, "OKAY", 4);
- s->peer->ready = local_socket_ready;
- s->peer->close = local_socket_close;
- s->peer->peer = s2;
- s2->peer = s->peer;
- s->peer = 0;
- D( "SS(%d): okay\n", s->id );
- s->close(s);
先来看可以用handle_host_request的部分,处理devices部分请求的代码如下
- // return a list of all connected devices
- if (!strcmp(service, "devices")) {
- char buffer[4096];
- memset(buf, 0, sizeof(buf));
- memset(buffer, 0, sizeof(buffer));
- D("Getting device list \n");
- list_transports(buffer, sizeof(buffer));
- snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
- D("Wrote device list \n");
- writex(reply_fd, buf, strlen(buf));
- return 0;
- }
它讲transport列表里面的信息读取出来,然后写入reply_fd里面,其实这里猜也猜到了,它就是local socket的fd,也就是将信息写入port5037里面,这样我们的client端就能将当前连接的设备信息打印到屏幕上了。
整个过程的如下,
___________________________________
| |
| ADB Server (host) |
| |
Client <-------> LocalSocket <-------------> RemoteSocket |
| ^^ |
|___________________________||_______|
||
jdwp(java debug wire protocol)是dalvik VM的一个线程,可以建立在adb或者tcp基础上,与DDMS或debugger进行通信。
代码位置
dalvik/vm/jdwp
frameworks/base/core/jni
java虚拟机初始化后,或者每次“zygote fork”出一个新进程时,会启动jdwp线程。关于虚拟机的初始化参考我的博客http://blog.youkuaiyun.com/yinlijun2004/article/details/6065979。
主要调用路径:dvmStartup->dvmInitAfterZygote->dvmInitJDWP
dvmInitJDWP线程启动之前会可能会阻塞VM,依赖于配置suspend=n,所以dvmInitJDWP放在dvmStartup的最后步骤来执行。dvmInitJDWP首先判断jdwp是否允许并且已经配置好,如果是,则读取jdwp的配置,这些配置是AndroidRuntime::startVm中配置的,
- /* enable debugging; set suspend=y to pause during VM init */
- #ifdef HAVE_ANDROID_OS
- /* use android ADB transport */
- opt.optionString =
- "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";
- #else
- /* use TCP socket; address=0 means start at port 8000 and probe up */
- LOGI("Using TCP socket for JDWP\n");
- opt.optionString =
- "-agentlib:jdwp=transport=dt_socket,suspend=n,server=y,address=0";
- #endif
这些配置保存在虚拟机全局变量gDvm中,gDvm是DvmGlobals变量,需要读取的配置包括transport,负责与ADB或TCP交换数据,
- if (gDvm.jdwpAllowed && gDvm.jdwpConfigured) {
- JdwpStartupParams params;
- if (gDvm.jdwpHost != NULL) {
- if (strlen(gDvm.jdwpHost) >= sizeof(params.host)-1) {
- LOGE("ERROR: hostname too long: '%s'\n", gDvm.jdwpHost);
- return false;
- }
- strcpy(params.host, gDvm.jdwpHost);
- } else {
- params.host[0] = '\0';
- }
- params.transport = gDvm.jdwpTransport;
- params.server = gDvm.jdwpServer;
- params.suspend = gDvm.jdwpSuspend;
- params.port = gDvm.jdwpPort;
- gDvm.jdwpState = dvmJdwpStartup(¶ms);
- if (gDvm.jdwpState == NULL) {
- LOGW("WARNING: debugger thread failed to initialize\n");
- /* TODO: ignore? fail? need to mimic "expected" behavior */
- }
- }
其中gDvm.jdwpAllowed在dalvik_system_Zygote.c中配置
gDvm.jdwpAllowed = ((debugFlags & DEBUG_ENABLE_DEBUGGER) != 0);
gDvm.jdwpConfigured在调用dvmStartup->dvmProcessOptions->parseJdwpOptions时配置。
参考上面的参数,对照Init.c的handleJdwpOption的函数,可知gDvm.jdwpTransport为kJdwpTransportAndroidAdb,gDvm.jdwpServer为true,gDvm.jdwpSuspend为false,gDvm.jdwpPort没有配置,这些参数保存到dvmJdwpStartup的参数里面。
再看dvmJdwpStartup,在里面,创建jdwp相关的结构体JdwpState,是先初始化一些互斥锁和条件锁,初始化transport
- switch (pParams->transport) {
- case kJdwpTransportSocket:
- // LOGD("prepping for JDWP over TCP\n");
- state->transport = dvmJdwpSocketTransport();
- break;
- case kJdwpTransportAndroidAdb:
- // LOGD("prepping for JDWP over ADB\n");
- state->transport = dvmJdwpAndroidAdbTransport();
- /* TODO */
- break;
- default:
- LOGE("Unknown transport %d\n", pParams->transport);
- assert(false);
- goto fail;
- }
由上文可知,这里执行dvmJdwpAndroidAdbTransport,返回一个JdwpTransport的接口指针结构体,这些在ADB和TCP上各有一套实现方法,对应不同类型的transport。
- typedef struct JdwpTransport {
- bool (*startup)(struct JdwpState* state, const JdwpStartupParams* pParams);
- bool (*accept)(struct JdwpState* state);
- bool (*establish)(struct JdwpState* state);
- void (*close)(struct JdwpState* state);
- void (*shutdown)(struct JdwpState* state);
- void (*free)(struct JdwpState* state);
- bool (*isConnected)(struct JdwpState* state);
- bool (*awaitingHandshake)(struct JdwpState* state);
- bool (*processIncoming)(struct JdwpState* state);
- bool (*sendRequest)(struct JdwpState* state, ExpandBuf* pReq);
- bool (*sendBufferedRequest)(struct JdwpState* state,
- const struct iovec* iov, int iovcnt);
- } JdwpTransport;
然后,调用dvmJdwpNetStartup,在里面实际执行JdwpTransport在ADB上的startup接口。在JdwpADB.c的start函数内,初始化与adb有关的一些网络参数,比如socket名称
- #define kJdwpControlName "\0jdwp-control"
这个socket名称已经被adbd绑定。
然后,调用dvmCreateInternalThread启动jdwp线程,dvmCreateInternalThread是pthread_create的包装,最终线程的执行函数是jdwpThreadStart,
在jdwpThreadStart中,会调用dvmJdwpEstablishConnection与adbd建立连接。在dvmJdwpEstablishConnection中,会一直等待与adbd的连接,直到连接成功
- int ret = connect(netState->controlSock,
- &netState->controlAddr.controlAddrPlain,
- netState->controlAddrLen);
如果执行connect成功,则将pid发送给adbd,
- snprintf(buff, sizeof(buff), "%04x", getpid());
- buff[4] = 0;
- do {
- ret = send( netState->controlSock, buff, 4, 0 );
- } while (ret < 0 && errno == EINTR);
接着,jdwp等待adbd返回一个客户文件描述符,
- netState->clientSock = receiveClientFd(netState);
如果返回成功,这个clientSock将用来直接与debugger或DDMS通信。可以想象,这里的clientSock就是TCP:5037对应的client描述符。
这样acceptConnection也成功返回了,回到jdwp线程处理函数jdwpThreadStart,接着进入一个while循环从adbd读取并处理握手消息。
- while (true) {
- // sanity check -- shouldn't happen?
- if (dvmThreadSelf()->status != THREAD_VMWAIT) {
- LOGE("JDWP thread no longer in VMWAIT (now %d); resetting\n",
- dvmThreadSelf()->status);
- dvmDbgThreadWaiting();
- }
- if (!dvmJdwpProcessIncoming(state)) /* blocking read */
- break;
- if (first && !dvmJdwpAwaitingHandshake(state)) {
- /* handshake worked, tell the interpreter that we're active */
- first = false;
- /* set thread ID; requires object registry to be active */
- state->debugThreadId = dvmDbgGetThreadSelfId();
- /* wake anybody who's waiting for us */
- dvmDbgLockMutex(&state->attachLock);
- dvmDbgCondBroadcast(&state->attachCond);
- dvmDbgUnlockMutex(&state->attachLock);
- }
- }
先看dvmJdwpProcessIncoming函数,在里面执行select,可能会收到三种数据,对应三个文件描述被set,其中wakeFds是定时唤醒作用,丢弃,controlSock的set也忽略,因为不需要接收第二个debugger文件描述服。之后收到debugger的数据,也就是clientSock被set的时候调用read读取数据,如果不一个单位数据包长度,则dvmJdwpProcessIncoming返回。否则,调用handlePacket处理数据包,
handlePacket->dvmJdwpProcessRequest->write
handlePacket从讲包中的数据还原成JdwpReqHeader和数据起始指针,送给dvmJdwpProcessRequest处理,dvmJdwpProcessRequest从gHandlerMap调出处理函数func
- typedef struct {
- u1 cmdSet;
- u1 cmd;
- JdwpRequestHandler func;
- const char* descr;
- } JdwpHandlerMap;
write讲结果,写回给adbd,adbd处理之后在发回给HOST端。
这篇博客梳理Device端adbd是如何运作的,最好有前面博客的预习,1、Android开发工具——ADB(Android Debug Bridge) <一>概览,2、Android开发工具——ADB(Android Debug Bridge) <二>HOST端,3、Android开发工具——ADB(Android Debug Bridge) <三>DalvikVM之jdwp线程。
在adbd起来时,也会监听TCP:5037端口(好像没有使用),扫描当前USB设备,注册好usb transport,等待远端的连接,同时启动jdwp服务,与虚拟机的jdwp线程进行握手通信。
先看HOST和DEVICE的连接过程。
HOST首先发出connect请求,数据包内容如下
- apacket *cp = get_apacket();
- cp->msg.command = A_CNXN;
- cp->msg.arg0 = A_VERSION;
- cp->msg.arg1 = MAX_PAYLOAD;
- snprintf((char*) cp->data, sizeof cp->data, "%s::",
- HOST ? "host" : adb_device_banner);
HOST收到DEVICE的connect请求后,解析,
- if(!strcmp(type, "device")) {
- D("setting connection_state to CS_DEVICE\n");
- t->connection_state = CS_DEVICE;
- update_transports();
- return;
- }
因此到此时为止,HOST和DEVICE已经处于online状态,准备好其它的通信了。
这里以adb jdwp命令为例说明,jdwp是获取当前device中注册了jdwp传输的进程列表。看看jdwp是怎么从HOST到DEVICE端的。
- if (!strcmp(argv[0], "jdwp")) {
- int fd = adb_connect("jdwp");
- if (fd >= 0) {
- read_and_dump(fd);
- adb_close(fd);
- return 0;
- } else {
- fprintf(stderr, "error: %s\n", adb_error());
- return -1;
- }
- }
这是调用adb_connect,然后直接从里面读取结果,在发送“jdwp”之前,先调用
- int fd = _adb_connect("host:version");
校验,adb版本。_adb_connect中,如果碰到“host”打头的请求,则切换transport。
- if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd)) {
- return -1;
- }
在switch_socket_transport中,如果刚开始在adb命令中未指定serial 和transport type, 则,将“host:transport-any‘发往5037端口
- if(writex(fd, tmp, 4) || writex(fd, service, len)) {
- strcpy(__adb_error, "write failure during connection");
- adb_close(fd);
- return -1;
- }
等待返回一个“OKAY”
- if(adb_status(fd)) {
- adb_close(fd);
- return -1;
- }
- int adb_status(int fd)
- {
- unsigned char buf[5];
- unsigned len;
- if(!memcmp(buf, "OKAY", 4)) {
- return 0;
- }
- }
TCP:5037的另一端,也就是service,它的读写处理函数是local_socket_event_func,将"host:transport-any"读取出来,调用s->peer->enqueue(s->peer, p);也就是smart_socket_enqueue进行处理,
smart_socket_enqueue->handle_host_request->acquire_one_transport处理host:transport-any"请求。
在acquire_one_transport中,会查询当前的transport_list,取出符合用户要求的transport,如果有多个,则返回错误。然后,将该transport赋给当前的socket。往TCP:5037回一个“OKAY”
- transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
- if (transport) {
- s->transport = transport;
- adb_write(reply_fd, "OKAY", 4);
- } else {
- sendfailmsg(reply_fd, error_string);
- }
由此可知,切换transport后,才将"host:version"请求发送到TCP:5037端口,同样经过smart_socket_enqueue->handle_host_request函数,执行下面语句
- // returns our value for ADB_SERVER_VERSION
- if (!strcmp(service, "version")) {
- char version[12];
- snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
- snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version);
- writex(reply_fd, buf, strlen(buf));
- return 0;
- }
再来看“jdwp”请求,smart_socket_enqueue->handle_host_request,handle_host_request发现处理不了,所以回到smart_socket_enqueue继续执行下面语句,
- s->peer->ready = local_socket_ready_notify;
- s->peer->close = local_socket_close_notify;
- s->peer->peer = 0;
- /* give him our transport and upref it */
- s->peer->transport = s->transport;
- connect_to_remote(s->peer, (char*) (p->data + 4));
- s->peer = 0;
- s->close(s);
这段语句,将smart soeckt关闭,然后将transport交给local socket,这样,connect_to_remote的参数就是local socket, “jdwp”,在connect_to_remote
- p->msg.command = A_OPEN;
- p->msg.arg0 = s->id;
- p->msg.data_length = len;
- strcpy((char*) p->data, destination);
- send_packet(p, s->transport);
把A_OPEN命令发给DEVICE端,id是socket的唯一标识,在初始化local socket的时候就确定,便于远端回复数据过来时,在socket list中能查找到该socket进行处理
- void install_local_socket(asocket *s)
- {
- adb_mutex_lock(&socket_list_lock);
- s->id = local_socket_next_id++;
- insert_local_socket(s, &local_socket_list);
- adb_mutex_unlock(&socket_list_lock);
- }
- for(;;) {
- p = get_apacket();
- if(t->read_from_remote(p, t) == 0){
- D("from_remote: received remote packet, sending to transport %p\n",
- t);
- if(write_packet(t->fd, &p)){
- put_apacket(p);
- D("from_remote: failed to write apacket to transport %p", t);
- goto oops;
- }
- } else {
- D("from_remote: remote read failed for transport %p\n", p);
- put_apacket(p);
- break;
- }
- }
create_local_service_socket->create_jdwp_service_socket,回调:
- s->socket.ready = jdwp_socket_ready;
- s->socket.enqueue = jdwp_socket_enqueue;
- s->socket.close = jdwp_socket_close;
- s->pass = 0;
create_remote_socket的回调:这里的id是HOST端的local socket的id。
- s->id = id;
- s->enqueue = remote_socket_enqueue;
- s->ready = remote_socket_ready;
- s->close = remote_socket_close;
- s->transport = t;
然后调用
- send_ready(s->id, s->peer->id, t);
- s->ready(s);
这里的s->id是DEVICE端local socket的id, s->peer->是HOST端的local socket的id。
- static void send_ready(unsigned local, unsigned remote, atransport *t)
- {
- D("Calling send_ready \n");
- apacket *p = get_apacket();
- p->msg.command = A_OKAY;
- p->msg.arg0 = local;
- p->msg.arg1 = remote;
- send_packet(p, t);
- }
这样,表示HOST端发送的A_OPEN命令成功了,DEVICE端的output_thread接收到以后,
- case A_OKAY: /* READY(local-id, remote-id, "") */
- if(t->connection_state != CS_OFFLINE) {
- if((s = find_local_socket(p->msg.arg1))) {
- if(s->peer == 0) {
- s->peer = create_remote_socket(p->msg.arg0, t);
- s->peer->peer = s;
- }
- s->ready(s);
- }
- }
- break;
根据id,找回local socket,同时创建remote socket。
前面看到,DEVICE端创建好local socket和remote socket之后,除了往HOST发一个OKAY,还调用
- s->ready(s);
这里的s是local jdwp service socket,来看它的ready函数jdwp_socket_ready
- apacket* p = get_apacket();
- p->len = jdwp_process_list((char*)p->data, MAX_PAYLOAD);
- peer->enqueue(peer, p);
- jdwp->pass = 1;
将jdwp服务中的进程号,写入packet,调用remote socket的enqueue,也就是remote_socket_enqueue
- static int remote_socket_enqueue(asocket *s, apacket *p)
- {
- D("Calling remote_socket_enqueue\n");
- p->msg.command = A_WRTE;
- p->msg.arg0 = s->peer->id;
- p->msg.arg1 = s->id;
- p->msg.data_length = p->len;
- send_packet(p, s->transport);
- return 1;
- }
它进程信息,写入transport,HOST的output_thread收到以后
- case A_WRTE:
- if(t->connection_state != CS_OFFLINE) {
- if((s = find_local_socket(p->msg.arg1))) {
- unsigned rid = p->msg.arg0;
- p->len = p->msg.data_length;
- if(s->enqueue(s, p) == 0) {
- D("Enqueue the socket\n");
- send_ready(s->id, rid, t);
- }
- return;
- }
- }
- break;
- int r = adb_write(s->fd, p->ptr, p->len);
- [yinlijun@localhost adb]$ adb jdwp
- 228
- 277
- 111
- 176
- 185
- 188
- 180
- 208
- 212
- 330
- 339
- 351
- 361
- 370
- 378
- 407
- 416
- 427
- 438
- 446
- 455