Loading adb/jdwp_service.cpp +287 −406 Original line number Original line Diff line number Diff line Loading @@ -14,7 +14,7 @@ * limitations under the License. * limitations under the License. */ */ /* implement the "debug-ports" and "track-debug-ports" device services */ #if !ADB_HOST #define TRACE_TAG JDWP #define TRACE_TAG JDWP Loading @@ -24,22 +24,29 @@ #include <stdio.h> #include <stdio.h> #include <stdlib.h> #include <stdlib.h> #include <string.h> #include <string.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> #include <unistd.h> #include <list> #include <memory> #include <vector> #include "adb.h" #include "adb.h" #include "adb_io.h" #include "adb_utils.h" #include "adb_utils.h" /* here's how these things work. /* here's how these things work. when adbd starts, it creates a unix server socket 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) to use the private namespace instead of the file system) when a new JDWP daemon thread starts in a new VM process, it creates 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> | | hello I'm in process <pid> | Loading Loading @@ -72,7 +79,7 @@ to the JDWP process with the help of sendmsg() to the JDWP process with the help of sendmsg() JDWP thread @vm-debug-control JDWP thread @jdwp-control | | | | | <----------------------| | <----------------------| | OK, try this file descriptor | | OK, try this file descriptor | Loading Loading @@ -116,229 +123,171 @@ ** for each JDWP process, we record its pid and its connected socket ** 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> struct JdwpProcess; #include <sys/un.h> static std::list<std::unique_ptr<JdwpProcess>> _jdwp_list; struct JdwpProcess { struct JdwpProcess { JdwpProcess* next; explicit JdwpProcess(int socket) { JdwpProcess* prev; this->socket = socket; int pid; this->fde = fdevent_create(socket, jdwp_process_event, this); 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 */ }; static JdwpProcess _jdwp_list; if (!this->fde) { fatal("could not create fdevent for new JDWP process"); 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); } } this->fde->state |= FDE_DONT_CLOSE; static int /* start by waiting for the PID */ jdwp_process_list_msg( char* buffer, int bufferlen ) fdevent_add(this->fde, FDE_READ); { 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; } } ~JdwpProcess() { static void jdwp_process_list_updated(void); if (this->socket >= 0) { adb_shutdown(this->socket); static void adb_close(this->socket); jdwp_process_free( JdwpProcess* proc ) this->socket = -1; { 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; } } if (proc->fde != NULL) { if (this->fde) { fdevent_destroy(proc->fde); fdevent_destroy(this->fde); proc->fde = NULL; this->fde = nullptr; } } proc->pid = -1; for (n = 0; n < proc->out_count; n++) { out_fds.clear(); adb_close(proc->out_fds[n]); } } proc->out_count = 0; free(proc); void RemoveFromList() { if (this->pid >= 0) { jdwp_process_list_updated(); 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* static size_t jdwp_process_list(char* buffer, size_t bufferlen) { jdwp_process_alloc( int socket ) std::string temp; { JdwpProcess* proc = reinterpret_cast<JdwpProcess*>( calloc(1, sizeof(*proc))); if (proc == NULL) { for (auto& proc : _jdwp_list) { D("not enough memory to create new JDWP process"); /* skip transient connections */ return NULL; if (proc->pid < 0) { continue; } } proc->socket = socket; std::string next = std::to_string(proc->pid) + "\n"; proc->pid = -1; if (temp.length() + next.length() > bufferlen) { proc->next = proc; D("truncating JDWP process list (max len = %zu)", bufferlen); proc->prev = proc; break; } proc->fde = fdevent_create( socket, jdwp_process_event, proc ); temp.append(next); if (proc->fde == NULL) { D("could not create fdevent for new JDWP process" ); free(proc); return NULL; } } proc->fde->state |= FDE_DONT_CLOSE; memcpy(buffer, temp.data(), temp.length()); proc->in_len = 0; return temp.length(); 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); 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 static void jdwp_process_event(int socket, unsigned events, void* _proc) { jdwp_process_event( int socket, unsigned events, void* _proc ) { JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc); JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc); if (events & FDE_READ) { if (events & FDE_READ) { if (proc->pid < 0) { if (proc->pid < 0) { /* read the PID as a 4-hexchar string */ /* read the PID as a 4-hexchar string */ char* p = proc->in_buff + proc->in_len; if (proc->in_len < 0) { int size = 4 - proc->in_len; fatal("attempting to read JDWP pid again?"); 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)); 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; goto CloseProcess; } } p += len; proc->in_len += len; proc->in_len += rc; size -= len; 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) { proc->in_buf[PID_LEN] = '\0'; D("could not decode JDWP %p PID number: '%s'", proc, temp); 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; goto CloseProcess; } } /* all is well, keep reading to detect connection closure */ /* all is well, keep reading to detect connection closure */ D("Adding pid %d to jdwp process list", proc->pid); D("Adding pid %d to jdwp process list", proc->pid); jdwp_process_list_updated(); jdwp_process_list_updated(); } } else { else { /* the pid was read, if we get there it's probably because the connection /* the pid was read, if we get there it's probably because the connection * was closed (e.g. the JDWP process exited or crashed) */ * was closed (e.g. the JDWP process exited or crashed) */ char buf[32]; char buf[32]; for (;;) { while (true) { int len = recv(socket, buf, sizeof(buf), 0); int len = TEMP_FAILURE_RETRY(recv(socket, buf, sizeof(buf), 0)); if (len <= 0) { if (len == 0) { if (len < 0 && errno == EINTR) D("terminating JDWP %d connection: EOF", proc->pid); continue; if (len < 0 && errno == EAGAIN) return; else { D("terminating JDWP %d connection: %s", proc->pid, strerror(errno)); break; break; } else if (len < 0) { if (len < 0 && errno == EAGAIN) { return; } } } else { D("terminating JDWP %d connection: EOF", proc->pid); D( "ignoring unexpected JDWP %d control socket activity (%d bytes)", break; proc->pid, len ); } else { D("ignoring unexpected JDWP %d control socket activity (%d bytes)", proc->pid, len); } } } } CloseProcess: goto CloseProcess; if (proc->pid >= 0) { D( "remove pid %d to jdwp process list", proc->pid ); } jdwp_process_free(proc); return; } } } } if (events & FDE_WRITE) { if (events & FDE_WRITE) { D("trying to write to JDWP pid controli (count=%d first=%d) %d", D("trying to send fd to JDWP process (count = %zu)", proc->out_fds.size()); proc->pid, proc->out_count, proc->out_fds[0]); if (!proc->out_fds.empty()) { if (proc->out_count > 0) { int fd = proc->out_fds.back().get(); int fd = proc->out_fds[0]; int n, ret; struct cmsghdr* cmsg; struct cmsghdr* cmsg; struct msghdr msg; struct msghdr msg; struct iovec iov; struct iovec iov; Loading Loading @@ -366,75 +315,60 @@ jdwp_process_event( int socket, unsigned events, void* _proc ) goto CloseProcess; goto CloseProcess; } } for (;;) { int ret = TEMP_FAILURE_RETRY(sendmsg(proc->socket, &msg, 0)); ret = sendmsg(proc->socket, &msg, 0); if (ret < 0) { if (ret >= 0) { D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno)); adb_close(fd); break; } if (errno == EINTR) continue; D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno)); goto CloseProcess; goto CloseProcess; } } D("sent file descriptor %d to JDWP process %d", adb_close(fd); fd, proc->pid); D("sent file descriptor %d to JDWP process %d", fd, proc->pid); for (n = 1; n < proc->out_count; n++) proc->out_fds.pop_back(); proc->out_fds[n-1] = proc->out_fds[n]; if (!set_file_block_mode(proc->socket, false)) { if (!set_file_block_mode(proc->socket, false)) { VLOG(JDWP) << "failed to set non-blocking mode for fd " << proc->socket; VLOG(JDWP) << "failed to set non-blocking mode for fd " << proc->socket; goto CloseProcess; goto CloseProcess; } } if (--proc->out_count == 0) if (proc->out_fds.empty()) { fdevent_del(proc->fde, FDE_WRITE); fdevent_del(proc->fde, FDE_WRITE); } } } } } } return; int CloseProcess: create_jdwp_connection_fd(int pid) proc->RemoveFromList(); { jdwp_process_list_updated(); JdwpProcess* proc = _jdwp_list.next; } int create_jdwp_connection_fd(int pid) { D("looking for pid %d in JDWP process list", 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]; 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) { if (adb_socketpair(fds) < 0) { D("%s: socket pair creation failed: %s", D("%s: socket pair creation failed: %s", __FUNCTION__, strerror(errno)); __FUNCTION__, strerror(errno)); return -1; return -1; } } D("socketpair: (%d,%d)", fds[0], fds[1]); D("socketpair: (%d,%d)", fds[0], fds[1]); proc->out_fds[ proc->out_count ] = fds[1]; proc->out_fds.emplace_back(fds[1]); if (++proc->out_count == 1) if (proc->out_fds.size() == 1) { fdevent_add(proc->fde, FDE_WRITE); fdevent_add(proc->fde, FDE_WRITE); } return fds[0]; return fds[0]; } } } } D("search failed !!"); return -1; } /** VM DEBUG CONTROL SOCKET /** VM DEBUG CONTROL SOCKET ** ** Loading @@ -450,16 +384,11 @@ struct JdwpControl { fdevent* fde; fdevent* fde; }; }; static JdwpControl _jdwp_control; static void static void jdwp_control_event(int s, unsigned events, void* user); jdwp_control_event(int s, unsigned events, void* user); static int static int jdwp_control_init(JdwpControl* control, const char* sockname, int socknamelen) { jdwp_control_init( JdwpControl* control, const char* sockname, int socknamelen ) { sockaddr_un addr; sockaddr_un addr; socklen_t addrlen; socklen_t addrlen; int s; int s; Loading @@ -467,8 +396,7 @@ jdwp_control_init( JdwpControl* control, int pathlen = socknamelen; int pathlen = socknamelen; if (pathlen >= maxpath) { if (pathlen >= maxpath) { D( "vm debug control socket name too long (%d extra chars)", D("vm debug control socket name too long (%d extra chars)", pathlen + 1 - maxpath); pathlen+1-maxpath ); return -1; return -1; } } Loading @@ -476,25 +404,22 @@ jdwp_control_init( JdwpControl* control, addr.sun_family = AF_UNIX; addr.sun_family = AF_UNIX; memcpy(addr.sun_path, sockname, socknamelen); 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) { if (s < 0) { D( "could not create vm debug control socket. %d: %s", D("could not create vm debug control socket. %d: %s", errno, strerror(errno)); errno, strerror(errno)); return -1; return -1; } } addrlen = (pathlen + sizeof(addr.sun_family)); addrlen = pathlen + sizeof(addr.sun_family); if (bind(s, reinterpret_cast<sockaddr*>(&addr), addrlen) < 0) { if (bind(s, reinterpret_cast<sockaddr*>(&addr), addrlen) < 0) { D( "could not bind vm debug control socket: %d: %s", D("could not bind vm debug control socket: %d: %s", errno, strerror(errno)); errno, strerror(errno) ); adb_close(s); adb_close(s); return -1; return -1; } } if (listen(s, 4) < 0) { if (listen(s, 4) < 0) { D("listen failed in jdwp control socket: %d: %s", D("listen failed in jdwp control socket: %d: %s", errno, strerror(errno)); errno, strerror(errno)); adb_close(s); adb_close(s); return -1; return -1; } } Loading @@ -510,121 +435,102 @@ jdwp_control_init( JdwpControl* control, /* only wait for incoming connections */ /* only wait for incoming connections */ fdevent_add(control->fde, FDE_READ); fdevent_add(control->fde, FDE_READ); close_on_exec(s); D("jdwp control socket started (%d)", control->listen_socket); D("jdwp control socket started (%d)", control->listen_socket); return 0; 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; JdwpControl* control = (JdwpControl*)_control; if (events & FDE_READ) { if (events & FDE_READ) { sockaddr_storage ss; sockaddr_storage ss; sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss); sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss); socklen_t addrlen = sizeof(ss); socklen_t addrlen = sizeof(ss); int s = -1; int s = adb_socket_accept(control->listen_socket, addrp, &addrlen); JdwpProcess* proc; do { s = adb_socket_accept(control->listen_socket, addrp, &addrlen); if (s < 0) { if (s < 0) { if (errno == EINTR) continue; if (errno == ECONNABORTED) { if (errno == ECONNABORTED) { /* oops, the JDWP process died really quick */ /* oops, the JDWP process died really quick */ D("oops, the JDWP process died really quick"); D("oops, the JDWP process died really quick"); return; return; } } else { /* the socket is probably closed ? */ /* the socket is probably closed ? */ D( "weird accept() failed on jdwp control socket: %s", D("weird accept() failed on jdwp control socket: %s", strerror(errno)); strerror(errno) ); return; return; } } } } while (s < 0); proc = jdwp_process_alloc( s ); auto proc = std::make_unique<JdwpProcess>(s); if (proc == NULL) if (!proc) { return; fatal("failed to allocate JdwpProcess"); } } } static JdwpControl _jdwp_control; _jdwp_list.emplace_back(std::move(proc)); } } /** "jdwp" local service implementation /** "jdwp" local service implementation ** this simply returns the list of known JDWP process pids ** this simply returns the list of known JDWP process pids **/ **/ struct JdwpSocket { struct JdwpSocket : public asocket { asocket socket; bool pass; int pass; }; }; static void static void jdwp_socket_close(asocket* s) { jdwp_socket_close( asocket* s ) D("LS(%d): closing jdwp socket", s->id); { asocket* peer = s->peer; remove_socket(s); if (s->peer) { D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd); if (peer) { s->peer->peer = nullptr; peer->peer = NULL; s->peer->close(s->peer); peer->close(peer); s->peer = nullptr; } } remove_socket(s); free(s); free(s); } } static int static int jdwp_socket_enqueue(asocket* s, apacket* p) { jdwp_socket_enqueue( asocket* s, apacket* p ) { /* you can't write to this asocket */ /* you can't write to this asocket */ D("LS(%d): JDWP socket received data?", s->id); put_apacket(p); put_apacket(p); s->peer->close(s->peer); s->peer->close(s->peer); return -1; return -1; } } static void jdwp_socket_ready(asocket* s) { static void jdwp_socket_ready( asocket* s ) { JdwpSocket* jdwp = (JdwpSocket*)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 first call, send the list of pids, * on the second one, close the connection * on the second one, close the connection */ */ if (jdwp->pass == 0) { if (!jdwp->pass) { apacket* p = get_apacket(); apacket* p = get_apacket(); p->len = jdwp_process_list((char*)p->data, s->get_max_payload()); p->len = jdwp_process_list((char*)p->data, s->get_max_payload()); peer->enqueue(peer, p); peer->enqueue(peer, p); jdwp->pass = 1; jdwp->pass = true; } } else { else { peer->close(peer); peer->close(peer); } } } } asocket* asocket* create_jdwp_service_socket(void) { create_jdwp_service_socket( void ) { JdwpSocket* s = reinterpret_cast<JdwpSocket*>(calloc(sizeof(*s), 1)); JdwpSocket* s = reinterpret_cast<JdwpSocket*>(calloc(sizeof(*s), 1)); if (s == NULL) if (!s) { return NULL; fatal("failed to allocate JdwpSocket"); } install_local_socket(&s->socket); install_local_socket(s); s->socket.ready = jdwp_socket_ready; s->ready = jdwp_socket_ready; s->socket.enqueue = jdwp_socket_enqueue; s->enqueue = jdwp_socket_enqueue; s->socket.close = jdwp_socket_close; s->close = jdwp_socket_close; s->pass = 0; s->pass = false; return &s->socket; return s; } } /** "track-jdwp" local service implementation /** "track-jdwp" local service implementation Loading @@ -632,113 +538,88 @@ create_jdwp_service_socket( void ) ** to the client... ** to the client... **/ **/ struct JdwpTracker { struct JdwpTracker : public asocket { asocket socket; bool need_initial; JdwpTracker* next; JdwpTracker* prev; int need_update; }; }; static JdwpTracker _jdwp_trackers_list; static std::vector<std::unique_ptr<JdwpTracker>> _jdwp_trackers; static void static void jdwp_process_list_updated(void) { jdwp_process_list_updated(void) { char buffer[1024]; char buffer[1024]; int len; int len = jdwp_process_list_msg(buffer, sizeof(buffer)); JdwpTracker* t = _jdwp_trackers_list.next; len = jdwp_process_list_msg(buffer, sizeof(buffer)); for (auto& t : _jdwp_trackers) { for ( ; t != &_jdwp_trackers_list; t = t->next ) { apacket* p = get_apacket(); apacket* p = get_apacket(); asocket* peer = t->socket.peer; memcpy(p->data, buffer, len); memcpy(p->data, buffer, len); p->len = 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 static void jdwp_tracker_close(asocket* s) { jdwp_tracker_close( asocket* s ) D("LS(%d): destroying jdwp tracker service", s->id); { JdwpTracker* tracker = (JdwpTracker*) s; asocket* peer = s->peer; if (peer) { if (s->peer) { peer->peer = NULL; D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd); peer->close(peer); s->peer->peer = nullptr; s->peer->close(s->peer); s->peer = nullptr; } } remove_socket(s); remove_socket(s); tracker->prev->next = tracker->next; auto pred = [s](const auto& tracker) { return tracker.get() == s; }; tracker->next->prev = tracker->prev; std::remove_if(_jdwp_trackers.begin(), _jdwp_trackers.end(), pred); free(s); } } static void static void jdwp_tracker_ready(asocket* s) { jdwp_tracker_ready( asocket* s ) { JdwpTracker* t = (JdwpTracker*)s; JdwpTracker* t = (JdwpTracker*)s; if (t->need_update) { if (t->need_initial) { apacket* p = get_apacket(); 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()); p->len = jdwp_process_list_msg((char*)p->data, s->get_max_payload()); s->peer->enqueue(s->peer, p); s->peer->enqueue(s->peer, p); } } } } static int static int jdwp_tracker_enqueue(asocket* s, apacket* p) { jdwp_tracker_enqueue( asocket* s, apacket* p ) { /* you can't write to this socket */ /* you can't write to this socket */ D("LS(%d): JDWP tracker received data?", s->id); put_apacket(p); put_apacket(p); s->peer->close(s->peer); s->peer->close(s->peer); return -1; return -1; } } asocket* create_jdwp_tracker_service_socket(void) { auto t = std::make_unique<JdwpTracker>(); if (!t) { fatal("failed to allocate JdwpTracker"); } asocket* memset(t.get(), 0, sizeof(asocket)); create_jdwp_tracker_service_socket( void ) { JdwpTracker* t = reinterpret_cast<JdwpTracker*>(calloc(sizeof(*t), 1)); if (t == NULL) return NULL; t->next = &_jdwp_trackers_list; install_local_socket(t.get()); t->prev = t->next->prev; D("LS(%d): created new jdwp tracker service", t->id); t->next->prev = t; t->ready = jdwp_tracker_ready; t->prev->next = t; 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; _jdwp_trackers.emplace_back(std::move(t)); t->socket.enqueue = jdwp_tracker_enqueue; t->socket.close = jdwp_tracker_close; t->need_update = 1; return &t->socket; return result; } } int init_jdwp(void) { int return jdwp_control_init(&_jdwp_control, JDWP_CONTROL_NAME, JDWP_CONTROL_NAME_LEN); 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 ); } } #endif /* !ADB_HOST */ #endif /* !ADB_HOST */ Loading
adb/jdwp_service.cpp +287 −406 Original line number Original line Diff line number Diff line Loading @@ -14,7 +14,7 @@ * limitations under the License. * limitations under the License. */ */ /* implement the "debug-ports" and "track-debug-ports" device services */ #if !ADB_HOST #define TRACE_TAG JDWP #define TRACE_TAG JDWP Loading @@ -24,22 +24,29 @@ #include <stdio.h> #include <stdio.h> #include <stdlib.h> #include <stdlib.h> #include <string.h> #include <string.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> #include <unistd.h> #include <list> #include <memory> #include <vector> #include "adb.h" #include "adb.h" #include "adb_io.h" #include "adb_utils.h" #include "adb_utils.h" /* here's how these things work. /* here's how these things work. when adbd starts, it creates a unix server socket 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) to use the private namespace instead of the file system) when a new JDWP daemon thread starts in a new VM process, it creates 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> | | hello I'm in process <pid> | Loading Loading @@ -72,7 +79,7 @@ to the JDWP process with the help of sendmsg() to the JDWP process with the help of sendmsg() JDWP thread @vm-debug-control JDWP thread @jdwp-control | | | | | <----------------------| | <----------------------| | OK, try this file descriptor | | OK, try this file descriptor | Loading Loading @@ -116,229 +123,171 @@ ** for each JDWP process, we record its pid and its connected socket ** 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> struct JdwpProcess; #include <sys/un.h> static std::list<std::unique_ptr<JdwpProcess>> _jdwp_list; struct JdwpProcess { struct JdwpProcess { JdwpProcess* next; explicit JdwpProcess(int socket) { JdwpProcess* prev; this->socket = socket; int pid; this->fde = fdevent_create(socket, jdwp_process_event, this); 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 */ }; static JdwpProcess _jdwp_list; if (!this->fde) { fatal("could not create fdevent for new JDWP process"); 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); } } this->fde->state |= FDE_DONT_CLOSE; static int /* start by waiting for the PID */ jdwp_process_list_msg( char* buffer, int bufferlen ) fdevent_add(this->fde, FDE_READ); { 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; } } ~JdwpProcess() { static void jdwp_process_list_updated(void); if (this->socket >= 0) { adb_shutdown(this->socket); static void adb_close(this->socket); jdwp_process_free( JdwpProcess* proc ) this->socket = -1; { 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; } } if (proc->fde != NULL) { if (this->fde) { fdevent_destroy(proc->fde); fdevent_destroy(this->fde); proc->fde = NULL; this->fde = nullptr; } } proc->pid = -1; for (n = 0; n < proc->out_count; n++) { out_fds.clear(); adb_close(proc->out_fds[n]); } } proc->out_count = 0; free(proc); void RemoveFromList() { if (this->pid >= 0) { jdwp_process_list_updated(); 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* static size_t jdwp_process_list(char* buffer, size_t bufferlen) { jdwp_process_alloc( int socket ) std::string temp; { JdwpProcess* proc = reinterpret_cast<JdwpProcess*>( calloc(1, sizeof(*proc))); if (proc == NULL) { for (auto& proc : _jdwp_list) { D("not enough memory to create new JDWP process"); /* skip transient connections */ return NULL; if (proc->pid < 0) { continue; } } proc->socket = socket; std::string next = std::to_string(proc->pid) + "\n"; proc->pid = -1; if (temp.length() + next.length() > bufferlen) { proc->next = proc; D("truncating JDWP process list (max len = %zu)", bufferlen); proc->prev = proc; break; } proc->fde = fdevent_create( socket, jdwp_process_event, proc ); temp.append(next); if (proc->fde == NULL) { D("could not create fdevent for new JDWP process" ); free(proc); return NULL; } } proc->fde->state |= FDE_DONT_CLOSE; memcpy(buffer, temp.data(), temp.length()); proc->in_len = 0; return temp.length(); 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); 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 static void jdwp_process_event(int socket, unsigned events, void* _proc) { jdwp_process_event( int socket, unsigned events, void* _proc ) { JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc); JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc); if (events & FDE_READ) { if (events & FDE_READ) { if (proc->pid < 0) { if (proc->pid < 0) { /* read the PID as a 4-hexchar string */ /* read the PID as a 4-hexchar string */ char* p = proc->in_buff + proc->in_len; if (proc->in_len < 0) { int size = 4 - proc->in_len; fatal("attempting to read JDWP pid again?"); 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)); 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; goto CloseProcess; } } p += len; proc->in_len += len; proc->in_len += rc; size -= len; 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) { proc->in_buf[PID_LEN] = '\0'; D("could not decode JDWP %p PID number: '%s'", proc, temp); 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; goto CloseProcess; } } /* all is well, keep reading to detect connection closure */ /* all is well, keep reading to detect connection closure */ D("Adding pid %d to jdwp process list", proc->pid); D("Adding pid %d to jdwp process list", proc->pid); jdwp_process_list_updated(); jdwp_process_list_updated(); } } else { else { /* the pid was read, if we get there it's probably because the connection /* the pid was read, if we get there it's probably because the connection * was closed (e.g. the JDWP process exited or crashed) */ * was closed (e.g. the JDWP process exited or crashed) */ char buf[32]; char buf[32]; for (;;) { while (true) { int len = recv(socket, buf, sizeof(buf), 0); int len = TEMP_FAILURE_RETRY(recv(socket, buf, sizeof(buf), 0)); if (len <= 0) { if (len == 0) { if (len < 0 && errno == EINTR) D("terminating JDWP %d connection: EOF", proc->pid); continue; if (len < 0 && errno == EAGAIN) return; else { D("terminating JDWP %d connection: %s", proc->pid, strerror(errno)); break; break; } else if (len < 0) { if (len < 0 && errno == EAGAIN) { return; } } } else { D("terminating JDWP %d connection: EOF", proc->pid); D( "ignoring unexpected JDWP %d control socket activity (%d bytes)", break; proc->pid, len ); } else { D("ignoring unexpected JDWP %d control socket activity (%d bytes)", proc->pid, len); } } } } CloseProcess: goto CloseProcess; if (proc->pid >= 0) { D( "remove pid %d to jdwp process list", proc->pid ); } jdwp_process_free(proc); return; } } } } if (events & FDE_WRITE) { if (events & FDE_WRITE) { D("trying to write to JDWP pid controli (count=%d first=%d) %d", D("trying to send fd to JDWP process (count = %zu)", proc->out_fds.size()); proc->pid, proc->out_count, proc->out_fds[0]); if (!proc->out_fds.empty()) { if (proc->out_count > 0) { int fd = proc->out_fds.back().get(); int fd = proc->out_fds[0]; int n, ret; struct cmsghdr* cmsg; struct cmsghdr* cmsg; struct msghdr msg; struct msghdr msg; struct iovec iov; struct iovec iov; Loading Loading @@ -366,75 +315,60 @@ jdwp_process_event( int socket, unsigned events, void* _proc ) goto CloseProcess; goto CloseProcess; } } for (;;) { int ret = TEMP_FAILURE_RETRY(sendmsg(proc->socket, &msg, 0)); ret = sendmsg(proc->socket, &msg, 0); if (ret < 0) { if (ret >= 0) { D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno)); adb_close(fd); break; } if (errno == EINTR) continue; D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno)); goto CloseProcess; goto CloseProcess; } } D("sent file descriptor %d to JDWP process %d", adb_close(fd); fd, proc->pid); D("sent file descriptor %d to JDWP process %d", fd, proc->pid); for (n = 1; n < proc->out_count; n++) proc->out_fds.pop_back(); proc->out_fds[n-1] = proc->out_fds[n]; if (!set_file_block_mode(proc->socket, false)) { if (!set_file_block_mode(proc->socket, false)) { VLOG(JDWP) << "failed to set non-blocking mode for fd " << proc->socket; VLOG(JDWP) << "failed to set non-blocking mode for fd " << proc->socket; goto CloseProcess; goto CloseProcess; } } if (--proc->out_count == 0) if (proc->out_fds.empty()) { fdevent_del(proc->fde, FDE_WRITE); fdevent_del(proc->fde, FDE_WRITE); } } } } } } return; int CloseProcess: create_jdwp_connection_fd(int pid) proc->RemoveFromList(); { jdwp_process_list_updated(); JdwpProcess* proc = _jdwp_list.next; } int create_jdwp_connection_fd(int pid) { D("looking for pid %d in JDWP process list", 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]; 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) { if (adb_socketpair(fds) < 0) { D("%s: socket pair creation failed: %s", D("%s: socket pair creation failed: %s", __FUNCTION__, strerror(errno)); __FUNCTION__, strerror(errno)); return -1; return -1; } } D("socketpair: (%d,%d)", fds[0], fds[1]); D("socketpair: (%d,%d)", fds[0], fds[1]); proc->out_fds[ proc->out_count ] = fds[1]; proc->out_fds.emplace_back(fds[1]); if (++proc->out_count == 1) if (proc->out_fds.size() == 1) { fdevent_add(proc->fde, FDE_WRITE); fdevent_add(proc->fde, FDE_WRITE); } return fds[0]; return fds[0]; } } } } D("search failed !!"); return -1; } /** VM DEBUG CONTROL SOCKET /** VM DEBUG CONTROL SOCKET ** ** Loading @@ -450,16 +384,11 @@ struct JdwpControl { fdevent* fde; fdevent* fde; }; }; static JdwpControl _jdwp_control; static void static void jdwp_control_event(int s, unsigned events, void* user); jdwp_control_event(int s, unsigned events, void* user); static int static int jdwp_control_init(JdwpControl* control, const char* sockname, int socknamelen) { jdwp_control_init( JdwpControl* control, const char* sockname, int socknamelen ) { sockaddr_un addr; sockaddr_un addr; socklen_t addrlen; socklen_t addrlen; int s; int s; Loading @@ -467,8 +396,7 @@ jdwp_control_init( JdwpControl* control, int pathlen = socknamelen; int pathlen = socknamelen; if (pathlen >= maxpath) { if (pathlen >= maxpath) { D( "vm debug control socket name too long (%d extra chars)", D("vm debug control socket name too long (%d extra chars)", pathlen + 1 - maxpath); pathlen+1-maxpath ); return -1; return -1; } } Loading @@ -476,25 +404,22 @@ jdwp_control_init( JdwpControl* control, addr.sun_family = AF_UNIX; addr.sun_family = AF_UNIX; memcpy(addr.sun_path, sockname, socknamelen); 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) { if (s < 0) { D( "could not create vm debug control socket. %d: %s", D("could not create vm debug control socket. %d: %s", errno, strerror(errno)); errno, strerror(errno)); return -1; return -1; } } addrlen = (pathlen + sizeof(addr.sun_family)); addrlen = pathlen + sizeof(addr.sun_family); if (bind(s, reinterpret_cast<sockaddr*>(&addr), addrlen) < 0) { if (bind(s, reinterpret_cast<sockaddr*>(&addr), addrlen) < 0) { D( "could not bind vm debug control socket: %d: %s", D("could not bind vm debug control socket: %d: %s", errno, strerror(errno)); errno, strerror(errno) ); adb_close(s); adb_close(s); return -1; return -1; } } if (listen(s, 4) < 0) { if (listen(s, 4) < 0) { D("listen failed in jdwp control socket: %d: %s", D("listen failed in jdwp control socket: %d: %s", errno, strerror(errno)); errno, strerror(errno)); adb_close(s); adb_close(s); return -1; return -1; } } Loading @@ -510,121 +435,102 @@ jdwp_control_init( JdwpControl* control, /* only wait for incoming connections */ /* only wait for incoming connections */ fdevent_add(control->fde, FDE_READ); fdevent_add(control->fde, FDE_READ); close_on_exec(s); D("jdwp control socket started (%d)", control->listen_socket); D("jdwp control socket started (%d)", control->listen_socket); return 0; 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; JdwpControl* control = (JdwpControl*)_control; if (events & FDE_READ) { if (events & FDE_READ) { sockaddr_storage ss; sockaddr_storage ss; sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss); sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss); socklen_t addrlen = sizeof(ss); socklen_t addrlen = sizeof(ss); int s = -1; int s = adb_socket_accept(control->listen_socket, addrp, &addrlen); JdwpProcess* proc; do { s = adb_socket_accept(control->listen_socket, addrp, &addrlen); if (s < 0) { if (s < 0) { if (errno == EINTR) continue; if (errno == ECONNABORTED) { if (errno == ECONNABORTED) { /* oops, the JDWP process died really quick */ /* oops, the JDWP process died really quick */ D("oops, the JDWP process died really quick"); D("oops, the JDWP process died really quick"); return; return; } } else { /* the socket is probably closed ? */ /* the socket is probably closed ? */ D( "weird accept() failed on jdwp control socket: %s", D("weird accept() failed on jdwp control socket: %s", strerror(errno)); strerror(errno) ); return; return; } } } } while (s < 0); proc = jdwp_process_alloc( s ); auto proc = std::make_unique<JdwpProcess>(s); if (proc == NULL) if (!proc) { return; fatal("failed to allocate JdwpProcess"); } } } static JdwpControl _jdwp_control; _jdwp_list.emplace_back(std::move(proc)); } } /** "jdwp" local service implementation /** "jdwp" local service implementation ** this simply returns the list of known JDWP process pids ** this simply returns the list of known JDWP process pids **/ **/ struct JdwpSocket { struct JdwpSocket : public asocket { asocket socket; bool pass; int pass; }; }; static void static void jdwp_socket_close(asocket* s) { jdwp_socket_close( asocket* s ) D("LS(%d): closing jdwp socket", s->id); { asocket* peer = s->peer; remove_socket(s); if (s->peer) { D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd); if (peer) { s->peer->peer = nullptr; peer->peer = NULL; s->peer->close(s->peer); peer->close(peer); s->peer = nullptr; } } remove_socket(s); free(s); free(s); } } static int static int jdwp_socket_enqueue(asocket* s, apacket* p) { jdwp_socket_enqueue( asocket* s, apacket* p ) { /* you can't write to this asocket */ /* you can't write to this asocket */ D("LS(%d): JDWP socket received data?", s->id); put_apacket(p); put_apacket(p); s->peer->close(s->peer); s->peer->close(s->peer); return -1; return -1; } } static void jdwp_socket_ready(asocket* s) { static void jdwp_socket_ready( asocket* s ) { JdwpSocket* jdwp = (JdwpSocket*)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 first call, send the list of pids, * on the second one, close the connection * on the second one, close the connection */ */ if (jdwp->pass == 0) { if (!jdwp->pass) { apacket* p = get_apacket(); apacket* p = get_apacket(); p->len = jdwp_process_list((char*)p->data, s->get_max_payload()); p->len = jdwp_process_list((char*)p->data, s->get_max_payload()); peer->enqueue(peer, p); peer->enqueue(peer, p); jdwp->pass = 1; jdwp->pass = true; } } else { else { peer->close(peer); peer->close(peer); } } } } asocket* asocket* create_jdwp_service_socket(void) { create_jdwp_service_socket( void ) { JdwpSocket* s = reinterpret_cast<JdwpSocket*>(calloc(sizeof(*s), 1)); JdwpSocket* s = reinterpret_cast<JdwpSocket*>(calloc(sizeof(*s), 1)); if (s == NULL) if (!s) { return NULL; fatal("failed to allocate JdwpSocket"); } install_local_socket(&s->socket); install_local_socket(s); s->socket.ready = jdwp_socket_ready; s->ready = jdwp_socket_ready; s->socket.enqueue = jdwp_socket_enqueue; s->enqueue = jdwp_socket_enqueue; s->socket.close = jdwp_socket_close; s->close = jdwp_socket_close; s->pass = 0; s->pass = false; return &s->socket; return s; } } /** "track-jdwp" local service implementation /** "track-jdwp" local service implementation Loading @@ -632,113 +538,88 @@ create_jdwp_service_socket( void ) ** to the client... ** to the client... **/ **/ struct JdwpTracker { struct JdwpTracker : public asocket { asocket socket; bool need_initial; JdwpTracker* next; JdwpTracker* prev; int need_update; }; }; static JdwpTracker _jdwp_trackers_list; static std::vector<std::unique_ptr<JdwpTracker>> _jdwp_trackers; static void static void jdwp_process_list_updated(void) { jdwp_process_list_updated(void) { char buffer[1024]; char buffer[1024]; int len; int len = jdwp_process_list_msg(buffer, sizeof(buffer)); JdwpTracker* t = _jdwp_trackers_list.next; len = jdwp_process_list_msg(buffer, sizeof(buffer)); for (auto& t : _jdwp_trackers) { for ( ; t != &_jdwp_trackers_list; t = t->next ) { apacket* p = get_apacket(); apacket* p = get_apacket(); asocket* peer = t->socket.peer; memcpy(p->data, buffer, len); memcpy(p->data, buffer, len); p->len = 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 static void jdwp_tracker_close(asocket* s) { jdwp_tracker_close( asocket* s ) D("LS(%d): destroying jdwp tracker service", s->id); { JdwpTracker* tracker = (JdwpTracker*) s; asocket* peer = s->peer; if (peer) { if (s->peer) { peer->peer = NULL; D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd); peer->close(peer); s->peer->peer = nullptr; s->peer->close(s->peer); s->peer = nullptr; } } remove_socket(s); remove_socket(s); tracker->prev->next = tracker->next; auto pred = [s](const auto& tracker) { return tracker.get() == s; }; tracker->next->prev = tracker->prev; std::remove_if(_jdwp_trackers.begin(), _jdwp_trackers.end(), pred); free(s); } } static void static void jdwp_tracker_ready(asocket* s) { jdwp_tracker_ready( asocket* s ) { JdwpTracker* t = (JdwpTracker*)s; JdwpTracker* t = (JdwpTracker*)s; if (t->need_update) { if (t->need_initial) { apacket* p = get_apacket(); 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()); p->len = jdwp_process_list_msg((char*)p->data, s->get_max_payload()); s->peer->enqueue(s->peer, p); s->peer->enqueue(s->peer, p); } } } } static int static int jdwp_tracker_enqueue(asocket* s, apacket* p) { jdwp_tracker_enqueue( asocket* s, apacket* p ) { /* you can't write to this socket */ /* you can't write to this socket */ D("LS(%d): JDWP tracker received data?", s->id); put_apacket(p); put_apacket(p); s->peer->close(s->peer); s->peer->close(s->peer); return -1; return -1; } } asocket* create_jdwp_tracker_service_socket(void) { auto t = std::make_unique<JdwpTracker>(); if (!t) { fatal("failed to allocate JdwpTracker"); } asocket* memset(t.get(), 0, sizeof(asocket)); create_jdwp_tracker_service_socket( void ) { JdwpTracker* t = reinterpret_cast<JdwpTracker*>(calloc(sizeof(*t), 1)); if (t == NULL) return NULL; t->next = &_jdwp_trackers_list; install_local_socket(t.get()); t->prev = t->next->prev; D("LS(%d): created new jdwp tracker service", t->id); t->next->prev = t; t->ready = jdwp_tracker_ready; t->prev->next = t; 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; _jdwp_trackers.emplace_back(std::move(t)); t->socket.enqueue = jdwp_tracker_enqueue; t->socket.close = jdwp_tracker_close; t->need_update = 1; return &t->socket; return result; } } int init_jdwp(void) { int return jdwp_control_init(&_jdwp_control, JDWP_CONTROL_NAME, JDWP_CONTROL_NAME_LEN); 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 ); } } #endif /* !ADB_HOST */ #endif /* !ADB_HOST */