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 ReadFdExactly(int fd, void* buf, size_t len) { char* p = reinterpret_cast<char*>(buf); #if ADB_TRACE size_t len0 = len; #endif D("readx: fd=%d wanted=%zu\n", fd, len); while (len > 0) { int r = adb_read(fd, p, len); if (r > 0) { len -= r; p += r; } else if (r == -1) { D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno)); return false; } else { D("readx: fd=%d disconnected\n", fd); errno = 0; return false; } } #if ADB_TRACE D("readx: fd=%d wanted=%zu got=%zu\n", fd, len0, len0 - len); if (ADB_TRACING) { dump_hex(reinterpret_cast<const unsigned char*>(buf), len0); } #endif return true; }
static void echo_service(int fd, void *cookie) { char buf[4096]; int r; char *p; int c; for (;;) { r = adb_read(fd, buf, 4096); if (r == 0) goto done; if (r < 0) { if (errno == EINTR) continue; else goto done; } c = r; p = buf; while (c > 0) { r = write(fd, p, c); if (r > 0) { c -= r; p += r; continue; } if ((r < 0) && (errno == EINTR)) continue; goto done; } } done: close(fd); }
bool ReadFdExactly(int fd, void* buf, size_t len) { char* p = reinterpret_cast<char*>(buf); size_t len0 = len; D("readx: fd=%d wanted=%zu", fd, len); while (len > 0) { int r = adb_read(fd, p, len); if (r > 0) { len -= r; p += r; } else if (r == -1) { D("readx: fd=%d error %d: %s", fd, errno, strerror(errno)); return false; } else { D("readx: fd=%d disconnected", fd); errno = 0; return false; } } VLOG(RWX) << "readx: fd=" << fd << " wanted=" << len0 << " got=" << (len0 - len) << " " << dump_hex(reinterpret_cast<const unsigned char*>(buf), len0); return true; }
TEST_F(sysdeps_poll, fd_count) { // https://code.google.com/p/android/issues/detail?id=12141 static constexpr int num_sockets = 512; std::vector<int> sockets; std::vector<adb_pollfd> pfds; sockets.resize(num_sockets * 2); for (int32_t i = 0; i < num_sockets; ++i) { ASSERT_EQ(0, adb_socketpair(&sockets[i * 2])) << strerror(errno); ASSERT_TRUE(WriteFdExactly(sockets[i * 2], &i, sizeof(i))); adb_pollfd pfd; pfd.events = POLLIN; pfd.fd = sockets[i * 2 + 1]; pfds.push_back(pfd); } ASSERT_EQ(num_sockets, adb_poll(pfds.data(), pfds.size(), 0)); for (int i = 0; i < num_sockets; ++i) { ASSERT_NE(0, pfds[i].revents & POLLIN); int32_t buf[2] = { -1, -1 }; ASSERT_EQ(adb_read(pfds[i].fd, buf, sizeof(buf)), static_cast<ssize_t>(sizeof(int32_t))); ASSERT_EQ(i, buf[0]); } for (int fd : sockets) { adb_close(fd); } }
int readx(int fd, void *ptr, size_t len) { char *p = (char *)ptr; int r; #if ADB_TRACE_FORCE int len0 = len; #endif D("readx: fd=%d wanted=%d\n", fd, (int)len); while(len > 0) { r = adb_read(fd, p, len); if(r > 0) { len -= r; p += r; } else { if (r < 0) { D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno)); if (errno == EINTR) continue; } else { D("readx: fd=%d disconnected\n", fd); } return -1; } } #if ADB_TRACE_FORCE D("readx: fd=%d wanted=%d got=%d\n", fd, len0, len0 - len); dump_hex( ptr, len0 ); #endif return 0; }
static int read_packet(int fd, const char* name, apacket** ppacket) { char *p = (char*)ppacket; /* really read a packet address */ int r; int len = sizeof(*ppacket); char buff[8]; if (!name) { snprintf(buff, sizeof buff, "fd=%d", fd); name = buff; } while(len > 0) { r = adb_read(fd, p, len); if(r > 0) { len -= r; p += r; } else { D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno)); if((r < 0) && (errno == EINTR)) continue; return -1; } } #if ADB_TRACE_FORCE //if (ADB_TRACING) { dump_packet(name, "from remote", *ppacket); // } #endif 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 bool do_recv(int s, const char* path, std::vector<char>& buffer) { int fd = adb_open(path, O_RDONLY | O_CLOEXEC); if (fd < 0) { SendSyncFailErrno(s, "open failed"); return false; } syncmsg msg; msg.data.id = ID_DATA; while (true) { int r = adb_read(fd, &buffer[0], buffer.size()); if (r <= 0) { if (r == 0) break; SendSyncFailErrno(s, "read failed"); adb_close(fd); return false; } msg.data.size = r; if (!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || !WriteFdExactly(s, &buffer[0], r)) { adb_close(fd); return false; } } adb_close(fd); msg.data.id = ID_DONE; msg.data.size = 0; return WriteFdExactly(s, &msg.data, sizeof(msg.data)); }
int readx(int fd, void *ptr, size_t len) { char *p = ptr; int r; #if ADB_TRACE int len0 = len; #endif D("readx: %d %p %d\n", fd, ptr, (int)len); while(len > 0) { r = adb_read(fd, p, len); if(r > 0) { len -= r; p += r; } else { D("readx: %d %d %s\n", fd, r, strerror(errno)); if((r < 0) && (errno == EINTR)) continue; return -1; } } #if ADB_TRACE D("readx: %d ok: ", fd); dump_hex( ptr, len0 ); #endif return 0; }
static int get_target_device_size(int fd, const char *blk_device, uint64_t *device_size) { int data_device; struct ext4_super_block sb; struct fs_info info; info.len = 0; /* Only len is set to 0 to ask the device for real size. */ data_device = adb_open(blk_device, O_RDONLY | O_CLOEXEC); if (data_device < 0) { write_console(fd, "Error opening block device (%s)\n", strerror(errno)); return -1; } if (lseek64(data_device, 1024, SEEK_SET) < 0) { write_console(fd, "Error seeking to superblock\n"); adb_close(data_device); return -1; } if (adb_read(data_device, &sb, sizeof(sb)) != sizeof(sb)) { write_console(fd, "Error reading superblock\n"); adb_close(data_device); return -1; } ext4_parse_sb(&sb, &info); *device_size = info.len; adb_close(data_device); return 0; }
// Watcher void *watcher(void *path) { char * moved_from = 0; int events = IN_CREATE | IN_MOVED_TO | IN_MOVED_FROM | IN_DELETE | IN_MODIFY; int plen = strlen((char *) path); // initialize and watch the entire directory tree from the current working // directory downwards for all events if (!inotifytools_initialize() || !inotifytools_watch_recursively(path, events)) { fprintf(stderr, "%s\n", strerror(inotifytools_error())); return -1; } else { fprintf(stderr, "Watching %s\n", (char *) path); } // set time format to 24 hour time, HH:MM:SS inotifytools_set_printf_timefmt("%T"); // Output all events as "<timestamp> <path> <events>" struct inotify_event * event = inotifytools_next_event(-1); while (event) { inotifytools_printf(event, "%T %w%f %e\n"); // For recursivity if ((event->mask & IN_CREATE) || (!moved_from && (event->mask & IN_MOVED_TO))) { // New file - if it is a directory, watch it static char * new_file; nasprintf(&new_file, "%s%s", inotifytools_filename_from_wd( event->wd), event->name); //ACTION if(isdir(new_file)) { int fd; char buf[4096]; snprintf(buf, sizeof buf, "shell:mkdir \"%s\%s\"", fdir( inotifytools_filename_from_wd(event->wd), plen), event->name); fd = adb_connect(buf); adb_read(fd, buf, 4096); if (fd < 0) { fprintf(stderr,"error: %s\n", adb_error()); return -1; } adb_close(fd); } else { do_sync_push(new_file, fdir(inotifytools_filename_from_wd( event->wd), plen), 0); } if (isdir(new_file) && !inotifytools_watch_recursively(new_file, events)) { fprintf(stderr, "Couldn't watch new directory %s: %s\n", new_file, strerror(inotifytools_error())); } free(new_file); } // IN_CREATE else if (event->mask & IN_MOVED_FROM) {
static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show_progress) { int lfd, err = 0; unsigned long long size = 0; lfd = adb_open(path, O_RDONLY); if(lfd < 0) { fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno)); return -1; } if (show_progress) { // Determine local file size. struct stat st; if (fstat(lfd, &st)) { fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno)); return -1; } size = st.st_size; } sbuf->id = ID_DATA; for(;;) { int ret; ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX); if(!ret) break; if(ret < 0) { if(errno == EINTR) continue; fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno)); break; } sbuf->size = htoll(ret); if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){ err = -1; break; } total_bytes += ret; if (show_progress) { print_transfer_progress(total_bytes, size); } } adb_close(lfd); return err; }
int usb_read(usb_handle *h, void *data, int len) { int n; D("about to read (fd=%d, len=%d)\n", h->fd, len); n = adb_read(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; }
static void read_and_dump(int fd) { char buf[4096]; int len; while(fd >= 0) { len = adb_read(fd, buf, 4096); if(len == 0) { break; } if(len < 0) { if(errno == EINTR) continue; break; } /* we want to output to stdout, so no adb_write here !! */ unix_write(1, buf, len); } }
static int transport_read_action(int fd, struct tmsg* m) { char *p = (char*)m; int len = sizeof(*m); int r; while(len > 0) { r = adb_read(fd, p, len); if(r > 0) { len -= r; p += r; } else { D("transport_read_action: on fd %d: %s", fd, strerror(errno)); return -1; } } return 0; }
static void read_and_dump(int fd) { char buf[4096]; int len; while(fd >= 0) { len = adb_read(fd, buf, 4096); if(len == 0) { break; } if(len < 0) { if(errno == EINTR) continue; break; } fwrite(buf, 1, len, stdout); fflush(stdout); } }
static int read_packet(int fd, apacket** ppacket) { char *p = (char*)ppacket; /* really read a packet address */ int r; int len = sizeof(*ppacket); while(len > 0) { r = adb_read(fd, p, len); if(r > 0) { len -= r; p += r; } else { D("read_packet: %d error %d %d\n", fd, r, errno); if((r < 0) && (errno == EINTR)) continue; return -1; } } #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("read_packet: %d ok: [%08x %s] %08x %08x (%d) ", fd, command, cmd, (*ppacket)->msg.arg0, (*ppacket)->msg.arg1, len); dump_hex((*ppacket)->data, len); } #endif return 0; }
static int transport_read_action(int fd, struct tmsg* m) { char *p = (char*)m; int len = sizeof(*m); int r; while(len > 0) { r = adb_read(fd, p, len); if(r > 0) { len -= r; p += r; } else { if((r < 0) && (errno == EINTR)) continue; D("transport_read_action: on fd %d, error %d: %s\n", fd, errno, strerror(errno)); return -1; } } return 0; }
static void read_and_dump(int fd) { char buf[4096]; int len; while(fd >= 0) { D("read_and_dump(): pre adb_read(fd=%d)\n", fd); len = adb_read(fd, buf, 4096); D("read_and_dump(): post adb_read(fd=%d): len=%d\n", fd, len); if(len == 0) { break; } if(len < 0) { if(errno == EINTR) continue; break; } fwrite(buf, 1, len, stdout); fflush(stdout); } }
bool ReadOrderlyShutdown(int fd) { char buf[16]; // Only call this function if you're sure that the peer does // orderly/graceful shutdown of the socket, closing the socket so that // adb_read() will return 0. If the peer keeps the socket open, adb_read() // will never return. int result = adb_read(fd, buf, sizeof(buf)); if (result == -1) { // If errno is EAGAIN, that means this function was called on a // nonblocking socket and it would have blocked (which would be bad // because we'd probably block the main thread where nonblocking IO is // done). Don't do that. If you have a nonblocking socket, use the // fdevent APIs to get called on FDE_READ, and then call this function // if you really need to, but it shouldn't be needed for server sockets. CHECK_NE(errno, EAGAIN); // Note that on Windows, orderly shutdown sometimes causes // recv() == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET. That // can be ignored. return false; } else if (result == 0) { // Peer has performed an orderly/graceful shutdown. return true; } else { // Unexpectedly received data. This is essentially a protocol error // because you should not call this function unless you expect no more // data. We don't repeatedly call adb_read() until we get zero because // we don't know how long that would take, but we do know that the // caller wants to close the socket soon. VLOG(RWX) << "ReadOrderlyShutdown(" << fd << ") unexpectedly read " << dump_hex(buf, result); // Shutdown the socket to prevent the caller from reading or writing to // it which doesn't make sense if we just read and discarded some data. adb_shutdown(fd); errno = EINVAL; return false; } }
static int write_data_file(int fd, const char *path, syncsendbuf *sbuf) { int lfd, err = 0; lfd = adb_open(path, O_RDONLY); if(lfd < 0) { fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno)); return -1; } sbuf->id = ID_DATA; for(;;) { int ret; ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX); if(!ret) break; if(ret < 0) { if(errno == EINTR) continue; fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno)); break; } sbuf->size = htoll(ret); if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){ err = -1; break; } total_bytes += ret; STATUS(); } adb_close(lfd); return err; }
static char *_send_shellcommand(transport_type transport, char* serial, char* cmd) { int fd; if((fd=_adb_connect(cmd))<0) { return NULL; } char buf[4096<<2]; char *ptr=buf; int left=sizeof(buf); int len = 0; while(left>0) { int n = adb_read(fd, ptr, left); if(n>0) { ptr += n; left -= n; len += n; } else if(n<=0) { break; } } adb_close(fd); return strndup(buf, len); }
static int read_packet(int fd, const char* name, apacket** ppacket) { char buff[8]; if (!name) { snprintf(buff, sizeof buff, "fd=%d", fd); name = buff; } char* p = reinterpret_cast<char*>(ppacket); /* really read a packet address */ int len = sizeof(apacket*); while(len > 0) { int r = adb_read(fd, p, len); if(r > 0) { len -= r; p += r; } else { D("%s: read_packet (fd=%d), error ret=%d: %s", name, fd, r, strerror(errno)); return -1; } } VLOG(TRANSPORT) << dump_packet(name, "from remote", *ppacket); return 0; }
/* 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 launch_server(int server_port) { #if defined(_WIN32) /* we need to start the server in the background */ /* we create a PIPE that will be used to wait for the server's "OK" */ /* message since the pipe handles must be inheritable, we use a */ /* security attribute */ HANDLE pipe_read, pipe_write; HANDLE stdout_handle, stderr_handle; SECURITY_ATTRIBUTES sa; STARTUPINFO startup; PROCESS_INFORMATION pinfo; char program_path[ MAX_PATH ]; int ret; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; /* create pipe, and ensure its read handle isn't inheritable */ ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 ); if (!ret) { fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() ); return -1; } SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 ); /* Some programs want to launch an adb command and collect its output by * calling CreateProcess with inheritable stdout/stderr handles, then * using read() to get its output. When this happens, the stdout/stderr * handles passed to the adb client process will also be inheritable. * When starting the adb server here, care must be taken to reset them * to non-inheritable. * Otherwise, something bad happens: even if the adb command completes, * the calling process is stuck while read()-ing from the stdout/stderr * descriptors, because they're connected to corresponding handles in the * adb server process (even if the latter never uses/writes to them). */ stdout_handle = GetStdHandle( STD_OUTPUT_HANDLE ); stderr_handle = GetStdHandle( STD_ERROR_HANDLE ); if (stdout_handle != INVALID_HANDLE_VALUE) { SetHandleInformation( stdout_handle, HANDLE_FLAG_INHERIT, 0 ); } if (stderr_handle != INVALID_HANDLE_VALUE) { SetHandleInformation( stderr_handle, HANDLE_FLAG_INHERIT, 0 ); } ZeroMemory( &startup, sizeof(startup) ); startup.cb = sizeof(startup); startup.hStdInput = GetStdHandle( STD_INPUT_HANDLE ); startup.hStdOutput = pipe_write; startup.hStdError = GetStdHandle( STD_ERROR_HANDLE ); startup.dwFlags = STARTF_USESTDHANDLES; ZeroMemory( &pinfo, sizeof(pinfo) ); /* get path of current program */ GetModuleFileName( NULL, program_path, sizeof(program_path) ); char args[64]; snprintf(args, sizeof(args), "adb -P %d fork-server server", server_port); ret = CreateProcess( program_path, /* program path */ args, /* the fork-server argument will set the debug = 2 in the child */ NULL, /* process handle is not inheritable */ NULL, /* thread handle is not inheritable */ TRUE, /* yes, inherit some handles */ DETACHED_PROCESS, /* the new process doesn't have a console */ NULL, /* use parent's environment block */ NULL, /* use parent's starting directory */ &startup, /* startup info, i.e. std handles */ &pinfo ); CloseHandle( pipe_write ); if (!ret) { fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() ); CloseHandle( pipe_read ); return -1; } CloseHandle( pinfo.hProcess ); CloseHandle( pinfo.hThread ); /* wait for the "OK\n" message */ { char temp[3]; DWORD count; ret = ReadFile( pipe_read, temp, 3, &count, NULL ); CloseHandle( pipe_read ); if ( !ret ) { fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() ); return -1; } if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') { fprintf(stderr, "ADB server didn't ACK\n" ); return -1; } } #else /* !defined(_WIN32) */ char path[PATH_MAX]; int fd[2]; // set up a pipe so the child can tell us when it is ready. // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child. if (pipe(fd)) { fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno); return -1; } get_my_path(path, PATH_MAX); pid_t pid = fork(); if(pid < 0) return -1; if (pid == 0) { // child side of the fork // redirect stderr to the pipe // we use stderr instead of stdout due to stdout's buffering behavior. adb_close(fd[0]); dup2(fd[1], STDERR_FILENO); adb_close(fd[1]); char str_port[30]; snprintf(str_port, sizeof(str_port), "%d", server_port); // child process int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL); // this should not return fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno); } else { // parent side of the fork char temp[3]; temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C'; // wait for the "OK\n" message adb_close(fd[1]); int ret = adb_read(fd[0], temp, 3); int saved_errno = errno; adb_close(fd[0]); if (ret < 0) { fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno); return -1; } if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') { fprintf(stderr, "ADB server didn't ACK\n" ); return -1; } setsid(); } #endif /* !defined(_WIN32) */ return 0; }
static int do_send(int s, char *path, char *buffer) { char *tmp; unsigned int mode; int is_link, ret; bool do_unlink; tmp = strrchr(path,','); if(tmp) { *tmp = 0; errno = 0; mode = strtoul(tmp + 1, NULL, 0); #ifndef HAVE_SYMLINKS is_link = 0; #else is_link = S_ISLNK((mode_t) mode); #endif mode &= 0777; } if(!tmp || errno) { mode = 0644; is_link = 0; do_unlink = true; } else { struct stat st; /* Don't delete files before copying if they are not "regular" */ do_unlink = lstat(path, &st) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode); if (do_unlink) { adb_unlink(path); } } #ifdef HAVE_SYMLINKS if(is_link) ret = handle_send_link(s, path, buffer); else { #else { #endif uid_t uid = -1; gid_t gid = -1; uint64_t cap = 0; /* copy user permission bits to "group" and "other" permissions */ mode |= ((mode >> 3) & 0070); mode |= ((mode >> 3) & 0007); tmp = path; if(*tmp == '/') { tmp++; } if (is_on_system(path) || is_on_vendor(path)) { fs_config(tmp, 0, &uid, &gid, &mode, &cap); } ret = handle_send_file(s, path, uid, gid, mode, buffer, do_unlink); } return ret; } static int do_recv(int s, const char *path, char *buffer) { syncmsg msg; int fd, r; fd = adb_open(path, O_RDONLY | O_CLOEXEC); if(fd < 0) { if(fail_errno(s)) return -1; return 0; } msg.data.id = ID_DATA; for(;;) { if(syc_size_enabled == 1) { r = adb_read(fd, buffer, SYNC_DATA_MAX_CUSTOMIZE); } else { r = adb_read(fd, buffer, SYNC_DATA_MAX); } if(r <= 0) { if(r == 0) break; if(errno == EINTR) continue; r = fail_errno(s); adb_close(fd); return r; } msg.data.size = htoll(r); if(writex(s, &msg.data, sizeof(msg.data)) || writex(s, buffer, r)) { adb_close(fd); return -1; } } adb_close(fd); msg.data.id = ID_DONE; msg.data.size = 0; if(writex(s, &msg.data, sizeof(msg.data))) { return -1; } return 0; }
int launch_server(int server_port) { #ifdef HAVE_WIN32_PROC /* we need to start the server in the background */ /* we create a PIPE that will be used to wait for the server's "OK" */ /* message since the pipe handles must be inheritable, we use a */ /* security attribute */ HANDLE pipe_read, pipe_write; SECURITY_ATTRIBUTES sa; STARTUPINFO startup; PROCESS_INFORMATION pinfo; char program_path[ MAX_PATH ]; int ret; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; /* create pipe, and ensure its read handle isn't inheritable */ ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 ); if (!ret) { fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() ); return -1; } SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 ); ZeroMemory( &startup, sizeof(startup) ); startup.cb = sizeof(startup); startup.hStdInput = GetStdHandle( STD_INPUT_HANDLE ); startup.hStdOutput = pipe_write; startup.hStdError = GetStdHandle( STD_ERROR_HANDLE ); startup.dwFlags = STARTF_USESTDHANDLES; ZeroMemory( &pinfo, sizeof(pinfo) ); /* get path of current program */ GetModuleFileName( NULL, program_path, sizeof(program_path) ); ret = CreateProcess( program_path, /* program path */ "adb fork-server server", /* the fork-server argument will set the debug = 2 in the child */ NULL, /* process handle is not inheritable */ NULL, /* thread handle is not inheritable */ TRUE, /* yes, inherit some handles */ DETACHED_PROCESS, /* the new process doesn't have a console */ NULL, /* use parent's environment block */ NULL, /* use parent's starting directory */ &startup, /* startup info, i.e. std handles */ &pinfo ); CloseHandle( pipe_write ); if (!ret) { fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() ); CloseHandle( pipe_read ); return -1; } CloseHandle( pinfo.hProcess ); CloseHandle( pinfo.hThread ); /* wait for the "OK\n" message */ { char temp[3]; DWORD count; ret = ReadFile( pipe_read, temp, 3, &count, NULL ); CloseHandle( pipe_read ); if ( !ret ) { fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() ); return -1; } if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') { fprintf(stderr, "ADB server didn't ACK\n" ); return -1; } } #elif defined(HAVE_FORKEXEC) char path[PATH_MAX]; int fd[2]; // set up a pipe so the child can tell us when it is ready. // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child. if (pipe(fd)) { fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno); return -1; } get_my_path(path, PATH_MAX); pid_t pid = fork(); if(pid < 0) return -1; if (pid == 0) { // child side of the fork // redirect stderr to the pipe // we use stderr instead of stdout due to stdout's buffering behavior. adb_close(fd[0]); dup2(fd[1], STDERR_FILENO); adb_close(fd[1]); // child process int result = execl(path, "adb", "fork-server", "server", NULL); // this should not return fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno); } else { // parent side of the fork char temp[3]; temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C'; // wait for the "OK\n" message adb_close(fd[1]); int ret = adb_read(fd[0], temp, 3); adb_close(fd[0]); if (ret < 0) { fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", errno); return -1; } if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') { fprintf(stderr, "ADB server didn't ACK\n" ); return -1; } setsid(); } #else #error "cannot implement background server start on this platform" #endif return 0; }
static int sync_send(int fd, const char *lpath, const char *rpath, unsigned mtime, mode_t mode, int verifyApk) { syncmsg msg; int len, r; syncsendbuf *sbuf = &send_buffer; char* file_buffer = NULL; int size = 0; char tmp[64]; len = strlen(rpath); if(len > 1024) goto fail; snprintf(tmp, sizeof(tmp), ",%d", mode); r = strlen(tmp); if (verifyApk) { int lfd; zipfile_t zip; zipentry_t entry; int amt; // if we are transferring an APK file, then sanity check to make sure // we have a real zip file that contains an AndroidManifest.xml // this requires that we read the entire file into memory. lfd = adb_open(lpath, O_RDONLY); if(lfd < 0) { fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno)); return -1; } size = adb_lseek(lfd, 0, SEEK_END); if (size == -1 || -1 == adb_lseek(lfd, 0, SEEK_SET)) { fprintf(stderr, "error seeking in file '%s'\n", lpath); adb_close(lfd); return 1; } file_buffer = (char *)malloc(size); if (file_buffer == NULL) { fprintf(stderr, "could not allocate buffer for '%s'\n", lpath); adb_close(lfd); return 1; } amt = adb_read(lfd, file_buffer, size); if (amt != size) { fprintf(stderr, "error reading from file: '%s'\n", lpath); adb_close(lfd); free(file_buffer); return 1; } adb_close(lfd); zip = init_zipfile(file_buffer, size); if (zip == NULL) { fprintf(stderr, "file '%s' is not a valid zip file\n", lpath); free(file_buffer); return 1; } entry = lookup_zipentry(zip, "AndroidManifest.xml"); release_zipfile(zip); if (entry == NULL) { fprintf(stderr, "file '%s' does not contain AndroidManifest.xml\n", lpath); free(file_buffer); return 1; } } msg.req.id = ID_SEND; msg.req.namelen = htoll(len + r); if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, rpath, len) || writex(fd, tmp, r)) { free(file_buffer); goto fail; } if (file_buffer) { write_data_buffer(fd, file_buffer, size, sbuf); free(file_buffer); } else if (S_ISREG(mode)) write_data_file(fd, lpath, sbuf); #ifdef HAVE_SYMLINKS else if (S_ISLNK(mode)) write_data_link(fd, lpath, sbuf); #endif else goto fail; msg.data.id = ID_DONE; msg.data.size = htoll(mtime); if(writex(fd, &msg.data, sizeof(msg.data))) goto fail; if(readx(fd, &msg.status, sizeof(msg.status))) return -1; if(msg.status.id != ID_OKAY) { if(msg.status.id == ID_FAIL) { len = ltohl(msg.status.msglen); if(len > 256) len = 256; if(readx(fd, sbuf->data, len)) { return -1; } sbuf->data[len] = 0; } else strcpy(sbuf->data, "unknown reason"); fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data); return -1; } return 0; fail: fprintf(stderr,"protocol failure\n"); adb_close(fd); return -1; }