美文网首页ADB
adb源码分析2

adb源码分析2

作者: 4528283108ee | 来源:发表于2017-04-28 19:23 被阅读62次

    注册完三个通信函数和连个线程之后,就调用函数install_listener在5037端口进行监听,然后将这个服务添加到链表中(可提供多个服务,这个我不关注),并将输入流重定向到/dev/null,打印 adb start ,向之前打开的管道写端写入 OK\N,通知服务已经启动。进入fdevent_loop,fdevent_process进行处理,这两个函数后面进行分析。回过头来看adb command发送的adb shell命令。

    前文讲到子进程execl了adb命令,我们回过头来看看父进程做什么

    chartemp[3];

    temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';

    // wait for the "OK\n" message

    adb_close(fd[1]);

    intret = adb_read(fd[0], temp, 3);

    intsaved_errno = errno;

    adb_close(fd[0]);

    if(ret < 0) {

    fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_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;

    }


    首先父进程关闭了管道写端,准备从管道读端读取数据,当adb-server启动后向写端写入OK\n 读端从阻塞返回,launch_server返回。再次进行__adb_connect 之后调用SendProtocolString 发送 000dhost:features,成功返回文件描述符,adb_connect返回到adb_query,
    , 之后读取四个字节长度,然后根据长度读取数据z,这里返回000c也就是12, 后面返回的是shell_v2,cmd
    协议版本和命令类型。adb_query返回之后adb_get_feature_set返回, FeatureSet
    为 shell_v2,cmd.

    之后调用CanUseFeature 对一下版本是否匹配。 最后解析参数调用RemoteShell函数进行处理。

    然后发送RemoteShell :shell,v2,TERM=xterm:

    之后就是从STDIN中读取数据 写入到5037端口的链接。 这部分看完了,再回来看adb-server收到接到adb的链接请求后如何处理。

    if(ev &FDE_READ) {

    sockaddr_storagess;

    sockaddr* addrp =reinterpret_cast(&ss);

    socklen_talen =sizeof(ss);

    intfd = adb_socket_accept(_fd,addrp,&alen);

    if(fd <0)return;

    intrcv_buf_size =CHUNK_SIZE;

    adb_setsockopt(fd,SOL_SOCKET,SO_RCVBUF,&rcv_buf_size,sizeof(rcv_buf_size));

    asocket* s = create_local_socket(fd);

    if(s) {

    connect_to_smartsocket(s);

    return;

    }

    adb_close(fd);

    }

    adb-server在ss_listener_event_func观察可读事件,当链接建立后进入这个函数,讲请求接进来后 重新设置缓冲区。

    创建一对asocket一个代表服务端,一个代表客户端(其实是一个从接进来的链接中读取数据,一个写入数据)。

    我们来看看怎么处理的,这个流程各种回调,响应式变成,好无聊

    create_local_socket 创建客户端asocket 设置回调函数local_socket_enqueue  local_socket_ready local_socket_close 链入local_socket_list

    connect_to_smartsocket 创建服务端asocket,设置回调函数smart_socket_enqueue smart_socket_ready  smart_socket_close,设置local和smatrserver互为对端。

    下面称服务端asocket和客户端socket分别为local_asocket,server_asocket,

    最后执行local_asocket.ready(local_asocket),

    static voidlocal_socket_ready(asocket* s) {

    /* far side is ready for data, pay attention to

    readable events */

    fdevent_add(&s->fde,FDE_READ);

    }

    其实就是观察这个socket可写状态(可写回调local_socket_event_func),因为客户端马上写了个000dhost:features(前边是长度,后边是命令)。所以该函数会马上回调。

    这时候关注读事件部分

    if(ev &FDE_READ) {

    这时候还没有设置transport 当前的max_payload= 256*1024,从客户端套接字读取数据到apacket->data,执行server_asocket.enqueue
    (server_asocket,p),注意这里p存了从套接字中读取的数据,server_asocket.enqueue函数就是smart_socket_enqueue函数,可以猜测smart_socket_enqueue是写入数据到usb,然后返回数据后写出到fd,这里稍后分析,再看smart_socket_enqueue 返回后,就卸载了可读事件的回调,因为之后要写入数据了。

    现在分析smart_socket_enqueue函数:获取数据前四位长度。解析命令,之后对不同命令进行处理,这里的命令是host:features,这里将

    type设置成kTransportAny,server设置成features,调用handle_host_request处理请求,在adb.cpp中,


    if(!strncmp(service, "transport", strlen("transport"))) {

    TransportType type = kTransportAny;

    atransport* t = acquire_one_transport(type, serial,nullptr, &error);
    。。。
    s->transport = t;
    SendOkay(reply_fd);

    通过acquire_one_transport获取一个transport, 从transport_list中找出合适的atransport,根据类型(还记得我们之前打开的套接字对用于和usb通信的那套通信框架吗,atransport就描述了该结构)对于不同的类型还有写限制。 返回到handle_host_request
    ,获取了atransport后,设置server_asocke的transport为 (选定通信通道),调用SendOkay(reply_fd);这里的reply_fd就是链接如5037端口的套接字,SendOkay就是向套接字中写入OKAY.

    这里我们不在关心协议细节的东西,我们来查看如何通信。假如命令是transport直接返回,由此可见transport是用于找到通信介质。这种命令不需要写入usb,就直接返回了。再看features命令,调用SendOkay(reply_fd, FeatureSetToString(t->features()));函数。

    static intSendOkay(intfd,conststd::string& s) {

    SendOkay(fd);

    SendProtocolString(fd, s);

    return0;

    }

    除了发送ok以为,还发送了 SendProtocolString 发送协议信息。到这里还没有看到如何和adbd通信。 整个流程还没有跑通,

    关键点就在transport初始化的时候,会初始化一些信息 feure也是其中初始化的数据。 所以features 也是不需要和手机通信的,处理完成这些不用和手机进行通信的请求后就是handle_forward_request 转发请求, 也是获取相应的atransport 然后install_listeren,

    以RemoteShell :shell,v2,TERM=xterm:这条命令为例子 第一个参数是RemoteShell,第二个参数是shell,v2,TERM=xterm: 三个参数是transport

    创建新的 alistener

    connect_to=shell,v2,TERM=xterm:
    name = RemoteShell


    相关文章

      网友评论

        本文标题:adb源码分析2

        本文链接:https://www.haomeiwen.com/subject/sirozttx.html