Merge changes Ibfa5e7e6,I706b57a9,I53d21134,I69d4d585
am: 9674bcbd23
Change-Id: Ibfec0e2581ec6ec6167d63e05deeed1263f0f458
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index c41db24..d6ce1a4 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -1795,6 +1795,11 @@
}
else if (!strcmp(argv[0], "track-devices")) {
return adb_connect_command("host:track-devices");
+ } else if (!strcmp(argv[0], "raw")) {
+ if (argc != 2) {
+ return syntax_error("adb raw SERVICE");
+ }
+ return adb_connect_command(argv[1]);
}
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 1b7758c..f98c11a 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -21,6 +21,7 @@
#include "fdevent.h"
#include <fcntl.h>
+#include <inttypes.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -34,6 +35,7 @@
#include <unordered_map>
#include <vector>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
@@ -75,6 +77,8 @@
static bool main_thread_valid;
static uint64_t main_thread_id;
+static uint64_t fdevent_id;
+
static bool run_needs_flush = false;
static auto& run_queue_notify_fd = *new unique_fd();
static auto& run_queue_mutex = *new std::mutex();
@@ -111,7 +115,8 @@
if (fde->state & FDE_ERROR) {
state += "E";
}
- return android::base::StringPrintf("(fdevent %d %s)", fde->fd.get(), state.c_str());
+ return android::base::StringPrintf("(fdevent %" PRIu64 ": fd %d %s)", fde->id, fde->fd.get(),
+ state.c_str());
}
void fdevent_install(fdevent* fde, int fd, fd_func func, void* arg) {
@@ -125,6 +130,7 @@
CHECK_GE(fd, 0);
fdevent* fde = new fdevent();
+ fde->id = fdevent_id++;
fde->state = FDE_ACTIVE;
fde->fd.reset(fd);
fde->func = func;
@@ -352,10 +358,56 @@
}
}
+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;
+ std::chrono::steady_clock::time_point timestamp;
+ uint64_t cycle;
+ };
+ static auto& g_continuously_pending = *new std::unordered_map<uint64_t, SpinCheck>();
+
+ auto now = std::chrono::steady_clock::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 > std::chrono::minutes(5)) {
+ 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;
@@ -365,6 +417,8 @@
fdevent_process();
+ fdevent_check_spin(cycle++);
+
while (!g_pending_list.empty()) {
fdevent* fde = g_pending_list.front();
g_pending_list.pop_front();
diff --git a/adb/fdevent.h b/adb/fdevent.h
index 69c4072..d501b86 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -32,8 +32,7 @@
typedef void (*fd_func)(int fd, unsigned events, void *userdata);
struct fdevent {
- fdevent* next = nullptr;
- fdevent* prev = nullptr;
+ uint64_t id;
unique_fd fd;
int force_eof = 0;
diff --git a/adb/services.cpp b/adb/services.cpp
index a757d90..b613d83 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -181,6 +181,29 @@
kick_transport(t);
}
+static void spin_service(int fd, void*) {
+ unique_fd sfd(fd);
+
+ if (!__android_log_is_debuggable()) {
+ WriteFdExactly(sfd.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(sfd.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(sfd.get(), "spinning\n");
+}
+
int reverse_service(const char* command, atransport* transport) {
int s[2];
if (adb_socketpair(s)) {
@@ -328,6 +351,8 @@
reinterpret_cast<void*>(1));
} else if (!strcmp(name, "reconnect")) {
ret = create_service_thread("reconnect", reconnect_service, transport);
+ } else if (!strcmp(name, "spin")) {
+ ret = create_service_thread("spin", spin_service, nullptr);
#endif
}
if (ret >= 0) {