adb

来源:互联网 发布:宁波行知中等职业学校 编辑:程序博客网 时间:2024/06/06 10:27

android adb 概述

android adb的代码分为两部分:
kernel层的代码在如下路径:
drivers/usb/gadget/f_adb.c
drivers/usb/gadget/android.c
他吐给上层应用的是如下的设备节点:/dev/android_adb
应用层的代码在如下路径:
system/core/adb目录
针对device,该目录编译的输出是adbd


控制台上手动启动平板adb的功能的方法如下:

step1:在init.rc中申明adbd服务
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. <span style="font-size: 18px;">service adbd /sbin/adbd  
  2.     class core  
  3. #    socket adbd stream 660 system system  
  4.     disabled  
  5. #    seclabel u:r:adbd:s0</span>  
step2:init.rc中通过属性变量来触发usb adb功能
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. on property:sys.usb.config=adb  
  2.     write /sys/class/android_usb/android0/enable 0  
  3.     write /sys/class/android_usb/android0/idVendor 18d1  
  4.     write /sys/class/android_usb/android0/idProduct D002  
  5.     write /sys/class/android_usb/android0/functions ${sys.usb.config}  
  6.     write /sys/class/android_usb/android0/enable 1  
  7.     start adbd  
  8.     setprop sys.usb.state ${sys.usb.config}  

step3: init.rc中disable adb
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. <span style="font-size: 18px;">on property:sys.usb.config=none  
  2.     stop adbd  
  3.     write /sys/class/android_usb/android0/enable 0  
  4.     write /sys/class/android_usb/android0/bDeviceClass 0  
  5.     setprop sys.usb.state ${sys.usb.config}</span>  

step4:在控制台上执行命令setprop sys.usb.config adb 将使能adb功能
         在控制台上执行命令setprop sys.usb.confignone关闭adb功能    

以上默认是通过usb来实现adb的功能,其实也可以通过网络来实现adb的功能;方法如下:
device端:
step1:  setprop service.adb.tcp.port 5555
step2:  setprop sys.usb.confignone
    setprop sys.usb.config adb
step3: 通过执行netstat -tna命令确认5555端口被监听。#以上操作如下图

pc端:
step1:  adb kill-server
step2: adb connect 10.1.32.4  #这里的地址就是平板的地址
step3: adb devices
step3: adb shell  #以上操作如下图

adb 出问题时的调试方法:
方法一:通过bus hound工具来抓pc跟device之间的usb 包的通讯。前提是需要对usb adb的命令包格式很熟悉。
方法二: 由属性变量:persist.adb.trace_mask来控制adb的log输出级别。其输出的log信息将被重定向到/data/adb/目录下的文件中。
具体源代码,请查看:/system/core/adb/adb.c(start_device_log函数), system/core/adb/adb.h(adb_trace_mask,AdbTrace)
方法三:由于方法二有一定的局限性,他是将printf的输出重定向到/data/adb/xxxx.txt文件中,这样很多的后台服务的打印信息是打印不出来的。
因为他的输入,输出被重定向到pty/pts或是pipe或是socket pair上了。所以我们的方法就是修改/system/core/adb/adb.h文件中的#  define  D(...) 宏,使其的打印输出到logcat中。方法如下:
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. /* you must define TRACE_TAG before using this macro */  
  2.  define  D(...)                                      \  
  3.       do {                                           \  
  4.           if (ADB_TRACING) {                         \  
  5.               int save_errno = errno;                \  
  6.               adb_mutex_lock(&D_lock);               \  
  7.               __android_log_print(3,"adb""%s::%s():",           \  
  8.                       __FILE__, __FUNCTION__);       \  
  9.               errno = save_errno;                    \  
  10.               __android_log_print(3,"adb", __VA_ARGS__ );         \  
  11.               fflush(stderr);                        \  
  12.               adb_mutex_unlock(&D_lock);             \  
  13.               errno = save_errno;                    \  
  14.          }                                           \  
  15.       } while (0)  
上面的__android_log_print函数需要依赖头文件#include <android/log.h>和动态库:liblog ,动态库的链接方法:
LOCAL_STATIC_LIBRARIES +=  liblog    #交叉编译时使用
LOCAL_LDLIBS += -llog  #编译主机端的adb时使用
为了查看更多地log,可以将persist.adb.trace_mask设置为0x3ff。


一下将从几个专题来研究devices端的adbd后台的工作内容:


专题一:#######adb 从pc端发送命令到device端的流程:#############

output_thread(system/core/adb/transport.c)

get_apacket(分配一个apacket包所需的内存)
t->read_from_remote(p, t)
write_packet(t->fd, t->serial, &p) //注意该函数,真正只是发送包的开始地址,并不是发送整个包的内容数据
|
|t->fd对应的pipe另一端为: t->transport_socket ,而该句柄的接收处理函数为: transport_socket_events
|
\|/
transport_socket_events
read_packet(fd, t->serial, &p)) //fd即为t->transport_socket
handle_packet(p, (atransport *) _t); //该函数根据从pc端发送过来的命令,做相应的处理的。


注意:
read_from_remote/write_to_remote  对应从/dev/android_adb读取和写入数据



专题二:###############adb 从device端发送响应到pc端的流程:#########
send_packet(apacket *p, atransport *t)//函数用来向pc端发送数据(通过usb或以太网)
write_packet(t->transport_socket, t->serial, &p)
 |
 |t->fd对应的pipe另一端为: t->transport_socket ,该socket对是在 transport_registration_func 函数中申明  |的。
\|/
input_thread
read_packet(t->fd, t->serial, &p)
t->write_to_remote(p, t);
 |
 |
 |对应于usb而言
\|/
remote_write //发送命令和数据到pc端
usb_write(t->usb, &p->msg, sizeof(amessage)) // 发送命令
usb_write(t->usb, &p->data, size) //发送数据

专题三:pc跟device之间传输adb数据包的格式
他们之间的数据传输单元称为:struct apacket,具体结构如下:
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. <span style="font-size: 18px;">     struct apacket  
  2.         {  
  3.             apacket *next;   //adb package队列,可以对还未来得及处理的adb数据包进行入队列  
  4.   
  5.             unsigned len;  
  6.             unsigned char *ptr;  
  7.   
  8.             amessage msg;     //adb数据包对应的命令头,对应一个IN或OUT传输  
  9.             unsigned char data[MAX_PAYLOAD]; //命令包对应的数据部分,对应一个IN或OUT传输  
  10.         };</span>  
一个 apacket 包传输分为两个阶段:
第一个阶段是:命令传输阶段(required),存储在 apacket.msg 中
第二个阶段是:数据传输阶段(optional),存储在 apacket.data 中
adb支持的命令如下:
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. <span style="font-size: 18px;">         #define A_SYNC 0x434e5953   //该命令用于adb push/pull命令  
  2.             #define A_CNXN 0x4e584e43   //该命令用于pc和device进行adb连接时使用,该命令带有数据阶段  
  3.             #define A_OPEN 0x4e45504f   //用于在devices端开启一个服务,譬如adb shell,adb logcat,adb remount等shell命令  
  4.             #define A_OKAY 0x59414b4f   //表示接收ok,该命令没有数据阶段  
  5.             #define A_CLSE 0x45534c43   //关闭对应的连接,关闭和打开都是双向的。  
  6.             #define A_WRTE 0x45545257   //该命令用来向pc端或是device端发送数据,该命令一般都有数据阶段  
  7.             #define A_AUTH 0x48545541</span>  

主题四:device端对收到的pc端来的命令或数据的处理函数:handle_packet
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. <span style="font-size: 18px;">void handle_packet(apacket *p, atransport *t)//system/core/adb/adb.c  
  2. {  
  3.     asocket *s;  
  4.   
  5.     D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],  
  6.             ((char*) (&(p->msg.command)))[1],  
  7.             ((char*) (&(p->msg.command)))[2],  
  8.             ((char*) (&(p->msg.command)))[3]);  
  9.     print_packet("recv", p);  
  10.   
  11.     switch(p->msg.command){  
  12.     case A_SYNC:           //在adb push和pull命令时使用。  
  13.         if(p->msg.arg0){  
  14.             send_packet(p, t);  
  15.             if(HOST) send_connect(t);  
  16.         } else {  
  17.             t->connection_state = CS_OFFLINE;  
  18.             handle_offline(t);  
  19.             send_packet(p, t);  
  20.         }  
  21.         return;  
  22.   
  23.     case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */ //在adb连接过程时使用。  
  24.             /* XXX verify version, etc */       //首先由pc发送一个A_CNXN命令和对应的数据,然后device收到后,会回复一个  
  25.                                                 //A_CNXN命令并带上数据阶段。  
  26.         if(t->connection_state != CS_OFFLINE) {  
  27.             t->connection_state = CS_OFFLINE;  
  28.             handle_offline(t);  
  29.         }  
  30.   
  31.         parse_banner((char*) p->data, t);  
  32.   
  33.         if (HOST || !auth_enabled) {  
  34.             handle_online(t);  
  35.             if(!HOST) send_connect(t);  
  36.         } else {  
  37.             send_auth_request(t);  
  38.         }  
  39.         break;  
  40.   
  41.     case A_AUTH:  
  42.         if (p->msg.arg0 == ADB_AUTH_TOKEN) {  
  43.             t->connection_state = CS_UNAUTHORIZED;  
  44.             t->key = adb_auth_nextkey(t->key);  
  45.             if (t->key) {  
  46.                 send_auth_response(p->data, p->msg.data_length, t);  
  47.             } else {  
  48.                 /* No more private keys to try, send the public key */  
  49.                 send_auth_publickey(t);  
  50.             }  
  51.         } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {  
  52.             if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {  
  53.                 adb_auth_verified(t);  
  54.                 t->failed_auth_attempts = 0;  
  55.             } else {  
  56.                 if (t->failed_auth_attempts++ > 10)  
  57.                     adb_sleep_ms(1000);  
  58.                 send_auth_request(t);  
  59.             }  
  60.         } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {  
  61.             adb_auth_confirm_key(p->data, p->msg.data_length, t);  
  62.         }  
  63.         break;  
  64.   
  65.     case A_OPEN: /* OPEN(local-id, 0, "destination") */  执行一个adb命令时,首先是发送的这个命令  
  66.         if (t->online) {  
  67.             char *name = (char*) p->data;  //命令对应的数据,该数据字段一般包含所要执行的shell命令  
  68.             name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;  
  69.          D("open usb\n");  
  70.             s = create_local_service_socket(name); // 根据命令的名字执行相应的后台服务线程,通过socket对或是pty/pts来实现本地socket跟  
  71.             if(s == 0) {                         //后台服务线程之间的通讯,本地socket用于跟对应命令的后台服务线程通讯  
  72.                 send_close(0, p->msg.arg0, t);  
  73.             } else {  
  74.                 s->peer = create_remote_socket(p->msg.arg0, t); //对端socket即用于实现跟pc端的交互,主要是向pc发送数据  
  75.                 s->peer->peer = s;  
  76.                 send_ready(s->id, s->peer->id, t);  
  77.                 s->ready(s);  
  78.             }  
  79.         }  
  80.         break;  
  81.   
  82.     case A_OKAY: /* READY(local-id, remote-id, "") */  
  83.         if (t->online) {  
  84.             if((s = find_local_socket(p->msg.arg1))) {  
  85.                 if(s->peer == 0) {  
  86.                     s->peer = create_remote_socket(p->msg.arg0, t);  
  87.                     s->peer->peer = s;  
  88.                 }  
  89.                 s->ready(s);  
  90.             }  
  91.         }  
  92.         break;  
  93.   
  94.     case A_CLSE: /* CLOSE(local-id, remote-id, "") */  
  95.         if (t->online) {  
  96.             if((s = find_local_socket(p->msg.arg1))) {  
  97.                 s->close(s);  //关闭时双向的,现实pc端发送关闭命令,然后是device端回复关闭命令,close 对应 local_socket_close  
  98.             }  
  99.         }  
  100.         break;  
  101.   
  102.     case A_WRTE:    // 对应pc端给device发送数据,分为两个阶段:一个阶段是命令:WRTE(包含在 apacket.msg中);另一个阶段是数据(包含在 apacket.data中)  
  103.         if (t->online) {  
  104.             if((s = find_local_socket(p->msg.arg1))) {  
  105.                 unsigned rid = p->msg.arg0;  
  106.                 p->len = p->msg.data_length;  
  107.   
  108.                 if(s->enqueue(s, p) == 0) {  //enqueue 对应的函数是 local_socket_enqueue  
  109.                     D("Enqueue the socket\n");  
  110.                     send_ready(s->id, rid, t);  
  111.                 }  
  112.                 return;  
  113.             }  
  114.         }  
  115.         break;  
  116.   
  117.     default:  
  118.         printf("handle_packet: what is %08x?!\n", p->msg.command);  
  119.     }  
  120.   
  121.     put_apacket(p);  
  122. }</span>  
上面函数中的remote_socket_enqueue函数,用于向pc端发送命令和数据
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. <span style="font-size: 18px;">static int remote_socket_enqueue(asocket *s, apacket *p)  
  2. {  
  3.     D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n",  
  4.       s->id, s->fd, s->peer->fd);  
  5.     p->msg.command = A_WRTE;      //apackge包对应的命令  
  6.     p->msg.arg0 = s->peer->id;  
  7.     p->msg.arg1 = s->id;  
  8.     p->msg.data_length = p->len;  
  9.     send_packet(p, s->transport);  
  10.     return 1;  
  11. }</span>  
上面函数create_local_service_socket的实现如下:
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. <span style="font-size: 18px;">asocket *create_local_service_socket(const char *name)  
  2. {  
  3.     asocket *s;  
  4.     int fd;  
  5.   
  6. #if !ADB_HOST  
  7.     if (!strcmp(name,"jdwp")) {  
  8.         return create_jdwp_service_socket();  
  9.     }  
  10.     if (!strcmp(name,"track-jdwp")) {  
  11.         return create_jdwp_tracker_service_socket();  
  12.     }  
  13. #endif  
  14.     D("begin service_to_fd:%s\n",name);  
  15.     fd = service_to_fd(name);//该函数的功能就是根据name来创建相应的后台服务,并创建一个socket pair或是pty/pts管道对,返回的fd对应该管道的一端;  
  16.     if(fd < 0) return 0;     //该管道的另一端,将dup重定向到该后台服务的输入输出句柄。  
  17.   
  18.     s = create_local_socket(fd);//安装本地句柄,即上面返回的fd句柄的输入和输出处理函数:local_socket_event_func  
  19.     D("LS(%d): bound to '%s' via %d\n", s->id, name, fd);  
  20.   
  21. #if !ADB_HOST  
  22.     if ((!strncmp(name, "root:", 5) && getuid() != 0)  
  23.         || !strncmp(name, "usb:", 4)  
  24.         || !strncmp(name, "tcpip:", 6)) {  
  25.         D("LS(%d): enabling exit_on_close\n", s->id);  
  26.         s->exit_on_close = 1;  
  27.     }  
  28. #endif  
  29.   
  30.     return s;  
  31. }</span>  
local_socket_event_func函数展开如下:该函数是handle_packet与对应的后台服务之间的一个中转函数,他的任务包括:
任务一:将pc端发送过来的命令和数据报(统称为adb package)通过local_socket_enqueue函数放置在struct 
apacket的next队列上,并触发如下函数的FDE_WRITE分支的处理,该分支将从apacket队列上取package,并将它写到管道另一端的后台服务上,作为后台服务的输入。
任务二:在要读出后台服务的输出结果时,通过调用函数local_socket_ready来触发如下函数的FDE_READ
分支,该分支将通过管道,读取后台服务的输出数据,并调用 s->peer->enqueue(即remote_socket_enqueue函数)将后台服务的输出发送到远端,即pc端上。
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. <span style="font-size: 18px;">static void local_socket_event_func(int fd, unsigned ev, void *_s)  
  2. {  
  3.     asocket *s = _s;  
  4.   
  5.     D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev);  
  6.   
  7.     /* put the FDE_WRITE processing before the FDE_READ 
  8.     ** in order to simplify the code. 
  9.     */  
  10.     if(ev & FDE_WRITE){  
  11.         apacket *p;  
  12.   
  13.         while((p = s->pkt_first) != 0) {  
  14.             while(p->len > 0) {  
  15.                 int r = adb_write(fd, p->ptr, p->len);//将pc段发送来的命令和数据写到后台服务  
  16.                 if(r > 0) {  
  17.                     p->ptr += r;  
  18.                     p->len -= r;  
  19.                     continue;  
  20.                 }  
  21.                 if(r < 0) {  
  22.                     /* returning here is ok because FDE_READ will 
  23.                     ** be processed in the next iteration loop 
  24.                     */  
  25.                     if(errno == EAGAIN) return;  
  26.                     if(errno == EINTR) continue;  
  27.                 }  
  28.                 D(" closing after write because r=%d and errno is %d\n", r, errno);  
  29.                 s->close(s);  
  30.                 return;  
  31.             }  
  32.   
  33.             if(p->len == 0) {  
  34.                 s->pkt_first = p->next;//取队列中的下一个apackage包  
  35.                 if(s->pkt_first == 0) s->pkt_last = 0;  
  36.                 put_apacket(p);  
  37.             }  
  38.         }  
  39.   
  40.             /* if we sent the last packet of a closing socket, 
  41.             ** we can now destroy it. 
  42.             */  
  43.         if (s->closing) {  
  44.             D(" closing because 'closing' is set after write\n");  
  45.             s->close(s);  
  46.             return;  
  47.         }  
  48.   
  49.             /* no more packets queued, so we can ignore 
  50.             ** writable events again and tell our peer 
  51.             ** to resume writing 
  52.             */  
  53.         fdevent_del(&s->fde, FDE_WRITE);  
  54.         s->peer->ready(s->peer);  
  55.     }  
  56.   
  57.   
  58.     if(ev & FDE_READ){  
  59.         apacket *p = get_apacket();  
  60.         unsigned char *x = p->data;  
  61.         size_t avail = MAX_PAYLOAD;  
  62.         int r;  
  63.         int is_eof = 0;  
  64.   
  65.         while(avail > 0) {  
  66.             r = adb_read(fd, x, avail);//读取后台服务的输出  
  67.             D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%d\n", s->id, s->fd, r, r<0?errno:0, avail);  
  68.             if(r > 0) {  
  69.                 avail -= r;  
  70.                 x += r;  
  71.                 continue;  
  72.             }  
  73.             if(r < 0) {  
  74.                 if(errno == EAGAIN) break;  
  75.                 if(errno == EINTR) continue;  
  76.             }  
  77.   
  78.                 /* r = 0 or unhandled error */  
  79.             is_eof = 1;  
  80.             break;  
  81.         }  
  82.         D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n",  
  83.           s->id, s->fd, r, is_eof, s->fde.force_eof);  
  84.         if((avail == MAX_PAYLOAD) || (s->peer == 0)) {  
  85.             put_apacket(p);  
  86.         } else {  
  87.             p->len = MAX_PAYLOAD - avail;  
  88. <span style="white-space: pre;">        </span>//以下将后台服务的输出发送到远端pc上。  
  89.             r = s->peer->enqueue(s->peer, p);//remote_socket_enqueue,该分支在handle_packet函数中的被create_remote_socket初始化  
  90.             D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r);  
  91.   
  92.             if(r < 0) {  
  93.                     /* error return means they closed us as a side-effect 
  94.                     ** and we must return immediately. 
  95.                     ** 
  96.                     ** note that if we still have buffered packets, the 
  97.                     ** socket will be placed on the closing socket list. 
  98.                     ** this handler function will be called again 
  99.                     ** to process FDE_WRITE events. 
  100.                     */  
  101.                 return;  
  102.             }  
  103.   
  104.             if(r > 0) {  
  105.                     /* if the remote cannot accept further events, 
  106.                     ** we disable notification of READs.  They'll 
  107.                     ** be enabled again when we get a call to ready() 
  108.                     */  
  109.                 fdevent_del(&s->fde, FDE_READ);  
  110.             }  
  111.         }  
  112.         /* Don't allow a forced eof if data is still there */  
  113.         if((s->fde.force_eof && !r) || is_eof) {  
  114.             D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof);  
  115.             s->close(s);  
  116.         }  
  117.     }  
  118.   
  119.     if(ev & FDE_ERROR){  
  120.             /* this should be caught be the next read or write 
  121.             ** catching it here means we may skip the last few 
  122.             ** bytes of readable data. 
  123.             */  
  124. //        s->close(s);  
  125.         D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd);  
  126.   
  127.         return;  
  128.     }  
  129. }</span>  

注意:
system/core/adb/services.c对应各种命令的后台服务
system/core/adb/commandline.c包含各种后台服务的具体实现。


主题五:usb adb的bus hound分析
情景1:adb的链接过程

2.1.0  
3.1.0
4.1.0 
5.1.0
以上是通用的枚举过程,即取得描述符的内容。
6.1.0  set_config
7.1.0  取得描述符
至此完成设备的枚举,开始adb的连接过程。
8.1.0 发送adb命令:A_CNXN  为out传输
9.1.0 发送adb命令A_CNXN所带的数据 为out传输
10.1.0 由device端发送adb命令A_CNXN到host pc段。IN传输
11.1.0 为adb命令A_CNXN所带的数据,IN传输
12.1.0为adb命令A_OPEN
13.1.0为adb命令A_OPEN所带的数据
14.1.0为以上命令的响应:A_OKAY
15.1.0为adb命令A_WRTE
16.1.0为adb命令A_WRTE所带的数据
17.1.0为以上命令的响应
21.1.0位adb命令A_CLSE,没有数据阶段 IN传输
22.1.0为adb命令A_CLSE,没有数据阶段,关闭时双向的。OUT传输
以上即为adb连接过程的usb封包的分析


情景2:adb logcat过程



1.1.0对应adb命令A_OPEN
2.1.0对应adb命令A_OPEN所带的数据,这个数据中有如下命令:exec logcat
3.1.0为以上命令的响应,IN传输


4.1.0对应adb命令A_WRTE
5.1.0对应adb命令A_WRTE的数据 IN传输,打开设备节点/dev/log/main
6.1.0为以上命令的响应 OUT传输




7.1.0对应adb命令A_WRTE
8.1.0对应adb命令A_WRTE的数据,即为logcat的输出内容 IN传输
10.1.0为以上命令的响应,OUT传输


再往下,即为上面命令的重复,以不断输出logcat的log信息

情景3:adb pull过程


1.1.0对应adb命令A_OPEN
2.1.0对应adb命令A_OPEN所带的数据,这个数据中有如下命令:sync,
     该sync命令在service_to_fd函数中,被file_sync_service函数所处理
3.1.0为以上命令的响应,IN传输


4.1.0对应adb命令A_WRTE
5.1.0对应adb命令A_WRTE的数据 IN传输,数据内容为:STAT,pc用该命令来查询该文件是否存在,已经是有权限
6.1.0为以上命令的响应 OUT传输


13.1.0 对应adb命令A_WRTE  OUT传输
14.1.0 对应adb命令A_WRTE的数据,该数据包含一个命令:RECV,表示pc从device段接收文件
15.1.0 为以上命令的响应


16.1.0 对应adb命令A_WRTE OUT传输
17.1.0 对应adb命令A_WRTE的数据,表示要pull的是哪个文件
18.1.0 为以上命令的响应


19.1.0 对应adb命令A_WRTE IN传输
20.1.0 对应adb命令A_WRTE的数据:DATA,表示开始数据传输,并且指定下一个命令需要传输的数据大小
21.1.0 为以上命令的响应


22.1.0 对应adb命令A_WRTE IN传输
23.1.0 对应adb命令A_WRTE的数据: 包含文件的具体内容,长度就是上面命令指定的长度
24.1.0 为以上命令的响应

重复19到24这个过程,直到文件被传输完成。


情景4:adb push过程


2.1.0对应adb命令A_OPEN所带的数据,这个数据中有如下命令:shell:
3.1.0为以上命令的响应,IN传输


4.1.0对应adb命令A_WRTE IN传输
5.1.0对应adb命令A_WRTE的数据 ,数据内容为:#,即为显示在pc上的cmd窗口上的#号。
6.1.0为以上命令的响应 OUT传输

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 舌头有异味怎么办是有口臭吗 快8个月羊水破了怎么办 25岁欠了50万债怎么办 28岁血压高150低压110怎么办 苹果6的4g网络慢怎么办 一个月染了6次头怎么办 五0二干在衣服上怎么办 刚怀孕见红了肚子不痛怎么办 我有外遇了老婆不离婚怎么办 套了牙套的牙疼怎么办 我鼻子上有很多螨虫和黑头怎么办 鱼刺卡在喉咙怎么办最有效的办法 脚被蚊子咬了很痒怎么办 好压7z密码忘了怎么办 4g卡显示2g网络怎么办 过塑机把纸吞了怎么办 红米1s开不了机怎么办 跟老婆吵架闹的要离婚该怎么办 充了q币没有到账怎么办 9个月宝宝吃了盐怎么办 红米4x开不了机怎么办 鱼身上有红斑像出血了怎么办 草鱼身上有红斑像出血了怎么办 宝宝屁眼红的破皮了怎么办 孩子身上起红疙瘩很痒怎么办 久而不射,但软了怎么办 盆底综合肌力1级怎么办 头发掉的厉害怎么办吃什么好 给蜂蛰了肿了痒怎么办 小米手环2没电了怎么办 小米手环2不亮了怎么办 红米3s无限重启怎么办 乐视手机1s卡顿怎么办 老公出轨了怎么办你会选择离婚吗 c盘和d盘换换了怎么办 晚上2点到3点醒怎么办 红米3s变砖了怎么办 6s锁屏密码忘了怎么办 怀孕9个月了胃疼怎么办 怀孕6个月了胃疼怎么办 孕妇胃疼怎么办4个月了