Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 36e60623 authored by Josh Gao's avatar Josh Gao Committed by android-build-merger
Browse files

Merge \\"adb: refactor jdwp_service.cpp.\\" am: 71d11ade

am: a4e35be4

Change-Id: I7bbc7c8b3df8cd2aa37bd41dfb53fda8b841cbb9
parents c0c57c43 a4e35be4
Loading
Loading
Loading
Loading
+287 −406
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
 * limitations under the License.
 */

/* implement the "debug-ports" and "track-debug-ports" device services */
#if !ADB_HOST

#define TRACE_TAG JDWP

@@ -24,22 +24,29 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#include <list>
#include <memory>
#include <vector>

#include "adb.h"
#include "adb_io.h"
#include "adb_utils.h"

/* here's how these things work.

   when adbd starts, it creates a unix server socket
   named @vm-debug-control (@ is a shortcut for "first byte is zero"
   named @jdwp-control (@ is a shortcut for "first byte is zero"
   to use the private namespace instead of the file system)

   when a new JDWP daemon thread starts in a new VM process, it creates
   a connection to @vm-debug-control to announce its availability.
   a connection to @jdwp-control to announce its availability.


     JDWP thread                             @vm-debug-control
     JDWP thread                             @jdwp-control
         |                                         |
         |------------------------------->         |
         | hello I'm in process <pid>              |
@@ -72,7 +79,7 @@
        to the JDWP process with the help of sendmsg()


     JDWP thread                             @vm-debug-control
     JDWP thread                             @jdwp-control
         |                                         |
         |                  <----------------------|
         |           OK, try this file descriptor  |
@@ -116,229 +123,171 @@
 ** for each JDWP process, we record its pid and its connected socket
 **/

#define  MAX_OUT_FDS   4
// PIDs are transmitted as 4 hex digits in ascii.
static constexpr size_t PID_LEN = 4;

#if !ADB_HOST
static void jdwp_process_event(int socket, unsigned events, void* _proc);
static void jdwp_process_list_updated(void);

#include <sys/socket.h>
#include <sys/un.h>
struct JdwpProcess;
static std::list<std::unique_ptr<JdwpProcess>> _jdwp_list;

struct JdwpProcess {
    JdwpProcess*  next;
    JdwpProcess*  prev;
    int           pid;
    int           socket;
    fdevent*      fde;

    char          in_buff[4];  /* input character to read PID */
    int           in_len;      /* number from JDWP process    */

    int           out_fds[MAX_OUT_FDS]; /* output array of file descriptors */
    int           out_count;            /* to send to the JDWP process      */
};
    explicit JdwpProcess(int socket) {
        this->socket = socket;
        this->fde = fdevent_create(socket, jdwp_process_event, this);

static JdwpProcess  _jdwp_list;

static int
jdwp_process_list( char*  buffer, int  bufferlen )
{
    char*         end  = buffer + bufferlen;
    char*         p    = buffer;
    JdwpProcess*  proc = _jdwp_list.next;

    for ( ; proc != &_jdwp_list; proc = proc->next ) {
        int  len;

        /* skip transient connections */
        if (proc->pid < 0)
            continue;

        len = snprintf(p, end-p, "%d\n", proc->pid);
        if (p + len >= end)
            break;
        p += len;
    }
    p[0] = 0;
    return (p - buffer);
        if (!this->fde) {
            fatal("could not create fdevent for new JDWP process");
        }

        this->fde->state |= FDE_DONT_CLOSE;

static int
jdwp_process_list_msg( char*  buffer, int  bufferlen )
{
    char  head[5];
    int   len = jdwp_process_list( buffer+4, bufferlen-4 );
    snprintf(head, sizeof head, "%04x", len);
    memcpy(buffer, head, 4);
    return len + 4;
        /* start by waiting for the PID */
        fdevent_add(this->fde, FDE_READ);
    }


static void  jdwp_process_list_updated(void);

static void
jdwp_process_free( JdwpProcess*  proc )
{
    if (proc) {
        int  n;

        proc->prev->next = proc->next;
        proc->next->prev = proc->prev;

        if (proc->socket >= 0) {
            adb_shutdown(proc->socket);
            adb_close(proc->socket);
            proc->socket = -1;
    ~JdwpProcess() {
        if (this->socket >= 0) {
            adb_shutdown(this->socket);
            adb_close(this->socket);
            this->socket = -1;
        }

        if (proc->fde != NULL) {
            fdevent_destroy(proc->fde);
            proc->fde = NULL;
        if (this->fde) {
            fdevent_destroy(this->fde);
            this->fde = nullptr;
        }
        proc->pid = -1;

        for (n = 0; n < proc->out_count; n++) {
            adb_close(proc->out_fds[n]);
        out_fds.clear();
    }
        proc->out_count = 0;

        free(proc);

        jdwp_process_list_updated();
    }
    void RemoveFromList() {
        if (this->pid >= 0) {
            D("removing pid %d from jdwp process list", this->pid);
        } else {
            D("removing transient JdwpProcess from list");
        }

        auto pred = [this](const auto& proc) { return proc.get() == this; };
        _jdwp_list.remove_if(pred);
    }

static void  jdwp_process_event(int, unsigned, void*);  /* forward */
    int pid = -1;
    int socket = -1;
    fdevent* fde = nullptr;

    std::vector<unique_fd> out_fds;
    char in_buf[PID_LEN + 1];
    ssize_t in_len = 0;
};

static JdwpProcess*
jdwp_process_alloc( int  socket )
{
    JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(
        calloc(1, sizeof(*proc)));
static size_t jdwp_process_list(char* buffer, size_t bufferlen) {
    std::string temp;

    if (proc == NULL) {
        D("not enough memory to create new JDWP process");
        return NULL;
    for (auto& proc : _jdwp_list) {
        /* skip transient connections */
        if (proc->pid < 0) {
            continue;
        }

    proc->socket = socket;
    proc->pid    = -1;
    proc->next   = proc;
    proc->prev   = proc;

    proc->fde = fdevent_create( socket, jdwp_process_event, proc );
    if (proc->fde == NULL) {
        D("could not create fdevent for new JDWP process" );
        free(proc);
        return NULL;
        std::string next = std::to_string(proc->pid) + "\n";
        if (temp.length() + next.length() > bufferlen) {
            D("truncating JDWP process list (max len = %zu)", bufferlen);
            break;
        }
        temp.append(next);
    }

    proc->fde->state |= FDE_DONT_CLOSE;
    proc->in_len      = 0;
    proc->out_count   = 0;

    /* append to list */
    proc->next = &_jdwp_list;
    proc->prev = proc->next->prev;

    proc->prev->next = proc;
    proc->next->prev = proc;

    /* start by waiting for the PID */
    fdevent_add(proc->fde, FDE_READ);
    memcpy(buffer, temp.data(), temp.length());
    return temp.length();
}

    return proc;
static size_t jdwp_process_list_msg(char* buffer, size_t bufferlen) {
    // Message is length-prefixed with 4 hex digits in ASCII.
    static constexpr size_t header_len = 4;
    if (bufferlen < header_len) {
        fatal("invalid JDWP process list buffer size: %zu", bufferlen);
    }

    char head[header_len + 1];
    size_t len = jdwp_process_list(buffer + header_len, bufferlen - header_len);
    snprintf(head, sizeof head, "%04zx", len);
    memcpy(buffer, head, header_len);
    return len + header_len;
}

static void
jdwp_process_event( int  socket, unsigned  events, void*  _proc )
{
static void jdwp_process_event(int socket, unsigned events, void* _proc) {
    JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc);

    if (events & FDE_READ) {
        if (proc->pid < 0) {
            /* read the PID as a 4-hexchar string */
            char*  p    = proc->in_buff + proc->in_len;
            int    size = 4 - proc->in_len;
            char   temp[5];
            while (size > 0) {
                int  len = recv( socket, p, size, 0 );
                if (len < 0) {
                    if (errno == EINTR)
                        continue;
                    if (errno == EAGAIN)
                        return;
                    /* this can fail here if the JDWP process crashes very fast */
                    D("weird unknown JDWP process failure: %s",
                      strerror(errno));
            if (proc->in_len < 0) {
                fatal("attempting to read JDWP pid again?");
            }

                    goto CloseProcess;
            char* p = proc->in_buf + proc->in_len;
            size_t size = PID_LEN - proc->in_len;

            ssize_t rc = TEMP_FAILURE_RETRY(recv(socket, p, size, 0));
            if (rc < 0) {
                if (errno == EAGAIN) {
                    return;
                }
                if (len == 0) {  /* end of stream ? */
                    D("weird end-of-stream from unknown JDWP process");

                D("failed to read jdwp pid: %s", strerror(errno));
                goto CloseProcess;
            }
                p            += len;
                proc->in_len += len;
                size         -= len;

            proc->in_len += rc;
            if (proc->in_len != PID_LEN) {
                return;
            }
            /* we have read 4 characters, now decode the pid */
            memcpy(temp, proc->in_buff, 4);
            temp[4] = 0;

            if (sscanf( temp, "%04x", &proc->pid ) != 1) {
                D("could not decode JDWP %p PID number: '%s'", proc, temp);
            proc->in_buf[PID_LEN] = '\0';
            proc->in_len = -1;

            if (sscanf(proc->in_buf, "%04x", &proc->pid) != 1) {
                D("could not decode JDWP %p PID number: '%s'", proc, p);
                goto CloseProcess;
            }

            /* all is well, keep reading to detect connection closure */
            D("Adding pid %d to jdwp process list", proc->pid);
            jdwp_process_list_updated();
        }
        else
        {
        } else {
            /* the pid was read, if we get there it's probably because the connection
             * was closed (e.g. the JDWP process exited or crashed) */
            char buf[32];

            for (;;) {
                int  len = recv(socket, buf, sizeof(buf), 0);
            while (true) {
                int len = TEMP_FAILURE_RETRY(recv(socket, buf, sizeof(buf), 0));

                if (len <= 0) {
                    if (len < 0 && errno == EINTR)
                        continue;
                    if (len < 0 && errno == EAGAIN)
                        return;
                    else {
                        D("terminating JDWP %d connection: %s", proc->pid,
                          strerror(errno));
                if (len == 0) {
                    D("terminating JDWP %d connection: EOF", proc->pid);
                    break;
                } else if (len < 0) {
                    if (len < 0 && errno == EAGAIN) {
                        return;
                    }
                }
                else {
                    D( "ignoring unexpected JDWP %d control socket activity (%d bytes)",
                       proc->pid, len );

                    D("terminating JDWP %d connection: EOF", proc->pid);
                    break;
                } else {
                    D("ignoring unexpected JDWP %d control socket activity (%d bytes)", proc->pid,
                      len);
                }
            }

        CloseProcess:
            if (proc->pid >= 0) {
                D( "remove pid %d to jdwp process list", proc->pid );
            }
            jdwp_process_free(proc);
            return;
            goto CloseProcess;
        }
    }

    if (events & FDE_WRITE) {
        D("trying to write to JDWP pid controli (count=%d first=%d) %d",
          proc->pid, proc->out_count, proc->out_fds[0]);
        if (proc->out_count > 0) {
            int  fd = proc->out_fds[0];
            int  n, ret;
        D("trying to send fd to JDWP process (count = %zu)", proc->out_fds.size());
        if (!proc->out_fds.empty()) {
            int fd = proc->out_fds.back().get();
            struct cmsghdr* cmsg;
            struct msghdr msg;
            struct iovec iov;
@@ -366,75 +315,60 @@ jdwp_process_event( int socket, unsigned events, void* _proc )
                goto CloseProcess;
            }

            for (;;) {
                ret = sendmsg(proc->socket, &msg, 0);
                if (ret >= 0) {
                    adb_close(fd);
                    break;
                }
                if (errno == EINTR)
                    continue;
                D("sending new file descriptor to JDWP %d failed: %s",
                  proc->pid, strerror(errno));
            int ret = TEMP_FAILURE_RETRY(sendmsg(proc->socket, &msg, 0));
            if (ret < 0) {
                D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno));
                goto CloseProcess;
            }

            D("sent file descriptor %d to JDWP process %d",
              fd, proc->pid);
            adb_close(fd);

            D("sent file descriptor %d to JDWP process %d", fd, proc->pid);

            for (n = 1; n < proc->out_count; n++)
                proc->out_fds[n-1] = proc->out_fds[n];
            proc->out_fds.pop_back();

            if (!set_file_block_mode(proc->socket, false)) {
                VLOG(JDWP) << "failed to set non-blocking mode for fd " << proc->socket;
                goto CloseProcess;
            }

            if (--proc->out_count == 0)
            if (proc->out_fds.empty()) {
                fdevent_del(proc->fde, FDE_WRITE);
            }
        }
    }

    return;

int
create_jdwp_connection_fd(int  pid)
{
    JdwpProcess*  proc = _jdwp_list.next;
CloseProcess:
    proc->RemoveFromList();
    jdwp_process_list_updated();
}

int create_jdwp_connection_fd(int pid) {
    D("looking for pid %d in JDWP process list", pid);
    for ( ; proc != &_jdwp_list; proc = proc->next ) {
        if (proc->pid == pid) {
            goto FoundIt;
        }
    }
    D("search failed !!");
    return -1;

FoundIt:
    {
    for (auto& proc : _jdwp_list) {
        if (proc->pid == pid) {
            int fds[2];

        if (proc->out_count >= MAX_OUT_FDS) {
            D("%s: too many pending JDWP connection for pid %d",
              __FUNCTION__, pid);
            return -1;
        }

            if (adb_socketpair(fds) < 0) {
            D("%s: socket pair creation failed: %s",
              __FUNCTION__, strerror(errno));
                D("%s: socket pair creation failed: %s", __FUNCTION__, strerror(errno));
                return -1;
            }
            D("socketpair: (%d,%d)", fds[0], fds[1]);

        proc->out_fds[ proc->out_count ] = fds[1];
        if (++proc->out_count == 1)
            proc->out_fds.emplace_back(fds[1]);
            if (proc->out_fds.size() == 1) {
                fdevent_add(proc->fde, FDE_WRITE);
            }

            return fds[0];
        }
    }
    D("search failed !!");
    return -1;
}

/**  VM DEBUG CONTROL SOCKET
 **
@@ -450,16 +384,11 @@ struct JdwpControl {
    fdevent* fde;
};

static JdwpControl _jdwp_control;

static void
jdwp_control_event(int  s, unsigned events, void*  user);

static void jdwp_control_event(int s, unsigned events, void* user);

static int
jdwp_control_init( JdwpControl*  control,
                   const char*   sockname,
                   int           socknamelen )
{
static int jdwp_control_init(JdwpControl* control, const char* sockname, int socknamelen) {
    sockaddr_un addr;
    socklen_t addrlen;
    int s;
@@ -467,8 +396,7 @@ jdwp_control_init( JdwpControl* control,
    int pathlen = socknamelen;

    if (pathlen >= maxpath) {
        D( "vm debug control socket name too long (%d extra chars)",
           pathlen+1-maxpath );
        D("vm debug control socket name too long (%d extra chars)", pathlen + 1 - maxpath);
        return -1;
    }

@@ -476,25 +404,22 @@ jdwp_control_init( JdwpControl* control,
    addr.sun_family = AF_UNIX;
    memcpy(addr.sun_path, sockname, socknamelen);

    s = socket( AF_UNIX, SOCK_STREAM, 0 );
    s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
    if (s < 0) {
        D( "could not create vm debug control socket. %d: %s",
           errno, strerror(errno));
        D("could not create vm debug control socket. %d: %s", errno, strerror(errno));
        return -1;
    }

    addrlen = (pathlen + sizeof(addr.sun_family));
    addrlen = pathlen + sizeof(addr.sun_family);

    if (bind(s, reinterpret_cast<sockaddr*>(&addr), addrlen) < 0) {
        D( "could not bind vm debug control socket: %d: %s",
           errno, strerror(errno) );
        D("could not bind vm debug control socket: %d: %s", errno, strerror(errno));
        adb_close(s);
        return -1;
    }

    if (listen(s, 4) < 0) {
        D("listen failed in jdwp control socket: %d: %s",
          errno, strerror(errno));
        D("listen failed in jdwp control socket: %d: %s", errno, strerror(errno));
        adb_close(s);
        return -1;
    }
@@ -510,121 +435,102 @@ jdwp_control_init( JdwpControl* control,

    /* only wait for incoming connections */
    fdevent_add(control->fde, FDE_READ);
    close_on_exec(s);

    D("jdwp control socket started (%d)", control->listen_socket);
    return 0;
}


static void
jdwp_control_event( int  s, unsigned  events, void*  _control )
{
static void jdwp_control_event(int s, unsigned events, void* _control) {
    JdwpControl* control = (JdwpControl*)_control;

    if (events & FDE_READ) {
        sockaddr_storage ss;
        sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
        socklen_t addrlen = sizeof(ss);
        int                s = -1;
        JdwpProcess*       proc;

        do {
            s = adb_socket_accept(control->listen_socket, addrp, &addrlen);
        int s = adb_socket_accept(control->listen_socket, addrp, &addrlen);
        if (s < 0) {
                if (errno == EINTR)
                    continue;
            if (errno == ECONNABORTED) {
                /* oops, the JDWP process died really quick */
                D("oops, the JDWP process died really quick");
                return;
                }
            } else {
                /* the socket is probably closed ? */
                D( "weird accept() failed on jdwp control socket: %s",
                   strerror(errno) );
                D("weird accept() failed on jdwp control socket: %s", strerror(errno));
                return;
            }
        }
        while (s < 0);

        proc = jdwp_process_alloc( s );
        if (proc == NULL)
            return;
        auto proc = std::make_unique<JdwpProcess>(s);
        if (!proc) {
            fatal("failed to allocate JdwpProcess");
        }
}


static JdwpControl   _jdwp_control;
        _jdwp_list.emplace_back(std::move(proc));
    }
}

/** "jdwp" local service implementation
 ** this simply returns the list of known JDWP process pids
 **/

struct JdwpSocket {
    asocket  socket;
    int      pass;
struct JdwpSocket : public asocket {
    bool pass;
};

static void
jdwp_socket_close( asocket*  s )
{
    asocket*  peer = s->peer;
static void jdwp_socket_close(asocket* s) {
    D("LS(%d): closing jdwp socket", s->id);

    remove_socket(s);

    if (peer) {
        peer->peer = NULL;
        peer->close(peer);
    if (s->peer) {
        D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
        s->peer->peer = nullptr;
        s->peer->close(s->peer);
        s->peer = nullptr;
    }

    remove_socket(s);
    free(s);
}

static int
jdwp_socket_enqueue( asocket*  s, apacket*  p )
{
static int jdwp_socket_enqueue(asocket* s, apacket* p) {
    /* you can't write to this asocket */
    D("LS(%d): JDWP socket received data?", s->id);
    put_apacket(p);
    s->peer->close(s->peer);
    return -1;
}


static void
jdwp_socket_ready( asocket*  s )
{
static void jdwp_socket_ready(asocket* s) {
    JdwpSocket* jdwp = (JdwpSocket*)s;
    asocket*     peer = jdwp->socket.peer;
    asocket* peer = jdwp->peer;

    /* on the first call, send the list of pids,
     * on the second one, close the connection
     */
    if (jdwp->pass == 0) {
    if (!jdwp->pass) {
        apacket* p = get_apacket();
        p->len = jdwp_process_list((char*)p->data, s->get_max_payload());
        peer->enqueue(peer, p);
        jdwp->pass = 1;
    }
    else {
        jdwp->pass = true;
    } else {
        peer->close(peer);
    }
}

asocket*
create_jdwp_service_socket( void )
{
asocket* create_jdwp_service_socket(void) {
    JdwpSocket* s = reinterpret_cast<JdwpSocket*>(calloc(sizeof(*s), 1));

    if (s == NULL)
        return NULL;
    if (!s) {
        fatal("failed to allocate JdwpSocket");
    }

    install_local_socket(&s->socket);
    install_local_socket(s);

    s->socket.ready   = jdwp_socket_ready;
    s->socket.enqueue = jdwp_socket_enqueue;
    s->socket.close   = jdwp_socket_close;
    s->pass           = 0;
    s->ready = jdwp_socket_ready;
    s->enqueue = jdwp_socket_enqueue;
    s->close = jdwp_socket_close;
    s->pass = false;

    return &s->socket;
    return s;
}

/** "track-jdwp" local service implementation
@@ -632,113 +538,88 @@ create_jdwp_service_socket( void )
 ** to the client...
 **/

struct JdwpTracker {
    asocket       socket;
    JdwpTracker*  next;
    JdwpTracker*  prev;
    int           need_update;
struct JdwpTracker : public asocket {
    bool need_initial;
};

static JdwpTracker   _jdwp_trackers_list;

static std::vector<std::unique_ptr<JdwpTracker>> _jdwp_trackers;

static void
jdwp_process_list_updated(void)
{
static void jdwp_process_list_updated(void) {
    char buffer[1024];
    int              len;
    JdwpTracker*  t = _jdwp_trackers_list.next;
    int len = jdwp_process_list_msg(buffer, sizeof(buffer));

    len = jdwp_process_list_msg(buffer, sizeof(buffer));

    for ( ; t != &_jdwp_trackers_list; t = t->next ) {
    for (auto& t : _jdwp_trackers) {
        apacket* p = get_apacket();
        asocket*  peer = t->socket.peer;
        memcpy(p->data, buffer, len);
        p->len = len;
        peer->enqueue( peer, p );

        if (t->peer) {
            // The tracker might not have been connected yet.
            t->peer->enqueue(t->peer, p);
        }
    }
}

static void
jdwp_tracker_close( asocket*  s )
{
    JdwpTracker*  tracker = (JdwpTracker*) s;
    asocket*      peer    = s->peer;
static void jdwp_tracker_close(asocket* s) {
    D("LS(%d): destroying jdwp tracker service", s->id);

    if (peer) {
        peer->peer = NULL;
        peer->close(peer);
    if (s->peer) {
        D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
        s->peer->peer = nullptr;
        s->peer->close(s->peer);
        s->peer = nullptr;
    }

    remove_socket(s);

    tracker->prev->next = tracker->next;
    tracker->next->prev = tracker->prev;

    free(s);
    auto pred = [s](const auto& tracker) { return tracker.get() == s; };
    std::remove_if(_jdwp_trackers.begin(), _jdwp_trackers.end(), pred);
}

static void
jdwp_tracker_ready( asocket*  s )
{
static void jdwp_tracker_ready(asocket* s) {
    JdwpTracker* t = (JdwpTracker*)s;

    if (t->need_update) {
    if (t->need_initial) {
        apacket* p = get_apacket();
        t->need_update = 0;
        t->need_initial = false;
        p->len = jdwp_process_list_msg((char*)p->data, s->get_max_payload());
        s->peer->enqueue(s->peer, p);
    }
}

static int
jdwp_tracker_enqueue( asocket*  s, apacket*  p )
{
static int jdwp_tracker_enqueue(asocket* s, apacket* p) {
    /* you can't write to this socket */
    D("LS(%d): JDWP tracker received data?", s->id);
    put_apacket(p);
    s->peer->close(s->peer);
    return -1;
}

asocket* create_jdwp_tracker_service_socket(void) {
    auto t = std::make_unique<JdwpTracker>();
    if (!t) {
        fatal("failed to allocate JdwpTracker");
    }

asocket*
create_jdwp_tracker_service_socket( void )
{
    JdwpTracker* t = reinterpret_cast<JdwpTracker*>(calloc(sizeof(*t), 1));

    if (t == NULL)
        return NULL;
    memset(t.get(), 0, sizeof(asocket));

    t->next = &_jdwp_trackers_list;
    t->prev = t->next->prev;
    install_local_socket(t.get());
    D("LS(%d): created new jdwp tracker service", t->id);

    t->next->prev = t;
    t->prev->next = t;
    t->ready = jdwp_tracker_ready;
    t->enqueue = jdwp_tracker_enqueue;
    t->close = jdwp_tracker_close;
    t->need_initial = true;

    install_local_socket(&t->socket);
    asocket* result = t.get();

    t->socket.ready   = jdwp_tracker_ready;
    t->socket.enqueue = jdwp_tracker_enqueue;
    t->socket.close   = jdwp_tracker_close;
    t->need_update    = 1;
    _jdwp_trackers.emplace_back(std::move(t));

    return &t->socket;
    return result;
}


int
init_jdwp(void)
{
    _jdwp_list.next = &_jdwp_list;
    _jdwp_list.prev = &_jdwp_list;

    _jdwp_trackers_list.next = &_jdwp_trackers_list;
    _jdwp_trackers_list.prev = &_jdwp_trackers_list;

    return jdwp_control_init( &_jdwp_control,
                              JDWP_CONTROL_NAME,
                              JDWP_CONTROL_NAME_LEN );
int init_jdwp(void) {
    return jdwp_control_init(&_jdwp_control, JDWP_CONTROL_NAME, JDWP_CONTROL_NAME_LEN);
}

#endif /* !ADB_HOST */