我分析代码的喜欢从main函数开始,因为还不知道代码结构的情况下,这是最直接的方法。所以先看adb.c的main函数

[cpp] view plaincopy
  1. int main(int argc, char **argv)
  2. {
  3. adb_trace_init();
  4. #if ADB_HOST
  5. adb_sysdeps_init();
  6. return adb_commandline(argc - 1, argv + 1);
  7. #else
  8. if((argc > 1) && (!strcmp(argv[1],"recovery"))) {
  9. adb_device_banner = "recovery";
  10. recovery_mode = 1;
  11. }
  12. start_device_log();
  13. return adb_main(0);
  14. #endif
  15. }

宏ADB_HOST用来区别编译adb和adbd,参见上一篇博客http://blog.csdn.net/yinlijun2004/article/details/7008952。

现在用一个常用命令“adb devices”用来捋顺代码流程,adb_trace_init用于log tag初始化,在host端,输入命令"adb devices"之后,进入adb_commandline函数。

adb_commandline首先解析参数,判断有没有指定transport type,即指定与哪个设备通信,emulator 或者 device,指定设备的方法是

[cpp] view plaincopy
  1. -d
  2. -e
  3. -s <serial number>

然后调用adb_set_transport将type,serial赋值给全局变量,

[cpp] view plaincopy
  1. void adb_set_transport(transport_type type, const char* serial)
  2. {
  3. __adb_transport = type;
  4. __adb_serial = serial;
  5. }

这两个全局变量由client保存,将用来告诉server,与何种设备通信,用何种方式传输通信。

接下来,adb_commandline用来判断server守护进程是否已经启动,

[cpp] view plaincopy
  1. if ((argc > 0) && (!strcmp(argv[0],"server"))) {
  2. if (no_daemon || is_daemon) {
  3. r = adb_main(is_daemon);
  4. } else {
  5. r = launch_server();
  6. }
  7. if(r) {
  8. fprintf(stderr,"* could not start server *\n");
  9. }
  10. return r;
  11. }

no_daemon和is_daemon初始化为0,当读到nodaemon参数时,no_daemon为1,这种情况用户显式的不用server进行通信;读到fork-server时is_daemon为1,这是标识当前进程已经是server进程。adb_main函数的is_daemon参数是用来决定是否回送一个应答“OK”给client的。

在这里我们的client第一次执行“adb device”,因此会去启动server,在launch_server中,执行fork()操作,生成一对管道用于父子进程的通信。子进程调用execl,执行adb fork-server server,父进程等待来自子进程的OK应答。

[cpp] view plaincopy
  1. // child side of the fork
  2. // redirect stderr to the pipe
  3. // we use stderr instead of stdout due to stdout's buffering behavior.
  4. adb_close(fd[0]);
  5. dup2(fd[1], STDERR_FILENO);
  6. adb_close(fd[1]);
  7. // child process
  8. int result = execl(path, "adb", "fork-server", "server", NULL);
  9. // this should not return
  10. fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);

这里子进程将STDERR_FILENO重定向到管道的写端fd[1];然后讲管道关闭,这样所有对stderr的操作都将写入父进程,fprintf语句只有在execl执行失败时执行。

[cpp] view plaincopy
  1. // parent side of the fork
  2. char  temp[3];
  3. temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
  4. // wait for the "OK\n" message
  5. adb_close(fd[1]);
  6. int ret = adb_read(fd[0], temp, 3);
  7. adb_close(fd[0]);
  8. if (ret < 0) {
  9. fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", errno);
  10. return -1;
  11. }
  12. if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
  13. fprintf(stderr, "ADB server didn't ACK\n" );
  14. return -1;
  15. }
  16. setsid();

父进程从管道的读端读取子进程发过来的应答,如果非“OK”,代表创建server失败,返回,setsid用于避免父进程退出时子进程也退出,即server真正成为一个守护进程。

花开两朵各表一只,先看fork出来的子进程,即守护进程server,前面说到,它的启动command是adb fork-server server,我们在回到adb的main函数,它用走到了adb_commandline里面来,这时候它解析参数以后,is_daemon就变成1了,因此执行adb_daemon(is_daemon)。

[cpp] view plaincopy
  1. init_transport_registration();
  2. ADB_HOST
  3. HOST = 1;
  4. usb_vendors_init();
  5. usb_init();
  6. local_init(ADB_LOCAL_TRANSPORT_PORT);
  7. if(install_listener("tcp:5037", "*smartsocket*", NULL)) {
  8. exit(1);
  9. }
  10. 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中:

[cpp] view plaincopy
  1. for (;;) {
  2. sleep(5);
  3. kick_disconnected();
  4. scan_usb_devices();
  5. }

通过scan_usb_devices查找用于adb的usb设备

scan_usb_devices->check_device->register_device->register_usb_transport->init_usb_transport->register_transport

在init_usb_transport中,

[cpp] view plaincopy
  1. void init_usb_transport(atransport *t, usb_handle *h, int state)
  2. {
  3. D("transport: usb\n");
  4. t->close = remote_close;
  5. t->kick = remote_kick;
  6. t->read_from_remote = remote_read;
  7. t->write_to_remote = remote_write;
  8. t->sync_token = 1;
  9. t->connection_state = state;
  10. t->type = kTransportUsb;
  11. t->usb = h;
  12. #if ADB_HOST
  13. HOST = 1;
  14. #else
  15. HOST = 0;
  16. #endif
  17. }

可以看到,不管在host端,还是在device端,都会去注册usb的transport

接着然后试图连接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中

[cpp] view plaincopy
  1. int init_socket_transport(atransport *t, int s, int port, int local)
  2. {
  3. int  fail = 0;
  4. t->kick = remote_kick;
  5. t->close = remote_close;
  6. t->read_from_remote = remote_read;
  7. t->write_to_remote = remote_write;
  8. t->sfd = s;
  9. t->sync_token = 1;
  10. t->connection_state = CS_OFFLINE;
  11. t->type = kTransportLocal;
  12. #if ADB_HOST
  13. if (HOST && local) {
  14. adb_mutex_lock( &local_transports_lock );
  15. {
  16. int  index = (port - ADB_LOCAL_TRANSPORT_PORT)/2;
  17. if (!(port & 1) || index < 0 || index >= ADB_LOCAL_TRANSPORT_MAX) {
  18. D("bad local transport port number: %d\n", port);
  19. fail = -1;
  20. }
  21. else if (local_transports[index] != NULL) {
  22. D("local transport for port %d already registered (%p)?\n",
  23. port, local_transports[index]);
  24. fail = -1;
  25. }
  26. else
  27. local_transports[index] = t;
  28. }
  29. adb_mutex_unlock( &local_transports_lock );
  30. }
  31. #endif
  32. return fail;
  33. }

注意看ADB_HOST里面的东西,如果是在HOST端,则将transport添加到列表里面,因为adb device就是从这个列表里面读信息的。

再看register_transport,它将transport信息,一个tmsp的结构体,写入transport_registration_send

[cpp] view plaincopy
  1. struct tmsg
  2. {
  3. atransport *transport;
  4. int         action;
  5. };

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为例,

[cpp] view plaincopy
  1. p = get_apacket();
  2. p->msg.command = A_SYNC;
  3. p->msg.arg0 = 1;
  4. p->msg.arg1 = ++(t->sync_token);
  5. p->msg.magic = A_SYNC ^ 0xffffffff;
  6. if(write_packet(t->fd, &p)) {
  7. put_apacket(p);
  8. D("from_remote: failed to write SYNC apacket to transport %p", t);
  9. goto oops;
  10. }

首先向fd写入一个包含A_SYNC命令的信息包,用于同步,transport_socket的处理回调函数transport_socket_events会执行,继而调用handle_packet处理信息包

[cpp] view plaincopy
  1. case A_SYNC:
  2. if(p->msg.arg0){
  3. send_packet(p, t);
  4. if(HOST) send_connect(t);
  5. } else {
  6. t->connection_state = CS_OFFLINE;
  7. handle_offline(t);
  8. send_packet(p, t);
  9. }
  10. return;

handle_packet判断是A_SYNC同步命令,则同时将信息包发送给远端,并发送一个连接请求给远端,里面包含adb版本,最大载荷等信息。send_package讲信息包写回给transport_socket。

回过头来output_thread线程回收到这些信息包,并将这些包写入远端。

写的太深入了,回到adb_main函数,初始化完可能USB和emulator的transport之后,执行下面这段代码

[cpp] view plaincopy
  1. if(install_listener("tcp:5037", "*smartsocket*", NULL)) {
  2. exit(1);
  3. }

listener是一个很重要的概念,它绑定到一个本地端口,即local socket,负责与client通信(稍候将看到),并且创建一个连接到远端的remote socket,smartsocket是一个特殊的socket,它其实类似一个接线员的角色,它分析后看你要连接到哪个remote socket,然后帮你连上。注意这里的第三个参数NULL,因为接线员还来不及分析你的adb命令参数,不知道你要往哪个remote上连,所以这里为NULL,等分析好了,确定要连接那个remote socket,smartsocket的任务也完成了。

[cpp] view plaincopy
  1. struct alistener
  2. {
  3. alistener *next;
  4. alistener *prev;
  5. fdevent fde;
  6. int fd;
  7. const char *local_name;
  8. const char *connect_to;
  9. atransport *transport;
  10. adisconnect  disconnect;
  11. };

在install_listener里面

[cpp] view plaincopy
  1. l->fd = local_name_to_fd(local_name);
  2. close_on_exec(l->fd);
  3. if(!strcmp(l->connect_to, "*smartsocket*")) {
  4. fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
  5. }

这样,client来消息的时候,就可以调用ss_listener_event_func进行处理了。

接下来,adb_main执行下面代码,

[cpp] view plaincopy
  1. if (is_daemon)
  2. {
  3. // inform our parent that we are up and running.
  4. f defined(HAVE_FORKEXEC)
  5. fprintf(stderr, "OK\n");
  6. if
  7. start_logging();
  8. }

这段代码,告诉父进程adb server已经跑起来了,因此,往stderr里面写一个OK,还记得刚刚server已经将stderr重定向到fd[1]了,所以父进程能接收到这个OK消息。

接下来,server调用fdevent_loop进入事件循环。

[cpp] view plaincopy
  1. for(;;) {
  2. fdevent_process();
  3. while((fde = fdevent_plist_dequeue())) {
  4. unsigned events = fde->events;
  5. fde->events = 0;
  6. fde->state &= (~FDE_PENDING);
  7. dump_fde(fde, "callback");
  8. fde->func(fde->fd, events, fde->arg);
  9. }
  10. }

因此adb是事件驱动型,所有的事件调用fdevent_register进行注册,该函数讲事件保存到全局事件数组fd_table里面,

[cpp] view plaincopy
  1. struct fdevent
  2. {
  3. fdevent *next;
  4. fdevent *prev;
  5. int fd;
  6. unsigned short state;
  7. unsigned short events;
  8. fd_func func;
  9. void *arg;
  10. };

如果有相关事件的到达则调用fun进行处理。

adb_main,即server已经启动完成,再回到client的adb_commandline函数,我们继续adb device命令的解析,

[cpp] view plaincopy
  1. if(!strcmp(argv[0], "devices")) {
  2. char *tmp;
  3. snprintf(buf, sizeof buf, "host:%s", argv[0]);
  4. tmp = adb_query(buf);
  5. if(tmp) {
  6. printf("List of devices attached \n");
  7. printf("%s\n", tmp);
  8. return 0;
  9. } else {
  10. return 1;
  11. }
  12. }

它调用adb_query函数,参数是"host:devices“,它表示需要发往server的请求,这些请求分两种query型和command型,分别调用adb_query和adb_command

[cpp] view plaincopy
  1. char *adb_query(const char *service)
  2. {
  3. char buf[5];
  4. unsigned n;
  5. char *tmp;
  6. D("adb_query: %s\n", service);
  7. int fd = adb_connect(service);
  8. if(readx(fd, buf, 4)) goto oops;
  9. if(readx(fd, tmp, n) == 0) {
  10. }
  11. }

可以看到,它连接到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读取该信息,

[cpp] view plaincopy
  1. fd = adb_socket_accept(_fd, &addr, &alen);
  2. if(fd < 0) return;
  3. adb_socket_setbufsize(fd, CHUNK_SIZE);
  4. s = create_local_socket(fd);
  5. if(s) {
  6. connect_to_smartsocket(s);
  7. return;
  8. }

先看create_local_socket,这个socket负责与client通信,回调处理函数是local_socket_event_func。

[cpp] view plaincopy
  1. asocket *create_local_socket(int fd)
  2. {
  3. asocket *s = calloc(1, sizeof(asocket));
  4. if(s == 0) fatal("cannot allocate socket");
  5. install_local_socket(s);
  6. s->fd = fd;
  7. s->enqueue = local_socket_enqueue;
  8. s->ready = local_socket_ready;
  9. s->close = local_socket_close;
  10. fdevent_install(&s->fde, fd, local_socket_event_func, s);
  11. return s;
  12. }

也就是由local_socket_event_func来读取“host:devices”串,然后调用s->peer->enqueue(s->peer, p);交给对断处理。

那local socket的对端是谁,看connect_to_smartsocket

[cpp] view plaincopy
  1. void connect_to_smartsocket(asocket *s)
  2. {
  3. D("Connecting to smart socket \n");
  4. asocket *ss = create_smart_socket(smart_socket_action);
  5. s->peer = ss;
  6. ss->peer = s;
  7. s->ready(s);
  8. }

这里明白了local socket的对端就是smart socket(remote socket的一种),与local socket交互。

[cpp] view plaincopy
  1. asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act))
  2. {
  3. asocket *s = calloc(1, sizeof(asocket));
  4. if(s == 0) fatal("cannot allocate socket");
  5. s->id = 0;
  6. s->enqueue = smart_socket_enqueue;
  7. s->ready = smart_socket_ready;
  8. s->close = smart_socket_close;
  9. s->extra = action_cb;
  10. return s;
  11. }

这两个socket结对以后,调用local socket的ready回调函数,也就是local_socket_ready

[cpp] view plaincopy
  1. static void local_socket_ready(asocket *s)
  2. {
  3. fdevent_add(&s->fde, FDE_READ);
  4. }

意思是说,我(local socket)已经准备好接收你smart socket发过来的数据了。

那local socket调用的s->peer->enqueue(s->peer, p);就是smart_socket_enqueue

在smart_socket_enqueue中,将刚刚读取到的package插入到package列表中,然后解析service,即发过来的“host:devices”

[cpp] view plaincopy
  1. #if ADB_HOST
  2. service = (char *)p->data + 4;
  3. if(!strncmp(service, "host-serial:", strlen("host-serial:"))) {
  4. char* serial_end;
  5. service += strlen("host-serial:");
  6. // serial number should follow "host:"
  7. serial_end = strchr(service, ':');
  8. if (serial_end) {
  9. *serial_end = 0; // terminate string
  10. serial = service;
  11. service = serial_end + 1;
  12. }
  13. } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) {
  14. ttype = kTransportUsb;
  15. service += strlen("host-usb:");
  16. } else if (!strncmp(service, "host-local:", strlen("host-local:"))) {
  17. ttype = kTransportLocal;
  18. service += strlen("host-local:");
  19. } else if (!strncmp(service, "host:", strlen("host:"))) {
  20. ttype = kTransportAny;
  21. service += strlen("host:");
  22. } else {
  23. service = NULL;
  24. }

这里将client发过来的请求,跟去前缀转化为各种transport type,接着解析具体的service名称,接着,调用handle_host_request处理一些可以立即响应的消息,然后直接返回(adb devices请求就是属于这一种),,否则调用create_host_service_socket创建另外一个service socket作为local service的对段,而smart socket就没什么事了,可以关闭了,如下代码。

[cpp] view plaincopy
  1. s2 = create_host_service_socket(service, serial);
  2. if(s2 == 0) {
  3. D( "SS(%d): couldn't create host service '%s'\n", s->id, service );
  4. sendfailmsg(s->peer->fd, "unknown host service");
  5. goto fail;
  6. }
  7. adb_write(s->peer->fd, "OKAY", 4);
  8. s->peer->ready = local_socket_ready;
  9. s->peer->close = local_socket_close;
  10. s->peer->peer = s2;
  11. s2->peer = s->peer;
  12. s->peer = 0;
  13. D( "SS(%d): okay\n", s->id );
  14. s->close(s);

先来看可以用handle_host_request的部分,处理devices部分请求的代码如下

[cpp] view plaincopy
  1. // return a list of all connected devices
  2. if (!strcmp(service, "devices")) {
  3. char buffer[4096];
  4. memset(buf, 0, sizeof(buf));
  5. memset(buffer, 0, sizeof(buffer));
  6. D("Getting device list \n");
  7. list_transports(buffer, sizeof(buffer));
  8. snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
  9. D("Wrote device list \n");
  10. writex(reply_fd, buf, strlen(buf));
  11. return 0;
  12. }

它讲transport列表里面的信息读取出来,然后写入reply_fd里面,其实这里猜也猜到了,它就是local socket的fd,也就是将信息写入port5037里面,这样我们的client端就能将当前连接的设备信息打印到屏幕上了。

整个过程的如下,

___________________________________
                               |                                                                                |
                               |                          ADB Server (host)                      |
                               |                                                                                 |
        Client   <-------> LocalSocket <-------------> RemoteSocket   |
                               |                                                              ^^                |
                               |___________________________||_______|

||

Android开发工具——ADB(Android Debug Bridge) 二HOST端相关推荐

  1. Android开发工具——ADB(Android Debug Bridge) 一概览

    Android Debug Bridge (adb) 是一个android开发人员必会的多功能的调试工具,确实它的名字一样,它在开发者和目标机器之间,架起了一座bridge. adb的用法很简单,只要 ...

  2. Android开发工具——ADB(Android Debug Bridge) 三DalvikVM之jdwp线程

    jdwp(java debug wire protocol)是dalvik VM的一个线程,可以建立在adb或者tcp基础上,与DDMS或debugger进行通信. 代码位置 dalvik/vm/jd ...

  3. 全网最全Android开发工具,Android开发框架大全

    涵盖Android方方面面的技术, 目前保持更新. 时刻与Android开发流行前沿同步. 目录 一.工具 Android开发工具 在线工具宝典大全 二.框架 *缓存框架* DiskLruCache ...

  4. Android开发工具视频Android 12(S)准备

    Android开发工具视频Android 12(S)准备 适配步骤 下载最新的Android studio工具,点我到官网下载最新的吧! 最新版的studio规定jdk使用必须至少11,所以请移步下载 ...

  5. Android 开发工具集合 - (Android Dev Tools)

    收集整理Android开发所需的Android SDK.开发中用到的工具.Android开发教程.Android设计规范,免费的设计素材等. 欢迎大家推荐自己在Android开发过程中用的好用的工具. ...

  6. Eclipse调试Android开发工具ADB

    要使用adb就要先配置adb的环境变量 http://jingyan.baidu.com/article/17bd8e52f514d985ab2bb800.html 配置完了之后,就可以使用adb的命 ...

  7. 盘点android 开发工具,盘点Android开发者必备的十大开发工具

    Android SDK提供了一系列可帮助开发者设计.创建.测试和发布Android应用程序的强大工具,以下是游戏邦编译developer推荐的10款最常用的开发工具. 1.Eclipse w/ADT ...

  8. Android开发工具之Android Studio----Gradle

    .gradle 文件介绍 一个 Android Studio 项目中,会存在多个 .gradle 文件.其中, project 目录下存在一个 build.gradle 文件和一个 settings. ...

  9. Android开发工具之Android Studio---版本控制SVN使用(二)

    1.从服务器Checkout代码到本地 Checkout入口 或者在Studio界面里 2.配置服务器地址与输入用户密码 会询问是否信任该地址,确定后,弹出用户名帐号,密码界面: 3.选择Checko ...

最新文章

  1. GNN教程:第六篇Spectral算法细节详解!
  2. Ajax.net实现的动态输入项
  3. strings命令(Win、Linux均可适用)
  4. Simulink_Debug的使用
  5. mysql infobright 缺点_infobright、mongodb优劣以及适用范围
  6. java模拟数据库压测_Jmeter压测工具使用总结
  7. netbeans 添加gif图片_史上功能最强最全最好用的GIF动画制作手机app——GIF豆豆——手机ae...
  8. python基本词汇的特点_开课吧老师为你讲解 Python都有什么优点?
  9. oracle dbua 升级,33篇Oracle升级文档大全(收藏版)
  10. 【C#】:浅谈反射机制 【转】
  11. main函数结束后的调用
  12. 了解OutOfMemoryError异常 - 深入Java虚拟机读后总结
  13. labimage 怎样旋转图片_西安匠艺工坊丨别克gl8内饰改装床车图片,精湛工艺,空间力量...
  14. 论网络工程中,系统开发设计可行性研究及市面产品对比!
  15. 【jzoj2173】【DFS】无根树
  16. Excel实现多表关联查询-VLOOKUP
  17. ai如何旋转画布_ai怎么让一个图形等比旋转
  18. deployer部署_使用Deployer轻松部署PHP应用程序
  19. nexus私服传项目-401 Unauthorized
  20. NPDP产品经理小知识:安索夫矩阵

热门文章

  1. JVM中线程是否可以并行执行
  2. React Native填坑之旅--动画篇
  3. Spring注解详解
  4. 电脑图片不显示缩略图怎么办
  5. Linux安装Android开发环境
  6. C#(Winform)实现条码打印
  7. Nginx 反向代理工作原理简介与配置详解
  8. jquery ajax IE
  9. CENTOS安装ElasticSearch
  10. cpu spectre 幽灵 漏洞 突破内存独立性限制 简介