Loading adb/daemon/jdwp_service.cpp +39 −69 Original line number Diff line number Diff line Loading @@ -212,6 +212,7 @@ static size_t jdwp_process_list_msg(char* buffer, size_t bufferlen) { static void jdwp_process_event(int socket, unsigned events, void* _proc) { JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc); CHECK_EQ(socket, proc->socket); if (events & FDE_READ) { if (proc->pid < 0) { Loading @@ -225,36 +226,16 @@ static void jdwp_process_event(int socket, unsigned events, void* _proc) { D("Adding pid %d to jdwp process list", proc->pid); jdwp_process_list_updated(); } else { /* the pid was read, if we get there it's probably because the connection * was closed (e.g. the JDWP process exited or crashed) */ char buf[32]; while (true) { int len = TEMP_FAILURE_RETRY(recv(socket, buf, sizeof(buf), 0)); if (len == 0) { D("terminating JDWP %d connection: EOF", proc->pid); break; } else if (len < 0) { if (len < 0 && errno == EAGAIN) { return; } D("terminating JDWP %d connection: EOF", proc->pid); break; } else { D("ignoring unexpected JDWP %d control socket activity (%d bytes)", proc->pid, len); } } // We already have the PID, if we can read from the socket, we've probably hit EOF. D("terminating JDWP connection %d", proc->pid); goto CloseProcess; } } if (events & FDE_WRITE) { D("trying to send fd to JDWP process (count = %zu)", proc->out_fds.size()); if (!proc->out_fds.empty()) { CHECK(!proc->out_fds.empty()); int fd = proc->out_fds.back().get(); struct cmsghdr* cmsg; struct msghdr msg; Loading @@ -278,12 +259,7 @@ static void jdwp_process_event(int socket, unsigned events, void* _proc) { cmsg->cmsg_type = SCM_RIGHTS; ((int*)CMSG_DATA(cmsg))[0] = fd; if (!set_file_block_mode(proc->socket, true)) { VLOG(JDWP) << "failed to set blocking mode for fd " << proc->socket; goto CloseProcess; } int ret = TEMP_FAILURE_RETRY(sendmsg(proc->socket, &msg, 0)); int ret = TEMP_FAILURE_RETRY(sendmsg(socket, &msg, 0)); if (ret < 0) { D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno)); goto CloseProcess; Loading @@ -292,17 +268,10 @@ static void jdwp_process_event(int socket, unsigned events, void* _proc) { D("sent file descriptor %d to JDWP process %d", fd, proc->pid); proc->out_fds.pop_back(); if (!set_file_block_mode(proc->socket, false)) { VLOG(JDWP) << "failed to set non-blocking mode for fd " << proc->socket; goto CloseProcess; } if (proc->out_fds.empty()) { fdevent_del(proc->fde, FDE_WRITE); } } } return; Loading Loading @@ -406,9 +375,10 @@ static int jdwp_control_init(JdwpControl* control, const char* sockname, int soc return 0; } static void jdwp_control_event(int s, unsigned events, void* _control) { static void jdwp_control_event(int fd, unsigned events, void* _control) { JdwpControl* control = (JdwpControl*)_control; CHECK_EQ(fd, control->listen_socket); if (events & FDE_READ) { int s = adb_socket_accept(control->listen_socket, nullptr, nullptr); if (s < 0) { Loading adb/daemon/services.cpp +24 −0 Original line number Diff line number Diff line Loading @@ -202,6 +202,27 @@ unique_fd ShellService(const std::string& args, const atransport* transport) { return StartSubprocess(command.c_str(), terminal_type.c_str(), type, protocol); } static void spin_service(unique_fd fd) { if (!__android_log_is_debuggable()) { WriteFdExactly(fd.get(), "refusing to spin on non-debuggable build\n"); return; } // A service that creates an fdevent that's always pending, and then ignores it. unique_fd pipe_read, pipe_write; if (!Pipe(&pipe_read, &pipe_write)) { WriteFdExactly(fd.get(), "failed to create pipe\n"); return; } fdevent_run_on_main_thread([fd = pipe_read.release()]() { fdevent* fde = fdevent_create(fd, [](int, unsigned, void*) {}, nullptr); fdevent_add(fde, FDE_READ); }); WriteFdExactly(fd.get(), "spinning\n"); } unique_fd daemon_service_to_fd(const char* name, atransport* transport) { if (!strncmp("dev:", name, 4)) { return unique_fd{unix_open(name + 4, O_RDWR | O_CLOEXEC)}; Loading Loading @@ -254,6 +275,9 @@ unique_fd daemon_service_to_fd(const char* name, atransport* transport) { } else if (!strcmp(name, "reconnect")) { return create_service_thread( "reconnect", std::bind(reconnect_service, std::placeholders::_1, transport)); } else if (!strcmp(name, "spin")) { return create_service_thread("spin", spin_service); } return unique_fd{}; } adb/fdevent.cpp +62 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,8 @@ #include <unordered_map> #include <vector> #include <android-base/chrono_utils.h> #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/stringprintf.h> #include <android-base/thread_annotations.h> Loading @@ -44,6 +46,7 @@ #include "adb_trace.h" #include "adb_unique_fd.h" #include "adb_utils.h" #include "sysdeps/chrono.h" #define FDE_EVENTMASK 0x00ff #define FDE_STATEMASK 0xff00 Loading Loading @@ -247,6 +250,7 @@ static void fdevent_process() { } CHECK_GT(pollfds.size(), 0u); D("poll(), pollfds = %s", dump_pollfds(pollfds).c_str()); int ret = adb_poll(&pollfds[0], pollfds.size(), -1); if (ret == -1) { PLOG(ERROR) << "poll(), ret = " << ret; Loading Loading @@ -367,10 +371,66 @@ void fdevent_run_on_main_thread(std::function<void()> fn) { } } static void fdevent_check_spin(uint64_t cycle) { // Check to see if we're spinning because we forgot about an fdevent // by keeping track of how long fdevents have been continuously pending. struct SpinCheck { fdevent* fde; android::base::boot_clock::time_point timestamp; uint64_t cycle; }; static auto& g_continuously_pending = *new std::unordered_map<uint64_t, SpinCheck>(); static auto last_cycle = android::base::boot_clock::now(); auto now = android::base::boot_clock::now(); if (now - last_cycle > 10ms) { // We're not spinning. g_continuously_pending.clear(); last_cycle = now; return; } last_cycle = now; for (auto* fde : g_pending_list) { auto it = g_continuously_pending.find(fde->id); if (it == g_continuously_pending.end()) { g_continuously_pending[fde->id] = SpinCheck{.fde = fde, .timestamp = now, .cycle = cycle}; } else { it->second.cycle = cycle; } } for (auto it = g_continuously_pending.begin(); it != g_continuously_pending.end();) { if (it->second.cycle != cycle) { it = g_continuously_pending.erase(it); } else { // Use an absurdly long window, since all we really care about is // getting a bugreport eventually. if (now - it->second.timestamp > 300s) { LOG(FATAL_WITHOUT_ABORT) << "detected spin in fdevent: " << dump_fde(it->second.fde); #if defined(__linux__) int fd = it->second.fde->fd.get(); std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd); std::string path; if (!android::base::Readlink(fd_path, &path)) { PLOG(FATAL_WITHOUT_ABORT) << "readlink of fd " << fd << " failed"; } LOG(FATAL_WITHOUT_ABORT) << "fd " << fd << " = " << path; #endif abort(); } ++it; } } } void fdevent_loop() { set_main_thread(); fdevent_run_setup(); uint64_t cycle = 0; while (true) { if (terminate_loop) { return; Loading @@ -380,6 +440,8 @@ void fdevent_loop() { fdevent_process(); fdevent_check_spin(cycle++); while (!g_pending_list.empty()) { fdevent* fde = g_pending_list.front(); g_pending_list.pop_front(); Loading Loading
adb/daemon/jdwp_service.cpp +39 −69 Original line number Diff line number Diff line Loading @@ -212,6 +212,7 @@ static size_t jdwp_process_list_msg(char* buffer, size_t bufferlen) { static void jdwp_process_event(int socket, unsigned events, void* _proc) { JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc); CHECK_EQ(socket, proc->socket); if (events & FDE_READ) { if (proc->pid < 0) { Loading @@ -225,36 +226,16 @@ static void jdwp_process_event(int socket, unsigned events, void* _proc) { D("Adding pid %d to jdwp process list", proc->pid); jdwp_process_list_updated(); } else { /* the pid was read, if we get there it's probably because the connection * was closed (e.g. the JDWP process exited or crashed) */ char buf[32]; while (true) { int len = TEMP_FAILURE_RETRY(recv(socket, buf, sizeof(buf), 0)); if (len == 0) { D("terminating JDWP %d connection: EOF", proc->pid); break; } else if (len < 0) { if (len < 0 && errno == EAGAIN) { return; } D("terminating JDWP %d connection: EOF", proc->pid); break; } else { D("ignoring unexpected JDWP %d control socket activity (%d bytes)", proc->pid, len); } } // We already have the PID, if we can read from the socket, we've probably hit EOF. D("terminating JDWP connection %d", proc->pid); goto CloseProcess; } } if (events & FDE_WRITE) { D("trying to send fd to JDWP process (count = %zu)", proc->out_fds.size()); if (!proc->out_fds.empty()) { CHECK(!proc->out_fds.empty()); int fd = proc->out_fds.back().get(); struct cmsghdr* cmsg; struct msghdr msg; Loading @@ -278,12 +259,7 @@ static void jdwp_process_event(int socket, unsigned events, void* _proc) { cmsg->cmsg_type = SCM_RIGHTS; ((int*)CMSG_DATA(cmsg))[0] = fd; if (!set_file_block_mode(proc->socket, true)) { VLOG(JDWP) << "failed to set blocking mode for fd " << proc->socket; goto CloseProcess; } int ret = TEMP_FAILURE_RETRY(sendmsg(proc->socket, &msg, 0)); int ret = TEMP_FAILURE_RETRY(sendmsg(socket, &msg, 0)); if (ret < 0) { D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno)); goto CloseProcess; Loading @@ -292,17 +268,10 @@ static void jdwp_process_event(int socket, unsigned events, void* _proc) { D("sent file descriptor %d to JDWP process %d", fd, proc->pid); proc->out_fds.pop_back(); if (!set_file_block_mode(proc->socket, false)) { VLOG(JDWP) << "failed to set non-blocking mode for fd " << proc->socket; goto CloseProcess; } if (proc->out_fds.empty()) { fdevent_del(proc->fde, FDE_WRITE); } } } return; Loading Loading @@ -406,9 +375,10 @@ static int jdwp_control_init(JdwpControl* control, const char* sockname, int soc return 0; } static void jdwp_control_event(int s, unsigned events, void* _control) { static void jdwp_control_event(int fd, unsigned events, void* _control) { JdwpControl* control = (JdwpControl*)_control; CHECK_EQ(fd, control->listen_socket); if (events & FDE_READ) { int s = adb_socket_accept(control->listen_socket, nullptr, nullptr); if (s < 0) { Loading
adb/daemon/services.cpp +24 −0 Original line number Diff line number Diff line Loading @@ -202,6 +202,27 @@ unique_fd ShellService(const std::string& args, const atransport* transport) { return StartSubprocess(command.c_str(), terminal_type.c_str(), type, protocol); } static void spin_service(unique_fd fd) { if (!__android_log_is_debuggable()) { WriteFdExactly(fd.get(), "refusing to spin on non-debuggable build\n"); return; } // A service that creates an fdevent that's always pending, and then ignores it. unique_fd pipe_read, pipe_write; if (!Pipe(&pipe_read, &pipe_write)) { WriteFdExactly(fd.get(), "failed to create pipe\n"); return; } fdevent_run_on_main_thread([fd = pipe_read.release()]() { fdevent* fde = fdevent_create(fd, [](int, unsigned, void*) {}, nullptr); fdevent_add(fde, FDE_READ); }); WriteFdExactly(fd.get(), "spinning\n"); } unique_fd daemon_service_to_fd(const char* name, atransport* transport) { if (!strncmp("dev:", name, 4)) { return unique_fd{unix_open(name + 4, O_RDWR | O_CLOEXEC)}; Loading Loading @@ -254,6 +275,9 @@ unique_fd daemon_service_to_fd(const char* name, atransport* transport) { } else if (!strcmp(name, "reconnect")) { return create_service_thread( "reconnect", std::bind(reconnect_service, std::placeholders::_1, transport)); } else if (!strcmp(name, "spin")) { return create_service_thread("spin", spin_service); } return unique_fd{}; }
adb/fdevent.cpp +62 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,8 @@ #include <unordered_map> #include <vector> #include <android-base/chrono_utils.h> #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/stringprintf.h> #include <android-base/thread_annotations.h> Loading @@ -44,6 +46,7 @@ #include "adb_trace.h" #include "adb_unique_fd.h" #include "adb_utils.h" #include "sysdeps/chrono.h" #define FDE_EVENTMASK 0x00ff #define FDE_STATEMASK 0xff00 Loading Loading @@ -247,6 +250,7 @@ static void fdevent_process() { } CHECK_GT(pollfds.size(), 0u); D("poll(), pollfds = %s", dump_pollfds(pollfds).c_str()); int ret = adb_poll(&pollfds[0], pollfds.size(), -1); if (ret == -1) { PLOG(ERROR) << "poll(), ret = " << ret; Loading Loading @@ -367,10 +371,66 @@ void fdevent_run_on_main_thread(std::function<void()> fn) { } } static void fdevent_check_spin(uint64_t cycle) { // Check to see if we're spinning because we forgot about an fdevent // by keeping track of how long fdevents have been continuously pending. struct SpinCheck { fdevent* fde; android::base::boot_clock::time_point timestamp; uint64_t cycle; }; static auto& g_continuously_pending = *new std::unordered_map<uint64_t, SpinCheck>(); static auto last_cycle = android::base::boot_clock::now(); auto now = android::base::boot_clock::now(); if (now - last_cycle > 10ms) { // We're not spinning. g_continuously_pending.clear(); last_cycle = now; return; } last_cycle = now; for (auto* fde : g_pending_list) { auto it = g_continuously_pending.find(fde->id); if (it == g_continuously_pending.end()) { g_continuously_pending[fde->id] = SpinCheck{.fde = fde, .timestamp = now, .cycle = cycle}; } else { it->second.cycle = cycle; } } for (auto it = g_continuously_pending.begin(); it != g_continuously_pending.end();) { if (it->second.cycle != cycle) { it = g_continuously_pending.erase(it); } else { // Use an absurdly long window, since all we really care about is // getting a bugreport eventually. if (now - it->second.timestamp > 300s) { LOG(FATAL_WITHOUT_ABORT) << "detected spin in fdevent: " << dump_fde(it->second.fde); #if defined(__linux__) int fd = it->second.fde->fd.get(); std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd); std::string path; if (!android::base::Readlink(fd_path, &path)) { PLOG(FATAL_WITHOUT_ABORT) << "readlink of fd " << fd << " failed"; } LOG(FATAL_WITHOUT_ABORT) << "fd " << fd << " = " << path; #endif abort(); } ++it; } } } void fdevent_loop() { set_main_thread(); fdevent_run_setup(); uint64_t cycle = 0; while (true) { if (terminate_loop) { return; Loading @@ -380,6 +440,8 @@ void fdevent_loop() { fdevent_process(); fdevent_check_spin(cycle++); while (!g_pending_list.empty()) { fdevent* fde = g_pending_list.front(); g_pending_list.pop_front(); Loading