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 !defined(__ANDROID_RECOVERY__)
18 #define TRACE_TAG JDWP
19
20 #include "sysdeps.h"
21
22 #include <errno.h>
23 #include <inttypes.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/process_info.h>
37 #include <adbconnection/server.h>
38 #include <android-base/cmsg.h>
39 #include <android-base/unique_fd.h>
40
41 #include "adb.h"
42 #include "adb_io.h"
43 #include "adb_unique_fd.h"
44 #include "adb_utils.h"
45 #include "app_processes.pb.h"
46
47 using android::base::borrowed_fd;
48 using android::base::unique_fd;
49
50 /* here's how these things work.
51
52 when adbd starts, it creates a unix server socket
53 named @jdwp-control (@ is a shortcut for "first byte is zero"
54 to use the private namespace instead of the file system)
55
56 when a new JDWP daemon thread starts in a new VM process, it creates
57 a connection to @jdwp-control to announce its availability.
58
59
60 JDWP thread @jdwp-control
61 | |
62 |-------------------------------> |
63 | hello I'm in process <pid> |
64 | |
65 | |
66
67 the connection is kept alive. it will be closed automatically if
68 the JDWP process terminates (this allows adbd to detect dead
69 processes).
70
71 adbd thus maintains a list of "active" JDWP processes. it can send
72 its content to clients through the "device:debug-ports" service,
73 or even updates through the "device:track-debug-ports" service.
74
75 when a debugger wants to connect, it simply runs the command
76 equivalent to "adb forward tcp:<hostport> jdwp:<pid>"
77
78 "jdwp:<pid>" is a new forward destination format used to target
79 a given JDWP process on the device. when sutch a request arrives,
80 adbd does the following:
81
82 - first, it calls socketpair() to create a pair of equivalent
83 sockets.
84
85 - it attaches the first socket in the pair to a local socket
86 which is itself attached to the transport's remote socket:
87
88
89 - it sends the file descriptor of the second socket directly
90 to the JDWP process with the help of sendmsg()
91
92
93 JDWP thread @jdwp-control
94 | |
95 | <----------------------|
96 | OK, try this file descriptor |
97 | |
98 | |
99
100 then, the JDWP thread uses this new socket descriptor as its
101 pass-through connection to the debugger (and receives the
102 JDWP-Handshake message, answers to it, etc...)
103
104 this gives the following graphics:
105 ____________________________________
106 | |
107 | ADB Server (host) |
108 | |
109 Debugger <---> LocalSocket <----> RemoteSocket |
110 | ^^ |
111 |___________________________||_______|
112 ||
113 Transport ||
114 (TCP for emulator - USB for device) ||
115 ||
116 ___________________________||_______
117 | || |
118 | ADBD (device) || |
119 | VV |
120 JDWP <======> LocalSocket <----> RemoteSocket |
121 | |
122 |____________________________________|
123
124 due to the way adb works, this doesn't need a special socket
125 type or fancy handling of socket termination if either the debugger
126 or the JDWP process closes the connection.
127
128 THIS IS THE SIMPLEST IMPLEMENTATION I COULD FIND, IF YOU HAPPEN
129 TO HAVE A BETTER IDEA, LET ME KNOW - Digit
130
131 **********************************************************************/
132
133 /** JDWP PID List Support Code
134 ** for each JDWP process, we record its pid and its connected socket
135 **/
136
137 enum class TrackerKind {
138 kJdwp,
139 kApp,
140 };
141
142 static void jdwp_process_event(int socket, unsigned events, void* _proc);
143 static void jdwp_process_list_updated(void);
144 static void app_process_list_updated(void);
145
146 struct JdwpProcess;
147 static auto& _jdwp_list = *new std::list<std::unique_ptr<JdwpProcess>>();
148
149 struct JdwpProcess {
JdwpProcessJdwpProcess150 JdwpProcess(unique_fd socket, ProcessInfo process) {
151 CHECK(process.pid != 0);
152
153 this->socket = socket;
154 this->process = process;
155 this->fde = fdevent_create(socket.release(), jdwp_process_event, this);
156
157 if (!this->fde) {
158 LOG(FATAL) << "could not create fdevent for new JDWP process";
159 }
160 }
161
~JdwpProcessJdwpProcess162 ~JdwpProcess() {
163 if (this->socket >= 0) {
164 adb_shutdown(this->socket);
165 this->socket = -1;
166 }
167
168 if (this->fde) {
169 fdevent_destroy(this->fde);
170 this->fde = nullptr;
171 }
172
173 out_fds.clear();
174 }
175
RemoveFromListJdwpProcess176 void RemoveFromList() {
177 auto pred = [this](const auto& proc) { return proc.get() == this; };
178 _jdwp_list.remove_if(pred);
179 }
180
181 borrowed_fd socket = -1;
182 ProcessInfo process;
183 fdevent* fde = nullptr;
184
185 std::vector<unique_fd> out_fds;
186 };
187
188 // Populate the list of processes for "track-jdwp" service.
jdwp_process_list(char * buffer,size_t bufferlen)189 static size_t jdwp_process_list(char* buffer, size_t bufferlen) {
190 std::string temp;
191
192 for (auto& proc : _jdwp_list) {
193 if (!proc->process.debuggable) continue;
194 std::string next = std::to_string(proc->process.pid) + "\n";
195 if (temp.length() + next.length() > bufferlen) {
196 D("truncating JDWP process list (max len = %zu)", bufferlen);
197 break;
198 }
199 temp.append(next);
200 }
201
202 memcpy(buffer, temp.data(), temp.length());
203 return temp.length();
204 }
205
206 // Populate the list of processes for "track-app" service.
207 // The list is a protobuf message in the binary format for efficiency.
app_process_list(char * buffer,size_t bufferlen)208 static size_t app_process_list(char* buffer, size_t bufferlen) {
209 adb::proto::AppProcesses output; // result that's guaranteed to fit in the given buffer
210 adb::proto::AppProcesses temp; // temporary result that may be longer than the given buffer
211 std::string serialized_message;
212
213 for (auto& proc : _jdwp_list) {
214 if (!proc->process.debuggable && !proc->process.profileable) continue;
215 auto* entry = temp.add_process();
216 entry->set_pid(proc->process.pid);
217 entry->set_debuggable(proc->process.debuggable);
218 entry->set_profileable(proc->process.profileable);
219 entry->set_architecture(proc->process.arch_name, proc->process.arch_name_length);
220 temp.SerializeToString(&serialized_message);
221 if (serialized_message.size() > bufferlen) {
222 D("truncating app process list (max len = %zu)", bufferlen);
223 break;
224 }
225 output = temp;
226 }
227 output.SerializeToString(&serialized_message);
228 memcpy(buffer, serialized_message.data(), serialized_message.length());
229 return serialized_message.length();
230 }
231
232 // Populate the list of processes for either "track-jdwp" or "track-app" services,
233 // depending on the given kind.
process_list(TrackerKind kind,char * buffer,size_t bufferlen)234 static size_t process_list(TrackerKind kind, char* buffer, size_t bufferlen) {
235 switch (kind) {
236 case TrackerKind::kJdwp:
237 return jdwp_process_list(buffer, bufferlen);
238 case TrackerKind::kApp:
239 return app_process_list(buffer, bufferlen);
240 }
241 }
242
process_list_msg(TrackerKind kind,char * buffer,size_t bufferlen)243 static size_t process_list_msg(TrackerKind kind, char* buffer, size_t bufferlen) {
244 // Message is length-prefixed with 4 hex digits in ASCII.
245 static constexpr size_t header_len = 4;
246 if (bufferlen < header_len) {
247 LOG(FATAL) << "invalid JDWP process list buffer size: " << bufferlen;
248 }
249
250 char head[header_len + 1];
251 size_t len = process_list(kind, buffer + header_len, bufferlen - header_len);
252 snprintf(head, sizeof head, "%04zx", len);
253 memcpy(buffer, head, header_len);
254 return len + header_len;
255 }
256
jdwp_process_event(int socket,unsigned events,void * _proc)257 static void jdwp_process_event(int socket, unsigned events, void* _proc) {
258 JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc);
259 CHECK_EQ(socket, proc->socket.get());
260
261 if (events & FDE_READ) {
262 // We already have the PID, if we can read from the socket, we've probably hit EOF.
263 D("terminating JDWP connection %" PRId64, proc->process.pid);
264 goto CloseProcess;
265 }
266
267 if (events & FDE_WRITE) {
268 D("trying to send fd to JDWP process (count = %zu)", proc->out_fds.size());
269 CHECK(!proc->out_fds.empty());
270
271 int fd = proc->out_fds.back().get();
272 if (android::base::SendFileDescriptors(socket, "", 1, fd) != 1) {
273 D("sending new file descriptor to JDWP %" PRId64 " failed: %s", proc->process.pid,
274 strerror(errno));
275 goto CloseProcess;
276 }
277
278 D("sent file descriptor %d to JDWP process %" PRId64, fd, proc->process.pid);
279
280 proc->out_fds.pop_back();
281 if (proc->out_fds.empty()) {
282 fdevent_del(proc->fde, FDE_WRITE);
283 }
284 }
285
286 return;
287
288 CloseProcess:
289 bool debuggable = proc->process.debuggable;
290 bool profileable = proc->process.profileable;
291 proc->RemoveFromList();
292 if (debuggable) jdwp_process_list_updated();
293 if (debuggable || profileable) app_process_list_updated();
294 }
295
create_jdwp_connection_fd(int pid)296 unique_fd create_jdwp_connection_fd(int pid) {
297 D("looking for pid %d in JDWP process list", pid);
298
299 for (auto& proc : _jdwp_list) {
300 // Don't allow JDWP connection to a non-debuggable process.
301 if (!proc->process.debuggable) continue;
302 if (proc->process.pid == static_cast<uint64_t>(pid)) {
303 int fds[2];
304
305 if (adb_socketpair(fds) < 0) {
306 D("%s: socket pair creation failed: %s", __FUNCTION__, strerror(errno));
307 return unique_fd{};
308 }
309 D("socketpair: (%d,%d)", fds[0], fds[1]);
310
311 proc->out_fds.emplace_back(fds[1]);
312 if (proc->out_fds.size() == 1) {
313 fdevent_add(proc->fde, FDE_WRITE);
314 }
315
316 return unique_fd{fds[0]};
317 }
318 }
319 D("search failed !!");
320 return unique_fd{};
321 }
322
323 /** "jdwp" local service implementation
324 ** this simply returns the list of known JDWP process pids
325 **/
326
327 struct JdwpSocket : public asocket {
328 bool pass = false;
329 };
330
jdwp_socket_close(asocket * s)331 static void jdwp_socket_close(asocket* s) {
332 D("LS(%d): closing jdwp socket", s->id);
333
334 if (s->peer) {
335 D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
336 s->peer->peer = nullptr;
337 s->peer->close(s->peer);
338 s->peer = nullptr;
339 }
340
341 remove_socket(s);
342 delete s;
343 }
344
jdwp_socket_enqueue(asocket * s,apacket::payload_type)345 static int jdwp_socket_enqueue(asocket* s, apacket::payload_type) {
346 /* you can't write to this asocket */
347 D("LS(%d): JDWP socket received data?", s->id);
348 s->peer->close(s->peer);
349 return -1;
350 }
351
jdwp_socket_ready(asocket * s)352 static void jdwp_socket_ready(asocket* s) {
353 JdwpSocket* jdwp = (JdwpSocket*)s;
354 asocket* peer = jdwp->peer;
355
356 /* on the first call, send the list of pids,
357 * on the second one, close the connection
358 */
359 if (!jdwp->pass) {
360 apacket::payload_type data;
361 data.resize(s->get_max_payload());
362 size_t len = jdwp_process_list(&data[0], data.size());
363 data.resize(len);
364 peer->enqueue(peer, std::move(data));
365 jdwp->pass = true;
366 } else {
367 peer->close(peer);
368 }
369 }
370
create_jdwp_service_socket(void)371 asocket* create_jdwp_service_socket(void) {
372 JdwpSocket* s = new JdwpSocket();
373
374 if (!s) {
375 LOG(FATAL) << "failed to allocate JdwpSocket";
376 }
377
378 install_local_socket(s);
379
380 s->ready = jdwp_socket_ready;
381 s->enqueue = jdwp_socket_enqueue;
382 s->close = jdwp_socket_close;
383 s->pass = false;
384
385 return s;
386 }
387
388 /** "track-jdwp" local service implementation
389 ** this periodically sends the list of known JDWP process pids
390 ** to the client...
391 **/
392
393 struct JdwpTracker : public asocket {
394 TrackerKind kind;
395 bool need_initial;
396
JdwpTrackerJdwpTracker397 explicit JdwpTracker(TrackerKind k, bool initial) : kind(k), need_initial(initial) {}
398 };
399
400 static auto& _jdwp_trackers = *new std::vector<std::unique_ptr<JdwpTracker>>();
401
process_list_updated(TrackerKind kind)402 static void process_list_updated(TrackerKind kind) {
403 std::string data;
404 const int kMaxLength = kind == TrackerKind::kJdwp ? 1024 : 2048;
405 data.resize(kMaxLength);
406 data.resize(process_list_msg(kind, &data[0], data.size()));
407
408 for (auto& t : _jdwp_trackers) {
409 if (t->kind == kind && t->peer) {
410 // The tracker might not have been connected yet.
411 apacket::payload_type payload(data.begin(), data.end());
412 t->peer->enqueue(t->peer, std::move(payload));
413 }
414 }
415 }
416
jdwp_process_list_updated(void)417 static void jdwp_process_list_updated(void) {
418 process_list_updated(TrackerKind::kJdwp);
419 }
420
app_process_list_updated(void)421 static void app_process_list_updated(void) {
422 process_list_updated(TrackerKind::kApp);
423 }
424
jdwp_tracker_close(asocket * s)425 static void jdwp_tracker_close(asocket* s) {
426 D("LS(%d): destroying jdwp tracker service", s->id);
427
428 if (s->peer) {
429 D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
430 s->peer->peer = nullptr;
431 s->peer->close(s->peer);
432 s->peer = nullptr;
433 }
434
435 remove_socket(s);
436
437 auto pred = [s](const auto& tracker) { return tracker.get() == s; };
438 _jdwp_trackers.erase(std::remove_if(_jdwp_trackers.begin(), _jdwp_trackers.end(), pred),
439 _jdwp_trackers.end());
440 }
441
jdwp_tracker_ready(asocket * s)442 static void jdwp_tracker_ready(asocket* s) {
443 JdwpTracker* t = (JdwpTracker*)s;
444
445 if (t->need_initial) {
446 apacket::payload_type data;
447 data.resize(s->get_max_payload());
448 data.resize(process_list_msg(t->kind, &data[0], data.size()));
449 t->need_initial = false;
450 s->peer->enqueue(s->peer, std::move(data));
451 }
452 }
453
jdwp_tracker_enqueue(asocket * s,apacket::payload_type)454 static int jdwp_tracker_enqueue(asocket* s, apacket::payload_type) {
455 /* you can't write to this socket */
456 D("LS(%d): JDWP tracker received data?", s->id);
457 s->peer->close(s->peer);
458 return -1;
459 }
460
create_process_tracker_service_socket(TrackerKind kind)461 static asocket* create_process_tracker_service_socket(TrackerKind kind) {
462 std::unique_ptr<JdwpTracker> t = std::make_unique<JdwpTracker>(kind, true);
463 if (!t) {
464 LOG(FATAL) << "failed to allocate JdwpTracker";
465 }
466
467 /* Object layout (with an inheritance hierarchy) varies across arch (e.g
468 * armv7a/Android TV vs aarch64), so no assumptions can be made about
469 * accessing fields based on offsets (e.g memset(t.get(), 0, sizeof(asocket))
470 * might clobber an unintended memory location).
471 */
472
473 install_local_socket(t.get());
474 D("LS(%d): created new jdwp tracker service", t->id);
475
476 t->ready = jdwp_tracker_ready;
477 t->enqueue = jdwp_tracker_enqueue;
478 t->close = jdwp_tracker_close;
479
480 asocket* result = t.get();
481
482 _jdwp_trackers.emplace_back(std::move(t));
483
484 return result;
485 }
486
create_jdwp_tracker_service_socket()487 asocket* create_jdwp_tracker_service_socket() {
488 return create_process_tracker_service_socket(TrackerKind::kJdwp);
489 }
490
create_app_tracker_service_socket()491 asocket* create_app_tracker_service_socket() {
492 return create_process_tracker_service_socket(TrackerKind::kApp);
493 }
494
init_jdwp(void)495 int init_jdwp(void) {
496 std::thread([]() {
497 adb_thread_setname("jdwp control");
498 adbconnection_listen([](int fd, ProcessInfo process) {
499 LOG(INFO) << "jdwp connection from " << process.pid;
500 fdevent_run_on_looper([fd, process] {
501 unique_fd ufd(fd);
502 auto proc = std::make_unique<JdwpProcess>(std::move(ufd), process);
503 if (!proc) {
504 LOG(FATAL) << "failed to allocate JdwpProcess";
505 }
506 _jdwp_list.emplace_back(std::move(proc));
507 if (process.debuggable) jdwp_process_list_updated();
508 if (process.debuggable || process.profileable) app_process_list_updated();
509 });
510 });
511 }).detach();
512 return 0;
513 }
514
515 #else // !defined(__ANDROID_RECOVERY)
516 #include "adb.h"
517
create_jdwp_service_socket(void)518 asocket* create_jdwp_service_socket(void) {
519 return nullptr;
520 }
521
create_jdwp_connection_fd(int pid)522 unique_fd create_jdwp_connection_fd(int pid) {
523 return {};
524 }
525
create_app_tracker_service_socket()526 asocket* create_app_tracker_service_socket() {
527 return nullptr;
528 }
529
create_jdwp_tracker_service_socket()530 asocket* create_jdwp_tracker_service_socket() {
531 return nullptr;
532 }
533
init_jdwp()534 int init_jdwp() {
535 return 0;
536 }
537
538 #endif /* defined(__ANDROID_RECOVERY__) */
539