Browsed by
分类:未分类

由Adb Emulator问题谈起

由Adb Emulator问题谈起

0,问题描述

进入RK3288平台,执行adb devices会有一个emulator-5554的模拟器的连接。

1,复现步骤

reboot rk3288
C:\Users\koffuxu>adb tcpip 5555
C:\Users\koffuxu>adb shell
shell@firefly:/ # adb devices
* daemon not running. starting it now on port 5038 *
* daemon started successfully *
List of devices attached
emulator-5554   device
or:
setprop service.adb.tcp.port 5555; stop adbd; start adbd;

2,port status

127.0.0.1的41114端口(adb),连接上了5555端口(adbd),认为有一个模拟器的存在。 
从而可以获得产生该问题的原因:
先启动adbd进程,监听127.0.0.1的5555端口;
再启动adb中的server,会去获得usb或者tcp链接上的adb状态,当有5555端口有响应的时候,认为有android device设备连接了,当对方的IP地址为127.0.0.1的话,就认为是emulator设备,即显示出来这个模拟器了。

3,打开调试

  1. --- a/system/core/adb/adb_trace.h
  2. +++ b/system/core/adb/adb_trace.h
  3. @@ -64,7 +64,7 @@ extern int adb_trace_mask;
  4. extern unsigned char adb_trace_output_count;
  5. void adb_trace_init(void);
  6. -# define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
  7. +# define ADB_TRACING 1// ((adb_trace_mask & (1 << TRACE_TAG)) != 0)

4,修正方案

第一次尝试:注册127.0.0.1:*<->127.0.0.1:5555的连接到transport_list全局链表时的时候,把类型由local转为非local型。
结果:几番adb kill-server /start-server之后还是会有emulator出现
 第二次尝试:不把与5555的连接注册到全局链表中。
结果:emulaotr没有添加到全局链表中,但连接是存在的,netstat 还是可以看与127.0.0.1有连接,仍有风险。
第三次尝试:不与5555进行连接
 结果:没有本地的5555的连接,emulator也没有产生,其它连接也不受影响。
其它功能测试如下:
  • PC通过usb或者网线连接RK3288的adbd

    

  • RK3288的通过usb或者网线连接手机I9300的adbd
    
     socket的连接情况
    
 .105  =RK3288的IP
.55     =I9300手机的IP
.239    =PC的IP
 

5,复盘

Overview
 

 5.1,2种Service:

Host Service:不需要与device进行通讯,直接在本地查询服务,比如版本号查询服务
Local Service:需要与Device进行通信,比如adb shell服务
ADB SERVER的各种类型参考SERVICES.txt,包含Host Service和Local Service

5.2,2个监听端口:

ADB Server监听TCP:localhost:5038,是用于等待Client的命令传输,指定127.0.0.1的连接
ADBD 监听TCP:0.0.0.0:5555,是用于监听TCP/IP的adb连接请求服务,任何IP皆可以连接 ,包括127.0.0.1

5.3,2种传输媒介:

USB:只限与物理设备的传输连接
TCP/IP:包括物理设备的连接,也包括本地adb与adbd的连接(这就是产生emualtor-5554的原因)

6,adb devices命令执行流程

ADB_HOST=1表示编译进adb可执行文件,否则为adbd可执行文件
adb devices
由services.txt可知,adb devices描述如下:
  1. host:devices host:devices-l Ask to return the list of available Android devices and their
  2. state. devices-l includes the device paths in the state.
  3. After the OKAY, this is followed by a 4-byte hex len,
  4. and a string that will be dumped as-is by the client, then
  5. the connection is closed
执行adb命令,首先进入main()
main()@adb.c
=>//adb_commandline()@commandline.c
system/core/adb/adb.c::main():Handling commandline() 
=>进行一些参数判断之后,进入qury_adb()函数 
  1. if(!strcmp(argv[0], "devices")) {
  2. ...
  3. tmp = adb_query(buf);
  4. if(tmp) {
  5. printf("List of devices attached \n");
  6. printf("%s\n", tmp);
  7. return 0;
=>//adb_query()@adb_client.c打印如下
system/core/adb/adb_client.c::adb_query():adb_query: host:devices 
=>
第一步,执行host:version命令
system/core/adb/adb_client.c::_adb_connect():_adb_connect: host:version //_adb_connect()@adb_client.c
adb_connect之前,先进行adb version查询,通过Socket的方式查询SOCK_STREAM。初次会返回为负值,需要自己启动。如果已经启动就会接下来读取版本。
=>
此段打印,检查adb_connecet是否已经启动。
//调用writex(fd, tmp, 4) || writex(fd, service, len)
system/core/adb/transport.c::writex():writex: fd=3 len=4: 30303063 000c
system/core/adb/transport.c::writex():writex: fd=3 len=12: 686f73743a76657273696f6e host:version
//接收server的数据:adb_status(fd)
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
4f4b4159 OKAY
//连接成功,正常则返回!
system/core/adb/adb_client.c::_adb_connect():_adb_connect: return fd 3
//D(“adb_connect: service %s\n”, service);打印
system/core/adb/adb_client.c::adb_connect():adb_connect: service host:devices 
第二步,读取版本号进行比较
//因为fd>0走else流程,开始进行版本比较
//if(readx(fd, buf, 4)) goto error; 读取前面4个字节,即本次buf的长度
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
30303034 0004
//readx(fd, buf, n) 读取整个buf的长度,获取Version号
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
30303230 0020
第三步,执行host:devices命令
//版本比对成功之后,开始执行host:devices
system/core/adb/adb_client.c::_adb_connect():_adb_connect: host:devices//打印来自fd = _adb_connect(service);
//给Service写数据,包含长度的命令writex(fd, tmp, 4) || writex(fd, service, len)
//整个帧的格式[][][][]+[……]
system/core/adb/transport.c::writex():writex: fd=3 len=4: 30303063 000c//host:devices刚好为12个字节
system/core/adb/transport.c::writex():writex: fd=3 len=12: 686f73743a64657669636573 host:devices//再写命令
////接收server的数据:adb_status(fd)
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
4f4b4159 OKAY
//命令已经写给Server了,_adb_connect正常返回
system/core/adb/adb_client.c::_adb_connect():_adb_connect: return fd 3
//adb_connect()也正常返回,打印来自    D(“adb_connect: return fd %d\n”, fd);进入adb_query
system/core/adb/adb_client.c::adb_connect():adb_connect: return fd 3
第四步,读取host:devices的返回数据
//返回到adb_query()@adb_client.c
//再读buf,第一次读buf的的前面4个字节,即长度 if(readx(fd, buf, 4))
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
//读取的buf长度为0,即没有device连接,符合打印。
30303030 0000
system/core/adb/transport.c::readx():readx: fd=3 wanted=0
system/core/adb/transport.c::readx():readx: fd=3 wanted=0 got=0
List of devices attached
有模拟器的打印,就很容易分析其中的流程
1|shell@firefly:/ $ adb devices
system/core/adb/adb.c::main():Handling commandline()
system/core/adb/adb_client.c::adb_query():adb_query: host:devices
//写host:version命令
system/core/adb/adb_client.c::_adb_connect():_adb_connect: host:version
system/core/adb/transport.c::writex():writex: fd=3 len=4: 30303063 000c
system/core/adb/transport.c::writex():writex: fd=3 len=12: 686f73743a76657273696f6e host:version
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
4f4b4159 OKAY
system/core/adb/adb_client.c::_adb_connect():_adb_connect: return fd 3
system/core/adb/adb_client.c::adb_connect():adb_connect: service host:devices
//读取版本号
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
30303034 0004
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
30303230 0020
//版本比对成功,写host:device命令
system/core/adb/adb_client.c::_adb_connect():_adb_connect: host:devices
system/core/adb/transport.c::writex():writex: fd=3 len=4: 30303063 000c
system/core/adb/transport.c::writex():writex: fd=3 len=12: 686f73743a64657669636573 host:devices
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
4f4b4159 OKAY
system/core/adb/adb_client.c::_adb_connect():_adb_connect: return fd 3
system/core/adb/adb_client.c::adb_connect():adb_connect: return fd 3
//成功返回之后,读取buf信息
system/core/adb/transport.c::readx():readx: fd=3 wanted=4
system/core/adb/transport.c::readx():readx: fd=3 wanted=4 got=4
30303135 0015
system/core/adb/transport.c::readx():readx: fd=3 wanted=21
system/core/adb/transport.c::readx():readx: fd=3 wanted=21 got=21//读取21个字节即emulator-5554.de[vices]
656d756c61746f722d35353534096465 emulator-5554.de
List of devices attached
//获得连接数据
emulator-5554   device

7,解决思路

设备以及状态是在server中检测和连接,在Service.c中屏蔽对127.0.0.1:5555的连接。
或者,让Server不去连接127.0.0.1:5555端口。【最终就是采用这种方法】
首先要弄懂
  • adbd是如何通过5555端口来检测是否有设备接入的。【fdevent机制:transport_registration_func
  • adb的Server端是如何去连接5555端口的。【socket机制:local_init()@transport_local.c】

       socket_loopback_client(adb_port, SOCK_STREAM),会去连接local:5555端口。

  1. addr.sin_family = AF_INET;
  2. addr.sin_port = htons(port);
  3. addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  4. s = socket(AF_INET, type, 0);
  • adb的Server与adbd的5555号端口连接,这种连接是谁先发起的?

从以下注释可以看到一些端倪

client_socket_thread()@transport_local.c
  1. /* try to connect to any number of running emulator instances */
  2. /* this is only done when ADB starts up. later, each new emulator */
  3. /* will send a message to ADB to indicate that is is starting up */
  4. for ( ; count > 0; count--, port += 2 ) {
  5. (void) local_connect(port);
  6. }
看来是新的模拟器先发消息给adb的,也就是adbd发起的??!!
7.1,adb start-server在Server端的处理
adb start-server是在adb_connect的时候执行host:version命令时就执行了,并未传递到Server端。
代码段为
_adb_connect()@adb_client.c,
fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
=>根据Unix Socket通信模型,此处即创建一个lopback地址(即127.0.0.1)端口号为5038的socket client,并进行连接。
  1. addr.sin_family = AF_INET;
  2. addr.sin_port = htons(port);
  3. addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  4. s = socket(AF_INET, type, 0);
  5. connect(s, (struct sockaddr *) &addr, sizeof(addr))
那么这个Socket的Server端是在哪里创建的?
main()@adb.c->adb_main()
  1. ...
  2. local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);//DEFAULT_ADB_LOCAL_TRANSPORT_PORT=5555
  3. ...
  4. char local_name[30];
  5. build_local_name(local_name, sizeof(local_name), server_port);//server_port=5038
  6. if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
  7. exit(1);
  8. }
local_init是初始化5555端口的socket,在local_init里面,会根据HOST的值,是创建一个监听5555的socket server(for adbd)还是连接5555端口的socket client?
  1. //port = 5555
  2. void local_init(int port)
  3. {
  4. ...
  5. if(HOST) {
  6. func = client_socket_thread;//在adb进程,属于soekct client
  7. } else {
  8. func = server_socket_thread;//在adbd进程,属于socket server
  9. ...
  10. adb_thread_create(&thr, func, (void *) (uintptr_t) port))
  11. ...
  12. }
接着,install_listener(local_name, “*smartsocket*”, NULL, 0)则是创建一个监听5038端口socket server。
7.2,adb devices命令在Server的处理
处理是在handle_host_request()@adb.c
  1. // return a list of all connected devices
  2. if (!strncmp(service, "devices", 7)) {
  3. char buffer[4096];
  4. int use_long = !strcmp(service+7, "-l");
  5. if (use_long || service[7] == 0) {
  6. memset(buffer, 0, sizeof(buffer));
  7. D("Getting device list \n");
  8. list_transports(buffer, sizeof(buffer), use_long);
  9. D("Wrote device list \n");
  10. send_msg_with_okay(reply_fd, buffer, strlen(buffer));
  11. return 0;
  12. }
  13. }
list_transports()方法
  1. for(t = transport_list.next; t != &transport_list; t = t->next) {
  2. len = format_transport(t, p, end - p, long_listing);
  3. if (p + len >= end) {
  4. /* discard last line if buffer is too short */
  5. break;
  6. }
主要是从transport_list这个全局链表中取出来。
这个链接是在transport_registration_func()@transport.c这个函数里添加元素的
  1. static void transport_registration_func(int _fd, unsigned ev, void *data)
  2. {
  3. ...
  4. /* put us on the master device list */
  5. t->next = &transport_list;
  6. t->prev = transport_list.prev;
  7. t->next->prev = t;
  8. t->prev->next = t;
  9. }
这个transport_registration_func()被void init_transport_registration(void)调用,注册为fdevent
  1. void init_transport_registration(void)
  2. {
  3. int s[2];
  4. if(adb_socketpair(s)){
  5. fatal_errno("cannot open transport registration socketpair");
  6. }
  7. transport_registration_send = s[0];
  8. transport_registration_recv = s[1];
  9. fdevent_install(&transport_registration_fde,
  10. transport_registration_recv,
  11. transport_registration_func,
  12. 0);
  13. fdevent_set(&transport_registration_fde, FDE_READ);
  14. }
按照道理,只要读某个socket fd,就会有回到全局链表中。
而init_transport_registration();由adb_main()调用,相当于adbd进程。
简而言之,在adbd进程,如果有其它进程读它的socket节点,将触发fdevent,会把访问它的client记录在全局列表transprot_list链表中,即devices的列表。
7.3,adb connect在Server端的处理

8,adb Server与adbd处理“客户端”的循环

8.1,在adb的Server端的处理,是在handle_host_request()@adb.c里面处理command line发过来的命令的。
由来:
在adb_main()的install_listener(local_name, “*smartsocket*”, NULL, 0)函数中,会创建一个名为*smartsocket*,监听端口为5028的socket server,同时还是注册监听事件
=>
  1. //install_listener("TCP:5038", "*smartsocket*", NULL, 0)
  2. static install_status_t install_listener(const char *local_name,
  3. const char *connect_to,
  4. atransport* transport,
  5. int no_rebind)
  6. {
  7. alistener *l;
  8. //1,填充l结构体
  9. if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
  10. if((l->local_name = strdup(local_name)) == 0) goto nomem;
  11. if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
  12. //2,local_name_to_fd会调用socet()和bin(),初始化socket server
  13. l->fd = local_name_to_fd(local_name);
  14. //3,开始install listen,用于响应客户端
  15. if(!strcmp(l->connect_to, "*smartsocket*")) {
  16. fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
  17. }
  18. fdevent_set(&l->fde, FDE_READ);
  19. //4,添加到listener_list全局链表中。
  20. l->next = &listener_list;
  21. l->prev = listener_list.prev;
  22. l->next->prev = l;
  23. l->prev->next = l;
  24. l->transport = transport;
  25. }
以上4步就完成adb server的socket server(*smartsocket*)的创建,其中第3步,安装了listen的处理,处理函数是ss_listener_event_func,继续深挖goon!
  1. static void ss_listener_event_func(int _fd, unsigned ev, void *_l)
  2. {
  3. asocket *s;
  4. ...
  5. s = create_local_socket(fd);
  6. if(s) {
  7. connect_to_smartsocket(s);
  8. return;
  9. }
  10. }
先创建asocket类型的s,然后调用connect_to_smartsocket进行连接
=>
create_smart_socket()
=>
s->enqueue = smart_socket_enqueue;
=>
if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) 
就调到handle_host_request函数里面了。DONE!
举例:比如说host:version的处理逻辑
    // returns our value for ADB_SERVER_VERSION
    if (!strcmp(service, “version”)) {
        char version[12];
        snprintf(version, sizeof version, “%04x”, ADB_SERVER_VERSION);
        send_msg_with_okay(reply_fd, version, strlen(version));
        return 0;
    }


8.2在adbd中,是在fdevent_loop()@fdevent.c处理客户端的请求;
  1. for(;;) {
  2. D("--- ---- waiting for events\n");
  3. fdevent_process();
  4. while((fde = fdevent_plist_dequeue())) {
  5. fdevent_call_fdfunc(fde);
  6. }
  7. }
死循环处理的,fdevent_loop()是在adb_main()@adb.c即adbd初始化的时候调用到。
TOP