1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #if !ADB_HOST
18
19 #define TRACE_TAG JDWP
20
21 #include "sysdeps.h"
22
23 #include <errno.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/socket.h>
28 #include <sys/un.h>
29 #include <unistd.h>
30
31 #include <list>
32 #include <memory>
33 #include <vector>
34
35 #include <android-base/cmsg.h>
36
37 #include "adb.h"
38 #include "adb_io.h"
39 #include "adb_unique_fd.h"
40 #include "adb_utils.h"
41
42 /* here's how these things work.
43
44 when adbd starts, it creates a unix server socket
45 named @jdwp-control (@ is a shortcut for "first byte is zero"
46 to use the private namespace instead of the file system)
47
48 when a new JDWP daemon thread starts in a new VM process, it creates
49 a connection to @jdwp-control to announce its availability.
50
51
52 JDWP thread @jdwp-control
53 | |
54 |-------------------------------> |
55 | hello I'm in process <pid> |
56 | |
57 | |
58
59 the connection is kept alive. it will be closed automatically if
60 the JDWP process terminates (this allows adbd to detect dead
61 processes).
62
63 adbd thus maintains a list of "active" JDWP processes. it can send
64 its content to clients through the "device:debug-ports" service,
65 or even updates through the "device:track-debug-ports" service.
66
67 when a debugger wants to connect, it simply runs the command
68 equivalent to "adb forward tcp:<hostport> jdwp:<pid>"
69
70 "jdwp:<pid>" is a new forward destination format used to target
71 a given JDWP process on the device. when sutch a request arrives,
72 adbd does the following:
73
74 - first, it calls socketpair() to create a pair of equivalent
75 sockets.
76
77 - it attaches the first socket in the pair to a local socket
78 which is itself attached to the transport's remote socket:
79
80
81 - it sends the file descriptor of the second socket directly
82 to the JDWP process with the help of sendmsg()
83
84
85 JDWP thread @jdwp-control
86 | |
87 | <----------------------|
88 | OK, try this file descriptor |
89 | |
90 | |
91
92 then, the JDWP thread uses this new socket descriptor as its
93 pass-through connection to the debugger (and receives the
94 JDWP-Handshake message, answers to it, etc...)
95
96 this gives the following graphics:
97 ____________________________________
98 | |
99 | ADB Server (host) |
100 | |
101 Debugger <---> LocalSocket <----> RemoteSocket |
102 | ^^ |
103 |___________________________||_______|
104 ||
105 Transport ||
106 (TCP for emulator - USB for device) ||
107 ||
108 ___________________________||_______
109 | || |
110 | ADBD (device) || |
111 | VV |
112 JDWP <======> LocalSocket <----> RemoteSocket |
113 | |
114 |____________________________________|
115
116 due to the way adb works, this doesn't need a special socket
117 type or fancy handling of socket termination if either the debugger
118 or the JDWP process closes the connection.
119
120 THIS IS THE SIMPLEST IMPLEMENTATION I COULD FIND, IF YOU HAPPEN
121 TO HAVE A BETTER IDEA, LET ME KNOW - Digit
122
123 **********************************************************************/
124
125 /** JDWP PID List Support Code
126 ** for each JDWP process, we record its pid and its connected socket
127 **/
128
129 static void jdwp_process_event(int socket, unsigned events, void* _proc);
130 static void jdwp_process_list_updated(void);
131
132 struct JdwpProcess;
133 static auto& _jdwp_list = *new std::list<std::unique_ptr<JdwpProcess>>();
134
135 struct JdwpProcess {
JdwpProcessJdwpProcess136 explicit JdwpProcess(int socket) {
137 this->socket = socket;
138 this->fde = fdevent_create(socket, jdwp_process_event, this);
139
140 if (!this->fde) {
141 LOG(FATAL) << "could not create fdevent for new JDWP process";
142 }
143
144 /* start by waiting for the PID */
145 fdevent_add(this->fde, FDE_READ);
146 }
147
~JdwpProcessJdwpProcess148 ~JdwpProcess() {
149 if (this->socket >= 0) {
150 adb_shutdown(this->socket);
151 this->socket = -1;
152 }
153
154 if (this->fde) {
155 fdevent_destroy(this->fde);
156 this->fde = nullptr;
157 }
158
159 out_fds.clear();
160 }
161
RemoveFromListJdwpProcess162 void RemoveFromList() {
163 if (this->pid >= 0) {
164 D("removing pid %d from jdwp process list", this->pid);
165 } else {
166 D("removing transient JdwpProcess from list");
167 }
168
169 auto pred = [this](const auto& proc) { return proc.get() == this; };
170 _jdwp_list.remove_if(pred);
171 }
172
173 int32_t pid = -1;
174 int socket = -1;
175 fdevent* fde = nullptr;
176
177 std::vector<unique_fd> out_fds;
178 };
179
jdwp_process_list(char * buffer,size_t bufferlen)180 static size_t jdwp_process_list(char* buffer, size_t bufferlen) {
181 std::string temp;
182
183 for (auto& proc : _jdwp_list) {
184 /* skip transient connections */
185 if (proc->pid < 0) {
186 continue;
187 }
188
189 std::string next = std::to_string(proc->pid) + "\n";
190 if (temp.length() + next.length() > bufferlen) {
191 D("truncating JDWP process list (max len = %zu)", bufferlen);
192 break;
193 }
194 temp.append(next);
195 }
196
197 memcpy(buffer, temp.data(), temp.length());
198 return temp.length();
199 }
200
jdwp_process_list_msg(char * buffer,size_t bufferlen)201 static size_t jdwp_process_list_msg(char* buffer, size_t bufferlen) {
202 // Message is length-prefixed with 4 hex digits in ASCII.
203 static constexpr size_t header_len = 4;
204 if (bufferlen < header_len) {
205 LOG(FATAL) << "invalid JDWP process list buffer size: " << bufferlen;
206 }
207
208 char head[header_len + 1];
209 size_t len = jdwp_process_list(buffer + header_len, bufferlen - header_len);
210 snprintf(head, sizeof head, "%04zx", len);
211 memcpy(buffer, head, header_len);
212 return len + header_len;
213 }
214
jdwp_process_event(int socket,unsigned events,void * _proc)215 static void jdwp_process_event(int socket, unsigned events, void* _proc) {
216 JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc);
217 CHECK_EQ(socket, proc->socket);
218
219 if (events & FDE_READ) {
220 if (proc->pid < 0) {
221 ssize_t rc = TEMP_FAILURE_RETRY(recv(socket, &proc->pid, sizeof(proc->pid), 0));
222 if (rc != sizeof(proc->pid)) {
223 D("failed to read jdwp pid: rc = %zd, errno = %s", rc, strerror(errno));
224 goto CloseProcess;
225 }
226
227 /* all is well, keep reading to detect connection closure */
228 D("Adding pid %d to jdwp process list", proc->pid);
229 jdwp_process_list_updated();
230 } else {
231 // We already have the PID, if we can read from the socket, we've probably hit EOF.
232 D("terminating JDWP connection %d", proc->pid);
233 goto CloseProcess;
234 }
235 }
236
237 if (events & FDE_WRITE) {
238 D("trying to send fd to JDWP process (count = %zu)", proc->out_fds.size());
239 CHECK(!proc->out_fds.empty());
240
241 int fd = proc->out_fds.back().get();
242 if (android::base::SendFileDescriptors(socket, "", 1, fd) != 1) {
243 D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno));
244 goto CloseProcess;
245 }
246
247 D("sent file descriptor %d to JDWP process %d", fd, proc->pid);
248
249 proc->out_fds.pop_back();
250 if (proc->out_fds.empty()) {
251 fdevent_del(proc->fde, FDE_WRITE);
252 }
253 }
254
255 return;
256
257 CloseProcess:
258 proc->RemoveFromList();
259 jdwp_process_list_updated();
260 }
261
create_jdwp_connection_fd(int pid)262 unique_fd create_jdwp_connection_fd(int pid) {
263 D("looking for pid %d in JDWP process list", pid);
264
265 for (auto& proc : _jdwp_list) {
266 if (proc->pid == pid) {
267 int fds[2];
268
269 if (adb_socketpair(fds) < 0) {
270 D("%s: socket pair creation failed: %s", __FUNCTION__, strerror(errno));
271 return unique_fd{};
272 }
273 D("socketpair: (%d,%d)", fds[0], fds[1]);
274
275 proc->out_fds.emplace_back(fds[1]);
276 if (proc->out_fds.size() == 1) {
277 fdevent_add(proc->fde, FDE_WRITE);
278 }
279
280 return unique_fd{fds[0]};
281 }
282 }
283 D("search failed !!");
284 return unique_fd{};
285 }
286
287 /** VM DEBUG CONTROL SOCKET
288 **
289 ** we do implement a custom asocket to receive the data
290 **/
291
292 /* name of the debug control Unix socket */
293 #define JDWP_CONTROL_NAME "\0jdwp-control"
294 #define JDWP_CONTROL_NAME_LEN (sizeof(JDWP_CONTROL_NAME) - 1)
295
296 struct JdwpControl {
297 int listen_socket;
298 fdevent* fde;
299 };
300
301 static JdwpControl _jdwp_control;
302
303 static void jdwp_control_event(int s, unsigned events, void* user);
304
jdwp_control_init(JdwpControl * control,const char * sockname,int socknamelen)305 static int jdwp_control_init(JdwpControl* control, const char* sockname, int socknamelen) {
306 sockaddr_un addr;
307 socklen_t addrlen;
308 int maxpath = sizeof(addr.sun_path);
309 int pathlen = socknamelen;
310
311 if (pathlen >= maxpath) {
312 D("vm debug control socket name too long (%d extra chars)", pathlen + 1 - maxpath);
313 return -1;
314 }
315
316 memset(&addr, 0, sizeof(addr));
317 addr.sun_family = AF_UNIX;
318 memcpy(addr.sun_path, sockname, socknamelen);
319
320 unique_fd s(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0));
321 if (s < 0) {
322 D("could not create vm debug control socket. %d: %s", errno, strerror(errno));
323 return -1;
324 }
325
326 addrlen = pathlen + sizeof(addr.sun_family);
327
328 if (bind(s, reinterpret_cast<sockaddr*>(&addr), addrlen) < 0) {
329 D("could not bind vm debug control socket: %d: %s", errno, strerror(errno));
330 return -1;
331 }
332
333 if (listen(s, 4) < 0) {
334 D("listen failed in jdwp control socket: %d: %s", errno, strerror(errno));
335 return -1;
336 }
337
338 control->listen_socket = s.release();
339 control->fde = fdevent_create(control->listen_socket, jdwp_control_event, control);
340 if (control->fde == nullptr) {
341 D("could not create fdevent for jdwp control socket");
342 return -1;
343 }
344
345 /* only wait for incoming connections */
346 fdevent_add(control->fde, FDE_READ);
347
348 D("jdwp control socket started (%d)", control->listen_socket);
349 return 0;
350 }
351
jdwp_control_event(int fd,unsigned events,void * _control)352 static void jdwp_control_event(int fd, unsigned events, void* _control) {
353 JdwpControl* control = (JdwpControl*)_control;
354
355 CHECK_EQ(fd, control->listen_socket);
356 if (events & FDE_READ) {
357 int s = adb_socket_accept(control->listen_socket, nullptr, nullptr);
358 if (s < 0) {
359 if (errno == ECONNABORTED) {
360 /* oops, the JDWP process died really quick */
361 D("oops, the JDWP process died really quick");
362 return;
363 } else {
364 /* the socket is probably closed ? */
365 D("weird accept() failed on jdwp control socket: %s", strerror(errno));
366 return;
367 }
368 }
369
370 auto proc = std::make_unique<JdwpProcess>(s);
371 if (!proc) {
372 LOG(FATAL) << "failed to allocate JdwpProcess";
373 }
374
375 _jdwp_list.emplace_back(std::move(proc));
376 }
377 }
378
379 /** "jdwp" local service implementation
380 ** this simply returns the list of known JDWP process pids
381 **/
382
383 struct JdwpSocket : public asocket {
384 bool pass = false;
385 };
386
jdwp_socket_close(asocket * s)387 static void jdwp_socket_close(asocket* s) {
388 D("LS(%d): closing jdwp socket", s->id);
389
390 if (s->peer) {
391 D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
392 s->peer->peer = nullptr;
393 s->peer->close(s->peer);
394 s->peer = nullptr;
395 }
396
397 remove_socket(s);
398 delete s;
399 }
400
jdwp_socket_enqueue(asocket * s,apacket::payload_type)401 static int jdwp_socket_enqueue(asocket* s, apacket::payload_type) {
402 /* you can't write to this asocket */
403 D("LS(%d): JDWP socket received data?", s->id);
404 s->peer->close(s->peer);
405 return -1;
406 }
407
jdwp_socket_ready(asocket * s)408 static void jdwp_socket_ready(asocket* s) {
409 JdwpSocket* jdwp = (JdwpSocket*)s;
410 asocket* peer = jdwp->peer;
411
412 /* on the first call, send the list of pids,
413 * on the second one, close the connection
414 */
415 if (!jdwp->pass) {
416 apacket::payload_type data;
417 data.resize(s->get_max_payload());
418 size_t len = jdwp_process_list(&data[0], data.size());
419 data.resize(len);
420 peer->enqueue(peer, std::move(data));
421 jdwp->pass = true;
422 } else {
423 peer->close(peer);
424 }
425 }
426
create_jdwp_service_socket(void)427 asocket* create_jdwp_service_socket(void) {
428 JdwpSocket* s = new JdwpSocket();
429
430 if (!s) {
431 LOG(FATAL) << "failed to allocate JdwpSocket";
432 }
433
434 install_local_socket(s);
435
436 s->ready = jdwp_socket_ready;
437 s->enqueue = jdwp_socket_enqueue;
438 s->close = jdwp_socket_close;
439 s->pass = false;
440
441 return s;
442 }
443
444 /** "track-jdwp" local service implementation
445 ** this periodically sends the list of known JDWP process pids
446 ** to the client...
447 **/
448
449 struct JdwpTracker : public asocket {
450 bool need_initial;
451 };
452
453 static auto& _jdwp_trackers = *new std::vector<std::unique_ptr<JdwpTracker>>();
454
jdwp_process_list_updated(void)455 static void jdwp_process_list_updated(void) {
456 std::string data;
457 data.resize(1024);
458 data.resize(jdwp_process_list_msg(&data[0], data.size()));
459
460 for (auto& t : _jdwp_trackers) {
461 if (t->peer) {
462 // The tracker might not have been connected yet.
463 apacket::payload_type payload(data.begin(), data.end());
464 t->peer->enqueue(t->peer, std::move(payload));
465 }
466 }
467 }
468
jdwp_tracker_close(asocket * s)469 static void jdwp_tracker_close(asocket* s) {
470 D("LS(%d): destroying jdwp tracker service", s->id);
471
472 if (s->peer) {
473 D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
474 s->peer->peer = nullptr;
475 s->peer->close(s->peer);
476 s->peer = nullptr;
477 }
478
479 remove_socket(s);
480
481 auto pred = [s](const auto& tracker) { return tracker.get() == s; };
482 _jdwp_trackers.erase(std::remove_if(_jdwp_trackers.begin(), _jdwp_trackers.end(), pred),
483 _jdwp_trackers.end());
484 }
485
jdwp_tracker_ready(asocket * s)486 static void jdwp_tracker_ready(asocket* s) {
487 JdwpTracker* t = (JdwpTracker*)s;
488
489 if (t->need_initial) {
490 apacket::payload_type data;
491 data.resize(s->get_max_payload());
492 data.resize(jdwp_process_list_msg(&data[0], data.size()));
493 t->need_initial = false;
494 s->peer->enqueue(s->peer, std::move(data));
495 }
496 }
497
jdwp_tracker_enqueue(asocket * s,apacket::payload_type)498 static int jdwp_tracker_enqueue(asocket* s, apacket::payload_type) {
499 /* you can't write to this socket */
500 D("LS(%d): JDWP tracker received data?", s->id);
501 s->peer->close(s->peer);
502 return -1;
503 }
504
create_jdwp_tracker_service_socket(void)505 asocket* create_jdwp_tracker_service_socket(void) {
506 auto t = std::make_unique<JdwpTracker>();
507 if (!t) {
508 LOG(FATAL) << "failed to allocate JdwpTracker";
509 }
510
511 memset(t.get(), 0, sizeof(asocket));
512
513 install_local_socket(t.get());
514 D("LS(%d): created new jdwp tracker service", t->id);
515
516 t->ready = jdwp_tracker_ready;
517 t->enqueue = jdwp_tracker_enqueue;
518 t->close = jdwp_tracker_close;
519 t->need_initial = true;
520
521 asocket* result = t.get();
522
523 _jdwp_trackers.emplace_back(std::move(t));
524
525 return result;
526 }
527
init_jdwp(void)528 int init_jdwp(void) {
529 return jdwp_control_init(&_jdwp_control, JDWP_CONTROL_NAME, JDWP_CONTROL_NAME_LEN);
530 }
531
532 #endif /* !ADB_HOST */
533