Merge "llkd: Do not check ueventd by default for stack"
diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
index b40faee..fe79acd 100644
--- a/adb/daemon/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -212,6 +212,7 @@
 
 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) {
@@ -225,82 +226,50 @@
             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()) {
-            int fd = proc->out_fds.back().get();
-            struct cmsghdr* cmsg;
-            struct msghdr msg;
-            struct iovec iov;
-            char dummy = '!';
-            char buffer[sizeof(struct cmsghdr) + sizeof(int)];
+        CHECK(!proc->out_fds.empty());
 
-            iov.iov_base = &dummy;
-            iov.iov_len = 1;
-            msg.msg_name = nullptr;
-            msg.msg_namelen = 0;
-            msg.msg_iov = &iov;
-            msg.msg_iovlen = 1;
-            msg.msg_flags = 0;
-            msg.msg_control = buffer;
-            msg.msg_controllen = sizeof(buffer);
+        int fd = proc->out_fds.back().get();
+        struct cmsghdr* cmsg;
+        struct msghdr msg;
+        struct iovec iov;
+        char dummy = '!';
+        char buffer[sizeof(struct cmsghdr) + sizeof(int)];
 
-            cmsg = CMSG_FIRSTHDR(&msg);
-            cmsg->cmsg_len = msg.msg_controllen;
-            cmsg->cmsg_level = SOL_SOCKET;
-            cmsg->cmsg_type = SCM_RIGHTS;
-            ((int*)CMSG_DATA(cmsg))[0] = fd;
+        iov.iov_base = &dummy;
+        iov.iov_len = 1;
+        msg.msg_name = nullptr;
+        msg.msg_namelen = 0;
+        msg.msg_iov = &iov;
+        msg.msg_iovlen = 1;
+        msg.msg_flags = 0;
+        msg.msg_control = buffer;
+        msg.msg_controllen = sizeof(buffer);
 
-            if (!set_file_block_mode(proc->socket, true)) {
-                VLOG(JDWP) << "failed to set blocking mode for fd " << proc->socket;
-                goto CloseProcess;
-            }
+        cmsg = CMSG_FIRSTHDR(&msg);
+        cmsg->cmsg_len = msg.msg_controllen;
+        cmsg->cmsg_level = SOL_SOCKET;
+        cmsg->cmsg_type = SCM_RIGHTS;
+        ((int*)CMSG_DATA(cmsg))[0] = fd;
 
-            int ret = TEMP_FAILURE_RETRY(sendmsg(proc->socket, &msg, 0));
-            if (ret < 0) {
-                D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno));
-                goto CloseProcess;
-            }
+        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;
+        }
 
-            D("sent file descriptor %d to JDWP process %d", fd, proc->pid);
+        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);
-            }
+        proc->out_fds.pop_back();
+        if (proc->out_fds.empty()) {
+            fdevent_del(proc->fde, FDE_WRITE);
         }
     }
 
@@ -406,9 +375,10 @@
     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) {
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index 2bac486..720ec6a 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -202,6 +202,27 @@
     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)};
@@ -254,6 +275,9 @@
     } 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{};
 }
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 98a73eb..e096560 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -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>
@@ -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
@@ -247,6 +250,7 @@
     }
     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;
@@ -367,10 +371,66 @@
     }
 }
 
+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;
@@ -380,6 +440,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/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 3f663ef..b3fce54 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -131,6 +131,11 @@
     if (args.size() < 2) {
         return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
     }
+
+    if (GetDeviceLockStatus()) {
+        return device->WriteStatus(FastbootResult::FAIL, "Erase is not allowed on locked devices");
+    }
+
     PartitionHandle handle;
     if (!OpenPartition(device, args[1], &handle)) {
         return device->WriteStatus(FastbootResult::FAIL, "Partition doesn't exist");
@@ -163,6 +168,12 @@
     if (args.size() < 2) {
         return device->WriteStatus(FastbootResult::FAIL, "size argument unspecified");
     }
+
+    if (GetDeviceLockStatus()) {
+        return device->WriteStatus(FastbootResult::FAIL,
+                                   "Download is not allowed on locked devices");
+    }
+
     // arg[0] is the command name, arg[1] contains size of data to be downloaded
     unsigned int size;
     if (!android::base::ParseUint("0x" + args[1], &size, UINT_MAX)) {
@@ -203,6 +214,11 @@
         return device->WriteStatus(FastbootResult::FAIL, "Missing slot argument");
     }
 
+    if (GetDeviceLockStatus()) {
+        return device->WriteStatus(FastbootResult::FAIL,
+                                   "set_active command is not allowed on locked devices");
+    }
+
     // Slot suffix needs to be between 'a' and 'z'.
     Slot slot;
     if (!GetSlotNumber(args[1], &slot)) {