static int get_fb_from_adb(struct fb *fb) { char buf[1024]; const struct fbinfo* fbinfo; int bytes_read; /* Init socket */ adb_fd = remote_socket("localhost", 5037); if (adb_fd < 0) { E("Failed to create socket, %s", strerror(errno)); return -1; } adb_write("host:transport-"); bytes_read = adb_read(buf, 1024); if (bytes_read <= 0) return -1; adb_write("framebuffer:"); bytes_read = adb_read(buf, 1024); if (bytes_read <= 0) return -1; /* Parse FB header. */ bytes_read = adb_read(buf, sizeof(struct fbinfo)); if (bytes_read <= 0 || (unsigned int)bytes_read < sizeof (struct fbinfo)) { E("Failed to read the FB Info data!", strerror(errno)); return -1; } fbinfo = (struct fbinfo*) buf; if (fbinfo->version != DDMS_RAWIMAGE_VERSION) { E("Unsupported adb version."); return -1; } /* Assemble struct fb */ memcpy(fb, &fbinfo->bpp, sizeof(struct fbinfo) - 4); fb_dump(fb); fb->data = malloc(fb->size); if (!fb->data) return -1; /* Read out the whole framebuffer */ bytes_read = 0; while ((unsigned int)bytes_read < fb->size) { int br = adb_read((char*)fb->data + bytes_read, fb->size - bytes_read); if (br <= 0) return -1; bytes_read += br; } return 0; }
bool WriteFdExactly(int fd, const void* buf, size_t len) { const char* p = reinterpret_cast<const char*>(buf); int r; VLOG(RWX) << "writex: fd=" << fd << " len=" << len << " " << dump_hex(reinterpret_cast<const unsigned char*>(buf), len); while (len > 0) { r = adb_write(fd, p, len); if (r == -1) { D("writex: fd=%d error %d: %s", fd, errno, strerror(errno)); if (errno == EAGAIN) { adb_sleep_ms(1); // just yield some cpu time continue; } else if (errno == EPIPE) { D("writex: fd=%d disconnected", fd); errno = 0; return false; } else { return false; } } else { len -= r; p += r; } } return true; }
bool WriteFdExactly(int fd, const void* buf, size_t len) { const char* p = reinterpret_cast<const char*>(buf); int r; #if ADB_TRACE D("writex: fd=%d len=%d: ", fd, (int)len); if (ADB_TRACING) { dump_hex(reinterpret_cast<const unsigned char*>(buf), len); } #endif while (len > 0) { r = adb_write(fd, p, len); if (r == -1) { D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno)); if (errno == EAGAIN) { adb_sleep_ms(1); // just yield some cpu time continue; } else if (errno == EPIPE) { D("writex: fd=%d disconnected\n", fd); errno = 0; return false; } else { return false; } } else { len -= r; p += r; } } return true; }
int writex(int fd, const void *ptr, size_t len) { char *p = (char*) ptr; int r; #if ADB_TRACE_FORCE D("writex: fd=%d len=%d: ", fd, (int)len); dump_hex( ptr, len ); #endif while(len > 0) { r = adb_write(fd, p, len); if(r > 0) { len -= r; p += r; } else { if (r < 0) { D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno)); if (errno == EINTR) continue; } else { D("writex: fd=%d disconnected\n", fd); } return -1; } } return 0; }
static int write_packet(int fd, const char* name, apacket** ppacket) { char *p = (char*) ppacket; /* we really write the packet address */ int r, len = sizeof(ppacket); char buff[8]; if (!name) { snprintf(buff, sizeof buff, "fd=%d", fd); name = buff; } #if ADB_TRACE_FORCE // if (ADB_TRACING) { dump_packet(name, "to remote", *ppacket); // } #endif len = sizeof(ppacket); while(len > 0) { r = adb_write(fd, p, len); if(r > 0) { len -= r; p += r; } else { D("%s: write_packet (fd=%d) error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno)); if((r < 0) && (errno == EINTR)) continue; return -1; } } return 0; }
/* this is used by magic sockets to rig local sockets to send the go-ahead message when they connect */ static void local_socket_ready_notify(asocket *s) { s->ready = local_socket_ready; s->close = local_socket_close; adb_write(s->fd, "OKAY", 4); s->ready(s); }
int writex(int fd, const void *ptr, size_t len) { char *p = (char*)ptr; int r; #if ADB_TRACE D("writex: fd=%d len=%d: ", fd, (int)len); dump_hex((const unsigned char *)ptr, len); #endif while (len > 0) { r = adb_write(fd, p, len); if (r > 0) { len -= r; p += r; } else { if (r < 0) { D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno)); if (errno == EINTR) continue; if (errno == EAGAIN) { adb_sleep_ms(1); // just yield some cpu time continue; } } else { D("writex: fd=%d disconnected\n", fd); } return -1; } } return 0; }
static void copy_to_file(int inFd, int outFd) { const size_t BUFSIZE = 32 * 1024; char* buf = (char*) malloc(BUFSIZE); int len; long total = 0; D("copy_to_file(%d -> %d)\n", inFd, outFd); for (;;) { len = adb_read(inFd, buf, BUFSIZE); if (len == 0) { D("copy_to_file() : read 0 bytes; exiting\n"); break; } if (len < 0) { if (errno == EINTR) { D("copy_to_file() : EINTR, retrying\n"); continue; } D("copy_to_file() : error %d\n", errno); break; } adb_write(outFd, buf, len); total += len; } D("copy_to_file() finished after %lu bytes\n", total); free(buf); }
static void write_console(int fd, const char* format, ...) { char buffer[256]; va_list args; va_start (args, format); vsnprintf (buffer, sizeof(buffer), format, args); va_end (args); adb_write(fd, buffer, strnlen(buffer, sizeof(buffer))); }
int adb_send_emulator_command(int argc, char **argv) { int fd, nn; fd = connect_to_console(); if (fd < 0) return 1; #define QUIT "quit\n" for (nn = 1; nn < argc; nn++) { adb_write(fd, argv[nn], strlen(argv[nn])); adb_write(fd, (nn == argc - 1) ? "\n" : " ", 1); } adb_write(fd, QUIT, sizeof(QUIT) - 1); adb_close(fd); return 0; }
void adb_qemu_trace(const char* fmt, ...) { va_list args; va_start(args, fmt); char msg[1024]; if (adb_debug_qemu >= 0) { vsnprintf(msg, sizeof(msg), fmt, args); adb_write(adb_debug_qemu, msg, strlen(msg)); } }
int adb_send_emulator_command(int argc, char** argv) { int fd, nn; printf("function = %s, file = %s, line = %u \n", __FUNCTION__, __FILE__, __LINE__); fd = connect_to_console(); if (fd < 0) return 1; #define QUIT "quit\n" for (nn = 1; nn < argc; nn++) { adb_write( fd, argv[nn], strlen(argv[nn]) ); adb_write( fd, (nn == argc-1) ? "\n" : " ", 1 ); } adb_write( fd, QUIT, sizeof(QUIT)-1 ); adb_close(fd); return 0; }
static int local_socket_enqueue(asocket* s, apacket* p) { D("LS(%d): enqueue %zu", s->id, p->len); p->ptr = p->data; /* if there is already data queue'd, we will receive ** events when it's time to write. just add this to ** the tail */ if (s->pkt_first) { goto enqueue; } /* write as much as we can, until we ** would block or there is an error/eof */ while (p->len > 0) { int r = adb_write(s->fd, p->ptr, p->len); if (r > 0) { p->len -= r; p->ptr += r; continue; } if ((r == 0) || (errno != EAGAIN)) { D("LS(%d): not ready, errno=%d: %s", s->id, errno, strerror(errno)); put_apacket(p); s->has_write_error = true; s->close(s); return 1; /* not ready (error) */ } else { break; } } if (p->len == 0) { put_apacket(p); return 0; /* ready for more data */ } enqueue: p->next = 0; if (s->pkt_first) { s->pkt_last->next = p; } else { s->pkt_first = p; } s->pkt_last = p; /* make sure we are notified when we can drain the queue */ fdevent_add(&s->fde, FDE_WRITE); return 1; /* not ready (backlog) */ }
static void *stdin_read_thread(void *x) { int fd, fdi; unsigned char buf[1024]; int r, n; int state = 0; int *fds = (int*) x; fd = fds[0]; fdi = fds[1]; free(fds); for(;;) { /* fdi is really the client's stdin, so use read, not adb_read here */ D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi); r = unix_read(fdi, buf, 1024); D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi); if(r == 0) break; if(r < 0) { if(errno == EINTR) continue; break; } for(n = 0; n < r; n++){ switch(buf[n]) { case '\n': state = 1; break; case '\r': state = 1; break; case '~': if(state == 1) state++; break; case '.': if(state == 2) { fprintf(stderr,"\n* disconnect *\n"); #ifdef HAVE_TERMIO_H stdin_raw_restore(fdi); #endif exit(0); } default: state = 0; } } r = adb_write(fd, buf, r); if(r <= 0) { break; } } return 0; }
static void init_subproc_child() { setsid(); // Set OOM score adjustment to prevent killing int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC); if (fd >= 0) { adb_write(fd, "0", 1); adb_close(fd); } else { D("adb: unable to update oom_score_adj\n"); } }
int usb_write(usb_handle *h, const void *data, int len) { int n; D("about to write (fd=%d, len=%d)\n", h->fd, len); n = adb_write(h->fd, data, len); if(n != len) { D("ERROR: fd = %d, n = %d, errno = %d (%s)\n", h->fd, n, errno, strerror(errno)); return -1; } D("[ done fd=%d ]\n", h->fd); return 0; }
void adbcmds(void) { char cmd; unsigned rtcu, rtcl, dec, pdec, x; int i, j; unsigned char d[64]; cmd = skipbl(); switch (cmd) { case 't': for (;;) { rtcl = get_rtcl(); rtcu = get_rtcu(); dec = get_dec(); printf("rtc u=%u l=%u dec=%x (%d = %d.%.7d)\n", rtcu, rtcl, dec, pdec - dec, (pdec - dec) / 1000000000, ((pdec - dec) % 1000000000) / 100); pdec = dec; if (cmd == 'x') break; while (xmon_read(stdin, &cmd, 1) != 1) ; } break; case 'r': init_adb_log(); while (adb_bitwait(8, 0, 0, 0) == 0) adb_readin(); break; case 'w': i = 0; while (scanhex(&x)) d[i++] = x; init_adb_log(); j = adb_write(d, i); printf("sent %d bytes\n", j); while (adb_bitwait(8, 0, 0, 0) == 0) adb_readin(); break; case 'l': dump_adb_log(); break; } }
static int transport_write_action(int fd, struct tmsg* m) { char *p = (char*)m; int len = sizeof(*m); int r; while(len > 0) { r = adb_write(fd, p, len); if(r > 0) { len -= r; p += r; } else { D("transport_write_action: on fd %d: %s", fd, strerror(errno)); return -1; } } return 0; }
static int write_packet(int fd, apacket** ppacket) { char *p = (char*) ppacket; /* we really write the packet address */ int r, len = sizeof(ppacket); #if ADB_TRACE if (ADB_TRACING) { unsigned command = (*ppacket)->msg.command; int len = (*ppacket)->msg.data_length; char cmd[5]; int n; for (n = 0; n < 4; n++) { int b = (command >> (n*8)) & 255; if (b >= 32 && b < 127) cmd[n] = (char)b; else cmd[n] = '.'; } cmd[4] = 0; D("write_packet: %d [%08x %s] %08x %08x (%d) ", fd, command, cmd, (*ppacket)->msg.arg0, (*ppacket)->msg.arg1, len); dump_hex((*ppacket)->data, len); } #endif len = sizeof(ppacket); while(len > 0) { r = adb_write(fd, p, len); if(r > 0) { len -= r; p += r; } else { D("write_packet: %d error %d %d\n", fd, r, errno); if((r < 0) && (errno == EINTR)) continue; return -1; } } return 0; }
static int sysfs_write(const char *node, const char *message) { int fd; ssize_t to_write; int ret = 0; fd = adb_open(node, O_RDWR); if (!fd) { D("open '%s' failed: %s\n", node, strerror(errno)); return -1; } to_write = strlen(message); if (adb_write(fd, message, to_write) != to_write) { D("write '%s' failed: %s\n", node, strerror(errno)); ret = -1; } adb_close(fd); return ret; }
static int transport_write_action(int fd, struct tmsg* m) { char *p = (char*)m; int len = sizeof(*m); int r; while(len > 0) { r = adb_write(fd, p, len); if(r > 0) { len -= r; p += r; } else { if((r < 0) && (errno == EINTR)) continue; D("transport_write_action: on fd %d, error %d: %s\n", fd, errno, strerror(errno)); return -1; } } return 0; }
static int write_packet(int fd, const char* name, apacket** ppacket) { char buff[8]; if (!name) { snprintf(buff, sizeof buff, "fd=%d", fd); name = buff; } VLOG(TRANSPORT) << dump_packet(name, "to remote", *ppacket); char* p = reinterpret_cast<char*>(ppacket); /* we really write the packet address */ int len = sizeof(apacket*); while(len > 0) { int r = adb_write(fd, p, len); if(r > 0) { len -= r; p += r; } else { D("%s: write_packet (fd=%d) error ret=%d: %s", name, fd, r, strerror(errno)); return -1; } } return 0; }
int writex(int fd, const void *ptr, size_t len) { char *p = (char*) ptr; int r; #if ADB_TRACE D("writex: %d %p %d: ", fd, ptr, (int)len); dump_hex( ptr, len ); #endif while(len > 0) { r = adb_write(fd, p, len); if(r > 0) { len -= r; p += r; } else { D("writex: %d %d %s\n", fd, r, strerror(errno)); if((r < 0) && (errno == EINTR)) continue; return -1; } } D("writex: %d ok\n", fd); return 0; }
int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s) { atransport *transport = NULL; if(!strcmp(service, "kill")) { fprintf(stderr,"adb server killed by remote request\n"); fflush(stdout); adb_write(reply_fd, "OKAY", 4); usb_cleanup(); exit(0); } #if ADB_HOST // "transport:" is used for switching transport with a specified serial number // "transport-usb:" is used for switching transport to the only USB transport // "transport-local:" is used for switching transport to the only local transport // "transport-any:" is used for switching transport to the only transport if (!strncmp(service, "transport", strlen("transport"))) { char* error_string = "unknown failure"; transport_type type = kTransportAny; if (!strncmp(service, "transport-usb", strlen("transport-usb"))) { type = kTransportUsb; } else if (!strncmp(service, "transport-local", strlen("transport-local"))) { type = kTransportLocal; } else if (!strncmp(service, "transport-any", strlen("transport-any"))) { type = kTransportAny; } else if (!strncmp(service, "transport:", strlen("transport:"))) { service += strlen("transport:"); serial = service; } transport = acquire_one_transport(CS_ANY, type, serial, &error_string); if (transport) { s->transport = transport; adb_write(reply_fd, "OKAY", 4); } else { sendfailmsg(reply_fd, error_string); } return 1; } // return a list of all connected devices if (!strncmp(service, "devices", 7)) { char buffer[4096]; int use_long = !strcmp(service+7, "-l"); if (use_long || service[7] == 0) { memset(buffer, 0, sizeof(buffer)); D("Getting device list \n"); list_transports(buffer, sizeof(buffer), use_long); D("Wrote device list \n"); send_msg_with_okay(reply_fd, buffer, strlen(buffer)); return 0; } } // remove TCP transport if (!strncmp(service, "disconnect:", 11)) { char buffer[4096]; memset(buffer, 0, sizeof(buffer)); char* serial = service + 11; if (serial[0] == 0) { // disconnect from all TCP devices unregister_all_tcp_transports(); } else { char hostbuf[100]; // assume port 5555 if no port is specified if (!strchr(serial, ':')) { snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial); serial = hostbuf; } atransport *t = find_transport(serial); if (t) { unregister_transport(t); } else { snprintf(buffer, sizeof(buffer), "No such device %s", serial); } } send_msg_with_okay(reply_fd, buffer, strlen(buffer)); return 0; } // returns our value for ADB_SERVER_VERSION if (!strcmp(service, "version")) { char version[12]; snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION); send_msg_with_okay(reply_fd, version, strlen(version)); return 0; } if(!strncmp(service,"get-serialno",strlen("get-serialno"))) { char *out = "unknown"; transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); if (transport && transport->serial) { out = transport->serial; } send_msg_with_okay(reply_fd, out, strlen(out)); return 0; } if(!strncmp(service,"get-devpath",strlen("get-devpath"))) { char *out = "unknown"; transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); if (transport && transport->devpath) { out = transport->devpath; } send_msg_with_okay(reply_fd, out, strlen(out)); return 0; } // indicates a new emulator instance has started if (!strncmp(service,"emulator:",9)) { int port = atoi(service+9); local_connect(port); /* we don't even need to send a reply */ return 0; } #endif // ADB_HOST int ret = handle_forward_request(service, ttype, serial, reply_fd); if (ret >= 0) return ret - 1; if(!strncmp(service,"get-state",strlen("get-state"))) { transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); char *state = connection_state_name(transport); send_msg_with_okay(reply_fd, state, strlen(state)); return 0; } return -1; }
int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s) { atransport *transport = NULL; char buf[4096]; if(!strcmp(service, "kill")) { fprintf(stderr,"adb server killed by remote request\n"); fflush(stdout); adb_write(reply_fd, "OKAY", 4); usb_cleanup(); exit(0); } #if ADB_HOST // "transport:" is used for switching transport with a specified serial number // "transport-usb:" is used for switching transport to the only USB transport // "transport-local:" is used for switching transport to the only local transport // "transport-any:" is used for switching transport to the only transport if (!strncmp(service, "transport", strlen("transport"))) { char* error_string = "unknown failure"; transport_type type = kTransportAny; if (!strncmp(service, "transport-usb", strlen("transport-usb"))) { type = kTransportUsb; } else if (!strncmp(service, "transport-local", strlen("transport-local"))) { type = kTransportLocal; } else if (!strncmp(service, "transport-any", strlen("transport-any"))) { type = kTransportAny; } else if (!strncmp(service, "transport:", strlen("transport:"))) { service += strlen("transport:"); serial = strdup(service); } transport = acquire_one_transport(CS_ANY, type, serial, &error_string); if (transport) { s->transport = transport; adb_write(reply_fd, "OKAY", 4); } else { sendfailmsg(reply_fd, error_string); } return 1; } // return a list of all connected devices if (!strcmp(service, "devices")) { char buffer[4096]; memset(buf, 0, sizeof(buf)); memset(buffer, 0, sizeof(buffer)); D("Getting device list \n"); list_transports(buffer, sizeof(buffer)); snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer); D("Wrote device list \n"); writex(reply_fd, buf, strlen(buf)); return 0; } // add a new TCP transport, device or emulator if (!strncmp(service, "connect:", 8)) { char buffer[4096]; char* host = service + 8; if (!strncmp(host, "emu:", 4)) { connect_emulator(host + 4, buffer, sizeof(buffer)); } else { connect_device(host, buffer, sizeof(buffer)); } // Send response for emulator and device snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer); writex(reply_fd, buf, strlen(buf)); return 0; } // remove TCP transport if (!strncmp(service, "disconnect:", 11)) { char buffer[4096]; memset(buffer, 0, sizeof(buffer)); char* serial = service + 11; if (serial[0] == 0) { // disconnect from all TCP devices unregister_all_tcp_transports(); } else { char hostbuf[100]; // assume port 5555 if no port is specified if (!strchr(serial, ':')) { snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial); serial = hostbuf; } atransport *t = find_transport(serial); if (t) { unregister_transport(t); } else { snprintf(buffer, sizeof(buffer), "No such device %s", serial); } } snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer); writex(reply_fd, buf, strlen(buf)); return 0; } // returns our value for ADB_SERVER_VERSION if (!strcmp(service, "version")) { char version[12]; snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION); snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version); writex(reply_fd, buf, strlen(buf)); return 0; } if(!strncmp(service,"get-serialno",strlen("get-serialno"))) { char *out = "unknown"; transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); if (transport && transport->serial) { out = transport->serial; } snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out); writex(reply_fd, buf, strlen(buf)); return 0; } // indicates a new emulator instance has started if (!strncmp(service,"emulator:",9)) { int port = atoi(service+9); local_connect(port); /* we don't even need to send a reply */ return 0; } #endif // ADB_HOST if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) { char *local, *remote, *err; int r; atransport *transport; int createForward = strncmp(service,"kill",4); local = service + (createForward ? 8 : 12); remote = strchr(local,';'); if(remote == 0) { sendfailmsg(reply_fd, "malformed forward spec"); return 0; } *remote++ = 0; if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){ sendfailmsg(reply_fd, "malformed forward spec"); return 0; } transport = acquire_one_transport(CS_ANY, ttype, serial, &err); if (!transport) { sendfailmsg(reply_fd, err); return 0; } if (createForward) { r = install_listener(local, remote, transport); } else { r = remove_listener(local, remote, transport); } if(r == 0) { /* 1st OKAY is connect, 2nd OKAY is status */ writex(reply_fd, "OKAYOKAY", 8); return 0; } if (createForward) { sendfailmsg(reply_fd, (r == -1) ? "cannot rebind smartsocket" : "cannot bind socket"); } else { sendfailmsg(reply_fd, "cannot remove listener"); } return 0; } if(!strncmp(service,"get-state",strlen("get-state"))) { transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); char *state = connection_state_name(transport); snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state); writex(reply_fd, buf, strlen(buf)); return 0; } return -1; }
/* A worker thread that monitors host connections, and registers a transport for * every new host connection. This thread replaces server_socket_thread on * condition that adbd daemon runs inside the emulator, and emulator uses QEMUD * pipe to communicate with adbd daemon inside the guest. This is done in order * to provide more robust communication channel between ADB host and guest. The * main issue with server_socket_thread approach is that it runs on top of TCP, * and thus is sensitive to network disruptions. For instance, the * ConnectionManager may decide to reset all network connections, in which case * the connection between ADB host and guest will be lost. To make ADB traffic * independent from the network, we use here 'adb' QEMUD service to transfer data * between the host, and the guest. See external/qemu/android/adb-*.* that * implements the emulator's side of the protocol. Another advantage of using * QEMUD approach is that ADB will be up much sooner, since it doesn't depend * anymore on network being set up. * The guest side of the protocol contains the following phases: * - Connect with adb QEMUD service. In this phase a handle to 'adb' QEMUD service * is opened, and it becomes clear whether or not emulator supports that * protocol. * - Wait for the ADB host to create connection with the guest. This is done by * sending an 'accept' request to the adb QEMUD service, and waiting on * response. * - When new ADB host connection is accepted, the connection with adb QEMUD * service is registered as the transport, and a 'start' request is sent to the * adb QEMUD service, indicating that the guest is ready to receive messages. * Note that the guest will ignore messages sent down from the emulator before * the transport registration is completed. That's why we need to send the * 'start' request after the transport is registered. */ static void *qemu_socket_thread(void * arg) { /* 'accept' request to the adb QEMUD service. */ static const char _accept_req[] = "accept"; /* 'start' request to the adb QEMUD service. */ static const char _start_req[] = "start"; /* 'ok' reply from the adb QEMUD service. */ static const char _ok_resp[] = "ok"; const int port = (int) (uintptr_t) arg; int res, fd; char tmp[256]; char con_name[32]; D("transport: qemu_socket_thread() starting\n"); /* adb QEMUD service connection request. */ snprintf(con_name, sizeof(con_name), "qemud:adb:%d", port); /* Connect to the adb QEMUD service. */ fd = qemu_pipe_open(con_name); if (fd < 0) { /* This could be an older version of the emulator, that doesn't * implement adb QEMUD service. Fall back to the old TCP way. */ D("adb service is not available. Falling back to TCP socket.\n"); adb_thread_create(server_socket_thread, arg); return 0; } for(;;) { /* * Wait till the host creates a new connection. */ /* Send the 'accept' request. */ res = adb_write(fd, _accept_req, strlen(_accept_req)); if ((size_t)res == strlen(_accept_req)) { /* Wait for the response. In the response we expect 'ok' on success, * or 'ko' on failure. */ res = adb_read(fd, tmp, sizeof(tmp)); if (res != 2 || memcmp(tmp, _ok_resp, 2)) { D("Accepting ADB host connection has failed.\n"); adb_close(fd); } else { /* Host is connected. Register the transport, and start the * exchange. */ register_socket_transport(fd, "host", port, 1); adb_write(fd, _start_req, strlen(_start_req)); } /* Prepare for accepting of the next ADB host connection. */ fd = qemu_pipe_open(con_name); if (fd < 0) { D("adb service become unavailable.\n"); return 0; } } else { D("Unable to send the '%s' request to ADB service.\n", _accept_req); return 0; } } D("transport: qemu_socket_thread() exiting\n"); return 0; }
static void local_socket_event_func(int fd, unsigned ev, void* _s) { asocket* s = reinterpret_cast<asocket*>(_s); D("LS(%d): event_func(fd=%d(==%d), ev=%04x)", s->id, s->fd, fd, ev); /* put the FDE_WRITE processing before the FDE_READ ** in order to simplify the code. */ if (ev & FDE_WRITE) { apacket* p; while ((p = s->pkt_first) != nullptr) { while (p->len > 0) { int r = adb_write(fd, p->ptr, p->len); if (r == -1) { /* returning here is ok because FDE_READ will ** be processed in the next iteration loop */ if (errno == EAGAIN) { return; } } else if (r > 0) { p->ptr += r; p->len -= r; continue; } D(" closing after write because r=%d and errno is %d", r, errno); s->has_write_error = true; s->close(s); return; } if (p->len == 0) { s->pkt_first = p->next; if (s->pkt_first == 0) { s->pkt_last = 0; } put_apacket(p); } } /* if we sent the last packet of a closing socket, ** we can now destroy it. */ if (s->closing) { D(" closing because 'closing' is set after write"); s->close(s); return; } /* no more packets queued, so we can ignore ** writable events again and tell our peer ** to resume writing */ fdevent_del(&s->fde, FDE_WRITE); s->peer->ready(s->peer); } if (ev & FDE_READ) { apacket* p = get_apacket(); char* x = p->data; const size_t max_payload = s->get_max_payload(); size_t avail = max_payload; int r = 0; int is_eof = 0; while (avail > 0) { r = adb_read(fd, x, avail); D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu", s->id, s->fd, r, r < 0 ? errno : 0, avail); if (r == -1) { if (errno == EAGAIN) { break; } } else if (r > 0) { avail -= r; x += r; continue; } /* r = 0 or unhandled error */ is_eof = 1; break; } D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d", s->id, s->fd, r, is_eof, s->fde.force_eof); if ((avail == max_payload) || (s->peer == 0)) { put_apacket(p); } else { p->len = max_payload - avail; // s->peer->enqueue() may call s->close() and free s, // so save variables for debug printing below. unsigned saved_id = s->id; int saved_fd = s->fd; r = s->peer->enqueue(s->peer, p); D("LS(%u): fd=%d post peer->enqueue(). r=%d", saved_id, saved_fd, r); if (r < 0) { /* error return means they closed us as a side-effect ** and we must return immediately. ** ** note that if we still have buffered packets, the ** socket will be placed on the closing socket list. ** this handler function will be called again ** to process FDE_WRITE events. */ return; } if (r > 0) { /* if the remote cannot accept further events, ** we disable notification of READs. They'll ** be enabled again when we get a call to ready() */ fdevent_del(&s->fde, FDE_READ); } } /* Don't allow a forced eof if data is still there */ if ((s->fde.force_eof && !r) || is_eof) { D(" closing because is_eof=%d r=%d s->fde.force_eof=%d", is_eof, r, s->fde.force_eof); s->close(s); return; } } if (ev & FDE_ERROR) { /* this should be caught be the next read or write ** catching it here means we may skip the last few ** bytes of readable data. */ D("LS(%d): FDE_ERROR (fd=%d)", s->id, s->fd); return; } }
int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s) { D("service=%s, ttype=%d, serial=%s, reply_fd=%d, asocket=?\n", service, ttype, serial, reply_fd); atransport *transport = NULL; char buf[4096]; if(!strcmp(service, "kill")) { fprintf(stderr,"adb server killed by remote request\n"); fflush(stdout); adb_write(reply_fd, "OKAY", 4); usb_cleanup(); exit(0); } #if ADB_HOST // "transport:" is used for switching transport with a specified serial number // "transport-usb:" is used for switching transport to the only USB transport // "transport-local:" is used for switching transport to the only local transport // "transport-any:" is used for switching transport to the only transport if (!strncmp(service, "transport", strlen("transport"))) { char* error_string = "unknown failure"; transport_type type = kTransportAny; if (!strncmp(service, "transport-usb", strlen("transport-usb"))) { type = kTransportUsb; } else if (!strncmp(service, "transport-local", strlen("transport-local"))) { type = kTransportLocal; } else if (!strncmp(service, "transport-any", strlen("transport-any"))) { type = kTransportAny; } else if (!strncmp(service, "transport:", strlen("transport:"))) { service += strlen("transport:"); serial = service; } transport = acquire_one_transport(CS_ANY, type, serial, &error_string); if (transport) { s->transport = transport; adb_write(reply_fd, "OKAY", 4); } else { sendfailmsg(reply_fd, error_string); } return 1; } // return a list of all connected devices if (!strncmp(service, "devices", 7)) { char buffer[4096]; int use_long = !strcmp(service+7, "-l"); if (use_long || service[7] == 0) { memset(buf, 0, sizeof(buf)); memset(buffer, 0, sizeof(buffer)); D("Getting device list \n"); list_transports(buffer, sizeof(buffer), use_long); snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer); D("Wrote device list \n"); writex(reply_fd, buf, strlen(buf)); return 0; } } // add a new TCP transport, device or emulator if (!strncmp(service, "connect:", 8)) { char buffer[4096]; char* host = service + 8; if (!strncmp(host, "emu:", 4)) { connect_emulator(host + 4, buffer, sizeof(buffer)); } else { connect_device(host, buffer, sizeof(buffer)); } // Send response for emulator and device snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer); writex(reply_fd, buf, strlen(buf)); return 0; } // remove TCP transport // Disable the disconnect service to prevent complexity with Windows // // returns our value for ADB_SERVER_VERSION if (!strcmp(service, "version")) { printf("the version service is disabled.\n"); return -1; } if(!strncmp(service,"get-serialno",strlen("get-serialno"))) { char *out = "unknown"; transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); if (transport && transport->serial) { out = transport->serial; } snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out); writex(reply_fd, buf, strlen(buf)); return 0; } if(!strncmp(service,"get-devpath",strlen("get-devpath"))) { char *out = "unknown"; transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); if (transport && transport->devpath) { out = transport->devpath; } snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out); writex(reply_fd, buf, strlen(buf)); return 0; } // indicates a new emulator instance has started if (!strncmp(service,"emulator:",9)) { int port = atoi(service+9); local_connect(port); /* we don't even need to send a reply */ return 0; } #endif // ADB_HOST if(!strcmp(service,"list-forward")) { // Create the list of forward redirections. char header[9]; int buffer_size = format_listeners(NULL, 0); // Add one byte for the trailing zero. char* buffer = (char*)malloc(buffer_size+1); (void) format_listeners(buffer, buffer_size+1); snprintf(header, sizeof header, "OKAY%04x", buffer_size); writex(reply_fd, header, 8); writex(reply_fd, buffer, buffer_size); free(buffer); return 0; } if (!strcmp(service,"killforward-all")) { remove_all_listeners(); adb_write(reply_fd, "OKAYOKAY", 8); return 0; } if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) { char *local, *remote, *err; int r; atransport *transport; int createForward = strncmp(service,"kill",4); int no_rebind = 0; local = strchr(service, ':') + 1; // Handle forward:norebind:<local>... here if (createForward && !strncmp(local, "norebind:", 9)) { no_rebind = 1; local = strchr(local, ':') + 1; } remote = strchr(local,';'); if (createForward) { // Check forward: parameter format: '<local>;<remote>' if(remote == 0) { sendfailmsg(reply_fd, "malformed forward spec"); return 0; } *remote++ = 0; if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){ sendfailmsg(reply_fd, "malformed forward spec"); return 0; } } else { // Check killforward: parameter format: '<local>' if (local[0] == 0) { sendfailmsg(reply_fd, "malformed forward spec"); return 0; } } transport = acquire_one_transport(CS_ANY, ttype, serial, &err); if (!transport) { sendfailmsg(reply_fd, err); return 0; } if (createForward) { r = install_listener(local, remote, transport, no_rebind); } else { r = remove_listener(local, transport); } if(r == 0) { /* 1st OKAY is connect, 2nd OKAY is status */ writex(reply_fd, "OKAYOKAY", 8); return 0; } if (createForward) { const char* message; switch (r) { case INSTALL_STATUS_CANNOT_BIND: message = "cannot bind to socket"; break; case INSTALL_STATUS_CANNOT_REBIND: message = "cannot rebind existing socket"; break; default: message = "internal error"; } sendfailmsg(reply_fd, message); } else { sendfailmsg(reply_fd, "cannot remove listener"); } return 0; } if(!strncmp(service,"get-state",strlen("get-state"))) { transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); char *state = connection_state_name(transport); snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state); writex(reply_fd, buf, strlen(buf)); return 0; } return -1; }
static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid) { #ifdef HAVE_WIN32_PROC D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1); fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1); return -1; #else /* !HAVE_WIN32_PROC */ char *devname; int ptm; ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY); if(ptm < 0){ printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno)); return -1; } fcntl(ptm, F_SETFD, FD_CLOEXEC); if(grantpt(ptm) || unlockpt(ptm) || ((devname = (char*) ptsname(ptm)) == 0)){ printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno)); adb_close(ptm); return -1; } *pid = fork(); if(*pid < 0) { printf("- fork failed: pid(%d) %s -\n", *pid, strerror(errno)); XLOGV("- fork failed: pid(%d) %s -\n", *pid, strerror(errno)); adb_close(ptm); return -1; } if(*pid == 0){ int pts; setsid(); pts = unix_open(devname, O_RDWR); if(pts < 0) { fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname); XLOGV("child failed to open pseudo-term slave: %s\n", devname); exit(-1); } dup2(pts, 0); dup2(pts, 1); dup2(pts, 2); adb_close(pts); adb_close(ptm); // set OOM adjustment to zero char text[64]; snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid()); int fd = adb_open(text, O_WRONLY); if (fd >= 0) { adb_write(fd, "0", 1); adb_close(fd); } else { D("adb: unable to open %s\n", text); XLOGW("adb: unable to open %s\n", text); } timer_t timerid; struct sigevent sev; /* Create the timer */ sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGALRM; sev.sigev_value.sival_ptr = &timerid; if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) { D("adb: Call timer_create failed!\n"); XLOGV("adb: Call timer_create failed!\n"); exit(-1); } struct itimerspec its; /* Start the timer */ its.it_value.tv_sec = 1; its.it_value.tv_nsec = 0; its.it_interval.tv_sec = 3; its.it_interval.tv_nsec = 0; if (timer_settime(timerid, 0, &its, NULL) == -1) { D("adb: Call timer_settime failed!\n"); XLOGV("adb: Call timer_settime failed!\n"); exit(-1); } sigset_t mask; struct sigaction sa; /* Establish handler for timer signal */ sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = catcher; sigemptyset(&sa.sa_mask); if (sigaction(SIGALRM, &sa, NULL) == -1) { D("adb: Call sigaction failed!\n"); XLOGV("adb: Call sigaction failed!\n"); exit(-1); } int nRet = execl(cmd, cmd, arg0, arg1, NULL); fprintf(stderr, "- exec '%s' failed: %s (%d) nRet(%d) -\n", cmd, strerror(errno), errno, nRet); XLOGV("- exec '%s' failed: %s (%d) nRet(%d) -\n", cmd, strerror(errno), errno, nRet); exit(-1); } else { // Don't set child's OOM adjustment to zero. // Let the child do it itself, as sometimes the parent starts // running before the child has a /proc/pid/oom_adj. // """adb: unable to open /proc/644/oom_adj""" seen in some logs. return ptm; } #endif /* !HAVE_WIN32_PROC */ }
// Try to handle a network forwarding request. // This returns 1 on success, 0 on failure, and -1 to indicate this is not // a forwarding-related request. int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd) { if (!strcmp(service, "list-forward")) { // Create the list of forward redirections. int buffer_size = format_listeners(NULL, 0); // Add one byte for the trailing zero. char* buffer = malloc(buffer_size + 1); if (buffer == NULL) { sendfailmsg(reply_fd, "not enough memory"); return 1; } (void) format_listeners(buffer, buffer_size + 1); #if ADB_HOST send_msg_with_okay(reply_fd, buffer, buffer_size); #else send_msg_with_header(reply_fd, buffer, buffer_size); #endif free(buffer); return 1; } if (!strcmp(service, "killforward-all")) { remove_all_listeners(); #if ADB_HOST /* On the host: 1st OKAY is connect, 2nd OKAY is status */ adb_write(reply_fd, "OKAY", 4); #endif adb_write(reply_fd, "OKAY", 4); return 1; } if (!strncmp(service, "forward:",8) || !strncmp(service, "killforward:",12)) { char *local, *remote, *err; int r; atransport *transport; int createForward = strncmp(service, "kill", 4); int no_rebind = 0; local = strchr(service, ':') + 1; // Handle forward:norebind:<local>... here if (createForward && !strncmp(local, "norebind:", 9)) { no_rebind = 1; local = strchr(local, ':') + 1; } remote = strchr(local,';'); if (createForward) { // Check forward: parameter format: '<local>;<remote>' if(remote == 0) { sendfailmsg(reply_fd, "malformed forward spec"); return 1; } *remote++ = 0; if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) { sendfailmsg(reply_fd, "malformed forward spec"); return 1; } } else { // Check killforward: parameter format: '<local>' if (local[0] == 0) { sendfailmsg(reply_fd, "malformed forward spec"); return 1; } } transport = acquire_one_transport(CS_ANY, ttype, serial, &err); if (!transport) { sendfailmsg(reply_fd, err); return 1; } if (createForward) { r = install_listener(local, remote, transport, no_rebind); } else { r = remove_listener(local, transport); } if(r == 0) { #if ADB_HOST /* On the host: 1st OKAY is connect, 2nd OKAY is status */ writex(reply_fd, "OKAY", 4); #endif writex(reply_fd, "OKAY", 4); return 1; } if (createForward) { const char* message; switch (r) { case INSTALL_STATUS_CANNOT_BIND: message = "cannot bind to socket"; break; case INSTALL_STATUS_CANNOT_REBIND: message = "cannot rebind existing socket"; break; default: message = "internal error"; } sendfailmsg(reply_fd, message); } else { sendfailmsg(reply_fd, "cannot remove listener"); } return 1; } return 0; }