jdwp_service.c revision 4f6e8d7a00cbeda1e70cc15be9c4af1018bdad53
1/* implement the "debug-ports" and "track-debug-ports" device services */
2#include "sysdeps.h"
3#define  TRACE_TAG   TRACE_JDWP
4#include "adb.h"
5#include <errno.h>
6#include <stdio.h>
7#include <string.h>
8
9/* here's how these things work.
10
11   when adbd starts, it creates a unix server socket
12   named @vm-debug-control (@ is a shortcut for "first byte is zero"
13   to use the private namespace instead of the file system)
14
15   when a new JDWP daemon thread starts in a new VM process, it creates
16   a connection to @vm-debug-control to announce its availability.
17
18
19     JDWP thread                             @vm-debug-control
20         |                                         |
21         |------------------------------->         |
22         | hello I'm in process <pid>              |
23         |                                         |
24         |                                         |
25
26    the connection is kept alive. it will be closed automatically if
27    the JDWP process terminates (this allows adbd to detect dead
28    processes).
29
30    adbd thus maintains a list of "active" JDWP processes. it can send
31    its content to clients through the "device:debug-ports" service,
32    or even updates through the "device:track-debug-ports" service.
33
34    when a debugger wants to connect, it simply runs the command
35    equivalent to  "adb forward tcp:<hostport> jdwp:<pid>"
36
37    "jdwp:<pid>" is a new forward destination format used to target
38    a given JDWP process on the device. when sutch a request arrives,
39    adbd does the following:
40
41      - first, it calls socketpair() to create a pair of equivalent
42        sockets.
43
44      - it attaches the first socket in the pair to a local socket
45        which is itself attached to the transport's remote socket:
46
47
48      - it sends the file descriptor of the second socket directly
49        to the JDWP process with the help of sendmsg()
50
51
52     JDWP thread                             @vm-debug-control
53         |                                         |
54         |                  <----------------------|
55         |           OK, try this file descriptor  |
56         |                                         |
57         |                                         |
58
59   then, the JDWP thread uses this new socket descriptor as its
60   pass-through connection to the debugger (and receives the
61   JDWP-Handshake message, answers to it, etc...)
62
63   this gives the following graphics:
64                    ____________________________________
65                   |                                    |
66                   |          ADB Server (host)         |
67                   |                                    |
68        Debugger <---> LocalSocket <----> RemoteSocket  |
69                   |                           ^^       |
70                   |___________________________||_______|
71                                               ||
72                                     Transport ||
73           (TCP for emulator - USB for device) ||
74                                               ||
75                    ___________________________||_______
76                   |                           ||       |
77                   |          ADBD  (device)   ||       |
78                   |                           VV       |
79         JDWP <======> LocalSocket <----> RemoteSocket  |
80                   |                                    |
81                   |____________________________________|
82
83    due to the way adb works, this doesn't need a special socket
84    type or fancy handling of socket termination if either the debugger
85    or the JDWP process closes the connection.
86
87    THIS IS THE SIMPLEST IMPLEMENTATION I COULD FIND, IF YOU HAPPEN
88    TO HAVE A BETTER IDEA, LET ME KNOW - Digit
89
90**********************************************************************/
91
92/** JDWP PID List Support Code
93 ** for each JDWP process, we record its pid and its connected socket
94 **/
95
96#define  MAX_OUT_FDS   4
97
98#if !ADB_HOST
99
100#include <sys/socket.h>
101#include <sys/un.h>
102
103typedef struct JdwpProcess  JdwpProcess;
104struct JdwpProcess {
105    JdwpProcess*  next;
106    JdwpProcess*  prev;
107    int           pid;
108    int           socket;
109    fdevent*      fde;
110
111    char          in_buff[4];  /* input character to read PID */
112    int           in_len;      /* number from JDWP process    */
113
114    int           out_fds[MAX_OUT_FDS]; /* output array of file descriptors */
115    int           out_count;            /* to send to the JDWP process      */
116};
117
118static JdwpProcess  _jdwp_list;
119
120static int
121jdwp_process_list( char*  buffer, int  bufferlen )
122{
123    char*         end  = buffer + bufferlen;
124    char*         p    = buffer;
125    JdwpProcess*  proc = _jdwp_list.next;
126
127    for ( ; proc != &_jdwp_list; proc = proc->next ) {
128        int  len;
129
130        /* skip transient connections */
131        if (proc->pid < 0)
132            continue;
133
134        len = snprintf(p, end-p, "%d\n", proc->pid);
135        if (p + len >= end)
136            break;
137        p += len;
138    }
139    p[0] = 0;
140    return (p - buffer);
141}
142
143
144static int
145jdwp_process_list_msg( char*  buffer, int  bufferlen )
146{
147    char  head[5];
148    int   len = jdwp_process_list( buffer+4, bufferlen-4 );
149    snprintf(head, sizeof head, "%04x", len);
150    memcpy(buffer, head, 4);
151    return len + 4;
152}
153
154
155static void  jdwp_process_list_updated(void);
156
157static void
158jdwp_process_free( JdwpProcess*  proc )
159{
160    if (proc) {
161        int  n;
162
163        proc->prev->next = proc->next;
164        proc->next->prev = proc->prev;
165
166        if (proc->socket >= 0) {
167            shutdown(proc->socket, SHUT_RDWR);
168            adb_close(proc->socket);
169            proc->socket = -1;
170        }
171
172        if (proc->fde != NULL) {
173            fdevent_destroy(proc->fde);
174            proc->fde = NULL;
175        }
176        proc->pid = -1;
177
178        for (n = 0; n < proc->out_count; n++) {
179            adb_close(proc->out_fds[n]);
180        }
181        proc->out_count = 0;
182
183        free(proc);
184
185        jdwp_process_list_updated();
186    }
187}
188
189
190static void  jdwp_process_event(int, unsigned, void*);  /* forward */
191
192
193static JdwpProcess*
194jdwp_process_alloc( int  socket )
195{
196    JdwpProcess*  proc = calloc(1,sizeof(*proc));
197
198    if (proc == NULL) {
199        D("not enough memory to create new JDWP process\n");
200        return NULL;
201    }
202
203    proc->socket = socket;
204    proc->pid    = -1;
205    proc->next   = proc;
206    proc->prev   = proc;
207
208    proc->fde = fdevent_create( socket, jdwp_process_event, proc );
209    if (proc->fde == NULL) {
210        D("could not create fdevent for new JDWP process\n" );
211        free(proc);
212        return NULL;
213    }
214
215    proc->fde->state |= FDE_DONT_CLOSE;
216    proc->in_len      = 0;
217    proc->out_count   = 0;
218
219    /* append to list */
220    proc->next = &_jdwp_list;
221    proc->prev = proc->next->prev;
222
223    proc->prev->next = proc;
224    proc->next->prev = proc;
225
226    /* start by waiting for the PID */
227    fdevent_add(proc->fde, FDE_READ);
228
229    return proc;
230}
231
232
233static void
234jdwp_process_event( int  socket, unsigned  events, void*  _proc )
235{
236    JdwpProcess*  proc = _proc;
237
238    if (events & FDE_READ) {
239        if (proc->pid < 0) {
240            /* read the PID as a 4-hexchar string */
241            char*  p    = proc->in_buff + proc->in_len;
242            int    size = 4 - proc->in_len;
243            char   temp[5];
244            while (size > 0) {
245                int  len = recv( socket, p, size, 0 );
246                if (len < 0) {
247                    if (errno == EINTR)
248                        continue;
249                    if (errno == EAGAIN)
250                        return;
251                    /* this can fail here if the JDWP process crashes very fast */
252                    D("weird unknown JDWP process failure: %s\n",
253                      strerror(errno));
254
255                    goto CloseProcess;
256                }
257                if (len == 0) {  /* end of stream ? */
258                    D("weird end-of-stream from unknown JDWP process\n");
259                    goto CloseProcess;
260                }
261                p            += len;
262                proc->in_len += len;
263                size         -= len;
264            }
265            /* we have read 4 characters, now decode the pid */
266            memcpy(temp, proc->in_buff, 4);
267            temp[4] = 0;
268
269            if (sscanf( temp, "%04x", &proc->pid ) != 1) {
270                D("could not decode JDWP %p PID number: '%s'\n", proc, temp);
271                goto CloseProcess;
272            }
273
274            /* all is well, keep reading to detect connection closure */
275            D("Adding pid %d to jdwp process list\n", proc->pid);
276            jdwp_process_list_updated();
277        }
278        else
279        {
280            /* the pid was read, if we get there it's probably because the connection
281             * was closed (e.g. the JDWP process exited or crashed) */
282            char  buf[32];
283
284            for (;;) {
285                int  len = recv(socket, buf, sizeof(buf), 0);
286
287                if (len <= 0) {
288                    if (len < 0 && errno == EINTR)
289                        continue;
290		    if (len < 0 && errno == EAGAIN)
291                        return;
292                    else {
293                        D("terminating JDWP %d connection: %s\n", proc->pid,
294                          strerror(errno));
295                        break;
296                    }
297                }
298		else {
299                    D( "ignoring unexpected JDWP %d control socket activity (%d bytes)\n",
300                       proc->pid, len );
301                }
302            }
303
304        CloseProcess:
305            if (proc->pid >= 0)
306                D( "remove pid %d to jdwp process list\n", proc->pid );
307            jdwp_process_free(proc);
308            return;
309        }
310    }
311
312    if (events & FDE_WRITE) {
313        D("trying to write to JDWP pid controli (count=%d first=%d) %d\n",
314          proc->pid, proc->out_count, proc->out_fds[0]);
315        if (proc->out_count > 0) {
316            int  fd = proc->out_fds[0];
317            int  n, ret;
318            struct cmsghdr*  cmsg;
319            struct msghdr    msg;
320            struct iovec     iov;
321            char             dummy = '!';
322            char             buffer[sizeof(struct cmsghdr) + sizeof(int)];
323
324            iov.iov_base       = &dummy;
325            iov.iov_len        = 1;
326            msg.msg_name       = NULL;
327            msg.msg_namelen    = 0;
328            msg.msg_iov        = &iov;
329            msg.msg_iovlen     = 1;
330            msg.msg_flags      = 0;
331            msg.msg_control    = buffer;
332            msg.msg_controllen = sizeof(buffer);
333
334            cmsg = CMSG_FIRSTHDR(&msg);
335            cmsg->cmsg_len   = msg.msg_controllen;
336            cmsg->cmsg_level = SOL_SOCKET;
337            cmsg->cmsg_type  = SCM_RIGHTS;
338            ((int*)CMSG_DATA(cmsg))[0] = fd;
339
340            for (;;) {
341                ret = sendmsg(proc->socket, &msg, 0);
342                if (ret >= 0)
343                    break;
344                if (errno == EINTR)
345                    continue;
346                D("sending new file descriptor to JDWP %d failed: %s\n",
347                  proc->pid, strerror(errno));
348                goto CloseProcess;
349            }
350
351            D("sent file descriptor %d to JDWP process %d\n",
352              fd, proc->pid);
353
354            for (n = 1; n < proc->out_count; n++)
355                proc->out_fds[n-1] = proc->out_fds[n];
356
357            if (--proc->out_count == 0)
358                fdevent_del( proc->fde, FDE_WRITE );
359        }
360    }
361}
362
363
364int
365create_jdwp_connection_fd(int  pid)
366{
367    JdwpProcess*  proc = _jdwp_list.next;
368
369    D("looking for pid %d in JDWP process list\n", pid);
370    for ( ; proc != &_jdwp_list; proc = proc->next ) {
371        if (proc->pid == pid) {
372            goto FoundIt;
373        }
374    }
375    D("search failed !!\n");
376    return -1;
377
378FoundIt:
379    {
380        int  fds[2];
381
382        if (proc->out_count >= MAX_OUT_FDS) {
383            D("%s: too many pending JDWP connection for pid %d\n",
384              __FUNCTION__, pid);
385            return -1;
386        }
387
388        if (adb_socketpair(fds) < 0) {
389            D("%s: socket pair creation failed: %s\n",
390              __FUNCTION__, strerror(errno));
391            return -1;
392        }
393
394        proc->out_fds[ proc->out_count ] = fds[1];
395        if (++proc->out_count == 1)
396            fdevent_add( proc->fde, FDE_WRITE );
397
398        return fds[0];
399    }
400}
401
402/**  VM DEBUG CONTROL SOCKET
403 **
404 **  we do implement a custom asocket to receive the data
405 **/
406
407/* name of the debug control Unix socket */
408#define  JDWP_CONTROL_NAME      "\0jdwp-control"
409#define  JDWP_CONTROL_NAME_LEN  (sizeof(JDWP_CONTROL_NAME)-1)
410
411typedef struct {
412    int       listen_socket;
413    fdevent*  fde;
414
415} JdwpControl;
416
417
418static void
419jdwp_control_event(int  s, unsigned events, void*  user);
420
421
422static int
423jdwp_control_init( JdwpControl*  control,
424                   const char*   sockname,
425                   int           socknamelen )
426{
427    struct sockaddr_un   addr;
428    socklen_t            addrlen;
429    int                  s;
430    int                  maxpath = sizeof(addr.sun_path);
431    int                  pathlen = socknamelen;
432
433    if (pathlen >= maxpath) {
434        D( "vm debug control socket name too long (%d extra chars)\n",
435           pathlen+1-maxpath );
436        return -1;
437    }
438
439    memset(&addr, 0, sizeof(addr));
440    addr.sun_family = AF_UNIX;
441    memcpy(addr.sun_path, sockname, socknamelen);
442
443    s = socket( AF_UNIX, SOCK_STREAM, 0 );
444    if (s < 0) {
445        D( "could not create vm debug control socket. %d: %s\n",
446           errno, strerror(errno));
447        return -1;
448    }
449
450    addrlen = (pathlen + sizeof(addr.sun_family));
451
452    if (bind(s, (struct sockaddr*)&addr, addrlen) < 0) {
453        D( "could not bind vm debug control socket: %d: %s\n",
454           errno, strerror(errno) );
455        adb_close(s);
456        return -1;
457    }
458
459    if ( listen(s, 4) < 0 ) {
460        D("listen failed in jdwp control socket: %d: %s\n",
461          errno, strerror(errno));
462        adb_close(s);
463        return -1;
464    }
465
466    control->listen_socket = s;
467
468    control->fde = fdevent_create(s, jdwp_control_event, control);
469    if (control->fde == NULL) {
470        D( "could not create fdevent for jdwp control socket\n" );
471        adb_close(s);
472        return -1;
473    }
474
475    /* only wait for incoming connections */
476    fdevent_add(control->fde, FDE_READ);
477
478    D("jdwp control socket started (%d)\n", control->listen_socket);
479    return 0;
480}
481
482
483static void
484jdwp_control_event( int  s, unsigned  events, void*  _control )
485{
486    JdwpControl*  control = (JdwpControl*) _control;
487
488    if (events & FDE_READ) {
489        struct sockaddr   addr;
490        socklen_t         addrlen = sizeof(addr);
491        int               s = -1;
492        JdwpProcess*      proc;
493
494        do {
495            s = adb_socket_accept( control->listen_socket, &addr, &addrlen );
496            if (s < 0) {
497                if (errno == EINTR)
498                    continue;
499                if (errno == ECONNABORTED) {
500                    /* oops, the JDWP process died really quick */
501                    D("oops, the JDWP process died really quick\n");
502                    return;
503                }
504                /* the socket is probably closed ? */
505                D( "weird accept() failed on jdwp control socket: %s\n",
506                   strerror(errno) );
507                return;
508            }
509        }
510        while (s < 0);
511
512        proc = jdwp_process_alloc( s );
513        if (proc == NULL)
514            return;
515    }
516}
517
518
519static JdwpControl   _jdwp_control;
520
521/** "jdwp" local service implementation
522 ** this simply returns the list of known JDWP process pids
523 **/
524
525typedef struct {
526    asocket  socket;
527    int      pass;
528} JdwpSocket;
529
530static void
531jdwp_socket_close( asocket*  s )
532{
533    asocket*  peer = s->peer;
534
535    remove_socket(s);
536
537    if (peer) {
538        peer->peer = NULL;
539        peer->close(peer);
540    }
541    free(s);
542}
543
544static int
545jdwp_socket_enqueue( asocket*  s, apacket*  p )
546{
547    /* you can't write to this asocket */
548    put_apacket(p);
549    s->peer->close(s->peer);
550    return -1;
551}
552
553
554static void
555jdwp_socket_ready( asocket*  s )
556{
557    JdwpSocket*  jdwp = (JdwpSocket*)s;
558    asocket*     peer = jdwp->socket.peer;
559
560   /* on the first call, send the list of pids,
561    * on the second one, close the connection
562    */
563    if (jdwp->pass == 0) {
564        apacket*  p = get_apacket();
565        p->len = jdwp_process_list((char*)p->data, MAX_PAYLOAD);
566        peer->enqueue(peer, p);
567        jdwp->pass = 1;
568    }
569    else {
570        peer->close(peer);
571    }
572}
573
574asocket*
575create_jdwp_service_socket( void )
576{
577    JdwpSocket*  s = calloc(sizeof(*s),1);
578
579    if (s == NULL)
580        return NULL;
581
582    install_local_socket(&s->socket);
583
584    s->socket.ready   = jdwp_socket_ready;
585    s->socket.enqueue = jdwp_socket_enqueue;
586    s->socket.close   = jdwp_socket_close;
587    s->pass           = 0;
588
589    return &s->socket;
590}
591
592/** "track-jdwp" local service implementation
593 ** this periodically sends the list of known JDWP process pids
594 ** to the client...
595 **/
596
597typedef struct JdwpTracker  JdwpTracker;
598
599struct JdwpTracker {
600    asocket       socket;
601    JdwpTracker*  next;
602    JdwpTracker*  prev;
603    int           need_update;
604};
605
606static JdwpTracker   _jdwp_trackers_list;
607
608
609static void
610jdwp_process_list_updated(void)
611{
612    char             buffer[1024];
613    int              len;
614    JdwpTracker*  t = _jdwp_trackers_list.next;
615
616    len = jdwp_process_list_msg(buffer, sizeof(buffer));
617
618    for ( ; t != &_jdwp_trackers_list; t = t->next ) {
619        apacket*  p    = get_apacket();
620        asocket*  peer = t->socket.peer;
621        memcpy(p->data, buffer, len);
622        p->len = len;
623        peer->enqueue( peer, p );
624    }
625}
626
627static void
628jdwp_tracker_close( asocket*  s )
629{
630    JdwpTracker*  tracker = (JdwpTracker*) s;
631    asocket*      peer    = s->peer;
632
633    if (peer) {
634        peer->peer = NULL;
635        peer->close(peer);
636    }
637
638    remove_socket(s);
639
640    tracker->prev->next = tracker->next;
641    tracker->next->prev = tracker->prev;
642
643    free(s);
644}
645
646static void
647jdwp_tracker_ready( asocket*  s )
648{
649    JdwpTracker*  t = (JdwpTracker*) s;
650
651    if (t->need_update) {
652        apacket*  p = get_apacket();
653        t->need_update = 0;
654        p->len = jdwp_process_list_msg((char*)p->data, sizeof(p->data));
655        s->peer->enqueue(s->peer, p);
656    }
657}
658
659static int
660jdwp_tracker_enqueue( asocket*  s, apacket*  p )
661{
662    /* you can't write to this socket */
663    put_apacket(p);
664    s->peer->close(s->peer);
665    return -1;
666}
667
668
669asocket*
670create_jdwp_tracker_service_socket( void )
671{
672    JdwpTracker*  t = calloc(sizeof(*t),1);
673
674    if (t == NULL)
675        return NULL;
676
677    t->next = &_jdwp_trackers_list;
678    t->prev = t->next->prev;
679
680    t->next->prev = t;
681    t->prev->next = t;
682
683    install_local_socket(&t->socket);
684
685    t->socket.ready   = jdwp_tracker_ready;
686    t->socket.enqueue = jdwp_tracker_enqueue;
687    t->socket.close   = jdwp_tracker_close;
688    t->need_update    = 1;
689
690    return &t->socket;
691}
692
693
694int
695init_jdwp(void)
696{
697    _jdwp_list.next = &_jdwp_list;
698    _jdwp_list.prev = &_jdwp_list;
699
700    _jdwp_trackers_list.next = &_jdwp_trackers_list;
701    _jdwp_trackers_list.prev = &_jdwp_trackers_list;
702
703    return jdwp_control_init( &_jdwp_control,
704                              JDWP_CONTROL_NAME,
705                              JDWP_CONTROL_NAME_LEN );
706}
707
708#endif /* !ADB_HOST */
709
710