summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'adb/jdwp_service.c')
-rw-r--r--adb/jdwp_service.c709
1 files changed, 709 insertions, 0 deletions
diff --git a/adb/jdwp_service.c b/adb/jdwp_service.c
new file mode 100644
index 000000000..43dc69eb4
--- /dev/null
+++ b/adb/jdwp_service.c
@@ -0,0 +1,709 @@
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