Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9674bcbd authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes Ibfa5e7e6,I706b57a9,I53d21134,I69d4d585

* changes:
  adb: detect some spin loops and abort.
  adb: add an id field to fdevent.
  adb: delete unused members in fdevent.
  adb: add `adb raw` to connect to an arbitrary service.
parents 812ba6a4 3bbc8164
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -1795,6 +1795,11 @@ int adb_commandline(int argc, const char** argv) {
    }
    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]);
    }


+55 −1
Original line number Diff line number Diff line
@@ -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 std::atomic<bool> terminate_loop(false);
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 @@ static std::string dump_fde(const fdevent* fde) {
    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 @@ fdevent* fdevent_create(int fd, fd_func func, void* arg) {
    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 @@ 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;
        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 @@ 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();
+1 −2
Original line number Diff line number Diff line
@@ -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;
+25 −0
Original line number Diff line number Diff line
@@ -181,6 +181,29 @@ static void reconnect_service(int fd, void* arg) {
    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 @@ int service_to_fd(const char* name, atransport* transport) {
                                    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) {