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 <thread>
34 #include <vector>
35
36 #include <adbconnection/server.h>
37 #include <android-base/cmsg.h>
38 #include <android-base/unique_fd.h>
39
40 #include "adb.h"
41 #include "adb_io.h"
42 #include "adb_unique_fd.h"
43 #include "adb_utils.h"
44
45 using android::base::borrowed_fd;
46 using android::base::unique_fd;
47
48 /* here's how these things work.
49
50 when adbd starts, it creates a unix server socket
51 named @jdwp-control (@ is a shortcut for "first byte is zero"
52 to use the private namespace instead of the file system)
53
54 when a new JDWP daemon thread starts in a new VM process, it creates
55 a connection to @jdwp-control to announce its availability.
56
57
58 JDWP thread @jdwp-control
59 | |
60 |-------------------------------> |
61 | hello I'm in process <pid> |
62 | |
63 | |
64
65 the connection is kept alive. it will be closed automatically if
66 the JDWP process terminates (this allows adbd to detect dead
67 processes).
68
69 adbd thus maintains a list of "active" JDWP processes. it can send
70 its content to clients through the "device:debug-ports" service,
71 or even updates through the "device:track-debug-ports" service.
72
73 when a debugger wants to connect, it simply runs the command
74 equivalent to "adb forward tcp:<hostport> jdwp:<pid>"
75
76 "jdwp:<pid>" is a new forward destination format used to target
77 a given JDWP process on the device. when sutch a request arrives,
78 adbd does the following:
79
80 - first, it calls socketpair() to create a pair of equivalent
81 sockets.
82
83 - it attaches the first socket in the pair to a local socket
84 which is itself attached to the transport's remote socket:
85
86
87 - it sends the file descriptor of the second socket directly
88 to the JDWP process with the help of sendmsg()
89
90
91 JDWP thread @jdwp-control
92 | |
93 | <----------------------|
94 | OK, try this file descriptor |
95 | |
96 | |
97
98 then, the JDWP thread uses this new socket descriptor as its
99 pass-through connection to the debugger (and receives the
100 JDWP-Handshake message, answers to it, etc...)
101
102 this gives the following graphics:
103 ____________________________________
104 | |
105 | ADB Server (host) |
106 | |
107 Debugger <---> LocalSocket <----> RemoteSocket |
108 | ^^ |
109 |___________________________||_______|
110 ||
111 Transport ||
112 (TCP for emulator - USB for device) ||
113 ||
114 ___________________________||_______
115 | || |
116 | ADBD (device) || |
117 | VV |
118 JDWP <======> LocalSocket <----> RemoteSocket |
119 | |
120 |____________________________________|
121
122 due to the way adb works, this doesn't need a special socket
123 type or fancy handling of socket termination if either the debugger
124 or the JDWP process closes the connection.
125
126 THIS IS THE SIMPLEST IMPLEMENTATION I COULD FIND, IF YOU HAPPEN
127 TO HAVE A BETTER IDEA, LET ME KNOW - Digit
128
129 **********************************************************************/
130
131 /** JDWP PID List Support Code
132 ** for each JDWP process, we record its pid and its connected socket
133 **/
134
135 static void jdwp_process_event(int socket, unsigned events, void* _proc);
136 static void jdwp_process_list_updated(void);
137
138 struct JdwpProcess;
139 static auto& _jdwp_list = *new std::list<std::unique_ptr<JdwpProcess>>();
140
141 struct JdwpProcess {
JdwpProcessJdwpProcess142 JdwpProcess(unique_fd socket, pid_t pid) {
143 CHECK(pid != 0);
144
145 this->socket = socket;
146 this->pid = pid;
147 this->fde = fdevent_create(socket.release(), jdwp_process_event, this);
148
149 if (!this->fde) {
150 LOG(FATAL) << "could not create fdevent for new JDWP process";
151 }
152 }
153
~JdwpProcessJdwpProcess154 ~JdwpProcess() {
155 if (this->socket >= 0) {
156 adb_shutdown(this->socket);
157 this->socket = -1;
158 }
159
160 if (this->fde) {
161 fdevent_destroy(this->fde);
162 this->fde = nullptr;
163 }
164
165 out_fds.clear();
166 }
167
RemoveFromListJdwpProcess168 void RemoveFromList() {
169 auto pred = [this](const auto& proc) { return proc.get() == this; };
170 _jdwp_list.remove_if(pred);
171 }
172
173 borrowed_fd socket = -1;
174 int32_t pid = -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 std::string next = std::to_string(proc->pid) + "\n";
185 if (temp.length() + next.length() > bufferlen) {
186 D("truncating JDWP process list (max len = %zu)", bufferlen);
187 break;
188 }
189 temp.append(next);
190 }
191
192 memcpy(buffer, temp.data(), temp.length());
193 return temp.length();
194 }
195
jdwp_process_list_msg(char * buffer,size_t bufferlen)196 static size_t jdwp_process_list_msg(char* buffer, size_t bufferlen) {
197 // Message is length-prefixed with 4 hex digits in ASCII.
198 static constexpr size_t header_len = 4;
199 if (bufferlen < header_len) {
200 LOG(FATAL) << "invalid JDWP process list buffer size: " << bufferlen;
201 }
202
203 char head[header_len + 1];
204 size_t len = jdwp_process_list(buffer + header_len, bufferlen - header_len);
205 snprintf(head, sizeof head, "%04zx", len);
206 memcpy(buffer, head, header_len);
207 return len + header_len;
208 }
209
jdwp_process_event(int socket,unsigned events,void * _proc)210 static void jdwp_process_event(int socket, unsigned events, void* _proc) {
211 JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc);
212 CHECK_EQ(socket, proc->socket.get());
213
214 if (events & FDE_READ) {
215 // We already have the PID, if we can read from the socket, we've probably hit EOF.
216 D("terminating JDWP connection %d", proc->pid);
217 goto CloseProcess;
218 }
219
220 if (events & FDE_WRITE) {
221 D("trying to send fd to JDWP process (count = %zu)", proc->out_fds.size());
222 CHECK(!proc->out_fds.empty());
223
224 int fd = proc->out_fds.back().get();
225 if (android::base::SendFileDescriptors(socket, "", 1, fd) != 1) {
226 D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno));
227 goto CloseProcess;
228 }
229
230 D("sent file descriptor %d to JDWP process %d", fd, proc->pid);
231
232 proc->out_fds.pop_back();
233 if (proc->out_fds.empty()) {
234 fdevent_del(proc->fde, FDE_WRITE);
235 }
236 }
237
238 return;
239
240 CloseProcess:
241 proc->RemoveFromList();
242 jdwp_process_list_updated();
243 }
244
create_jdwp_connection_fd(int pid)245 unique_fd create_jdwp_connection_fd(int pid) {
246 D("looking for pid %d in JDWP process list", pid);
247
248 for (auto& proc : _jdwp_list) {
249 if (proc->pid == pid) {
250 int fds[2];
251
252 if (adb_socketpair(fds) < 0) {
253 D("%s: socket pair creation failed: %s", __FUNCTION__, strerror(errno));
254 return unique_fd{};
255 }
256 D("socketpair: (%d,%d)", fds[0], fds[1]);
257
258 proc->out_fds.emplace_back(fds[1]);
259 if (proc->out_fds.size() == 1) {
260 fdevent_add(proc->fde, FDE_WRITE);
261 }
262
263 return unique_fd{fds[0]};
264 }
265 }
266 D("search failed !!");
267 return unique_fd{};
268 }
269
270 /** "jdwp" local service implementation
271 ** this simply returns the list of known JDWP process pids
272 **/
273
274 struct JdwpSocket : public asocket {
275 bool pass = false;
276 };
277
jdwp_socket_close(asocket * s)278 static void jdwp_socket_close(asocket* s) {
279 D("LS(%d): closing jdwp socket", s->id);
280
281 if (s->peer) {
282 D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
283 s->peer->peer = nullptr;
284 s->peer->close(s->peer);
285 s->peer = nullptr;
286 }
287
288 remove_socket(s);
289 delete s;
290 }
291
jdwp_socket_enqueue(asocket * s,apacket::payload_type)292 static int jdwp_socket_enqueue(asocket* s, apacket::payload_type) {
293 /* you can't write to this asocket */
294 D("LS(%d): JDWP socket received data?", s->id);
295 s->peer->close(s->peer);
296 return -1;
297 }
298
jdwp_socket_ready(asocket * s)299 static void jdwp_socket_ready(asocket* s) {
300 JdwpSocket* jdwp = (JdwpSocket*)s;
301 asocket* peer = jdwp->peer;
302
303 /* on the first call, send the list of pids,
304 * on the second one, close the connection
305 */
306 if (!jdwp->pass) {
307 apacket::payload_type data;
308 data.resize(s->get_max_payload());
309 size_t len = jdwp_process_list(&data[0], data.size());
310 data.resize(len);
311 peer->enqueue(peer, std::move(data));
312 jdwp->pass = true;
313 } else {
314 peer->close(peer);
315 }
316 }
317
create_jdwp_service_socket(void)318 asocket* create_jdwp_service_socket(void) {
319 JdwpSocket* s = new JdwpSocket();
320
321 if (!s) {
322 LOG(FATAL) << "failed to allocate JdwpSocket";
323 }
324
325 install_local_socket(s);
326
327 s->ready = jdwp_socket_ready;
328 s->enqueue = jdwp_socket_enqueue;
329 s->close = jdwp_socket_close;
330 s->pass = false;
331
332 return s;
333 }
334
335 /** "track-jdwp" local service implementation
336 ** this periodically sends the list of known JDWP process pids
337 ** to the client...
338 **/
339
340 struct JdwpTracker : public asocket {
341 bool need_initial;
342 };
343
344 static auto& _jdwp_trackers = *new std::vector<std::unique_ptr<JdwpTracker>>();
345
jdwp_process_list_updated(void)346 static void jdwp_process_list_updated(void) {
347 std::string data;
348 data.resize(1024);
349 data.resize(jdwp_process_list_msg(&data[0], data.size()));
350
351 for (auto& t : _jdwp_trackers) {
352 if (t->peer) {
353 // The tracker might not have been connected yet.
354 apacket::payload_type payload(data.begin(), data.end());
355 t->peer->enqueue(t->peer, std::move(payload));
356 }
357 }
358 }
359
jdwp_tracker_close(asocket * s)360 static void jdwp_tracker_close(asocket* s) {
361 D("LS(%d): destroying jdwp tracker service", s->id);
362
363 if (s->peer) {
364 D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
365 s->peer->peer = nullptr;
366 s->peer->close(s->peer);
367 s->peer = nullptr;
368 }
369
370 remove_socket(s);
371
372 auto pred = [s](const auto& tracker) { return tracker.get() == s; };
373 _jdwp_trackers.erase(std::remove_if(_jdwp_trackers.begin(), _jdwp_trackers.end(), pred),
374 _jdwp_trackers.end());
375 }
376
jdwp_tracker_ready(asocket * s)377 static void jdwp_tracker_ready(asocket* s) {
378 JdwpTracker* t = (JdwpTracker*)s;
379
380 if (t->need_initial) {
381 apacket::payload_type data;
382 data.resize(s->get_max_payload());
383 data.resize(jdwp_process_list_msg(&data[0], data.size()));
384 t->need_initial = false;
385 s->peer->enqueue(s->peer, std::move(data));
386 }
387 }
388
jdwp_tracker_enqueue(asocket * s,apacket::payload_type)389 static int jdwp_tracker_enqueue(asocket* s, apacket::payload_type) {
390 /* you can't write to this socket */
391 D("LS(%d): JDWP tracker received data?", s->id);
392 s->peer->close(s->peer);
393 return -1;
394 }
395
create_jdwp_tracker_service_socket(void)396 asocket* create_jdwp_tracker_service_socket(void) {
397 auto t = std::make_unique<JdwpTracker>();
398 if (!t) {
399 LOG(FATAL) << "failed to allocate JdwpTracker";
400 }
401
402 memset(t.get(), 0, sizeof(asocket));
403
404 install_local_socket(t.get());
405 D("LS(%d): created new jdwp tracker service", t->id);
406
407 t->ready = jdwp_tracker_ready;
408 t->enqueue = jdwp_tracker_enqueue;
409 t->close = jdwp_tracker_close;
410 t->need_initial = true;
411
412 asocket* result = t.get();
413
414 _jdwp_trackers.emplace_back(std::move(t));
415
416 return result;
417 }
418
init_jdwp(void)419 int init_jdwp(void) {
420 std::thread([]() {
421 adb_thread_setname("jdwp control");
422 adbconnection_listen([](int fd, pid_t pid) {
423 LOG(INFO) << "jdwp connection from " << pid;
424 fdevent_run_on_main_thread([fd, pid] {
425 unique_fd ufd(fd);
426 auto proc = std::make_unique<JdwpProcess>(std::move(ufd), pid);
427 if (!proc) {
428 LOG(FATAL) << "failed to allocate JdwpProcess";
429 }
430 _jdwp_list.emplace_back(std::move(proc));
431 jdwp_process_list_updated();
432 });
433 });
434 }).detach();
435 return 0;
436 }
437
438 #endif /* !ADB_HOST */
439