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

Commit db037bcd authored by Dan Albert's avatar Dan Albert Committed by Gerrit Code Review
Browse files

Merge "Make atransport be a real class."

parents 9dd0914a c7915a34
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ adb_version := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/nul
ADB_COMMON_CFLAGS := \
    -Wall -Wextra -Werror \
    -Wno-unused-parameter \
    -Wno-missing-field-initializers \
    -DADB_REVISION='"$(adb_version)"' \

# libadb
@@ -45,7 +46,6 @@ LIBADB_TEST_SRCS := \

LIBADB_CFLAGS := \
    $(ADB_COMMON_CFLAGS) \
    -Wno-missing-field-initializers \
    -fvisibility=hidden \

LIBADB_darwin_SRC_FILES := \
+62 −49
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#include <limits.h>
#include <sys/types.h>

#include <base/macros.h>

#include "adb_trace.h"
#include "fdevent.h"

@@ -43,7 +45,7 @@
// Increment this when we want to force users to start a new adb server.
#define ADB_SERVER_VERSION 32

struct atransport;
class atransport;
struct usb_handle;

struct amessage {
@@ -152,15 +154,14 @@ struct adisconnect
};


/* a transport object models the connection to a remote device or emulator
** there is one transport per connected device/emulator. a "local transport"
** connects through TCP (for the emulator), while a "usb transport" through
** USB (for real devices)
**
** note that kTransportHost doesn't really correspond to a real transport
** object, it's a special value used to indicate that a client wants to
** connect to a service implemented within the ADB server itself.
*/
// A transport object models the connection to a remote device or emulator there
// is one transport per connected device/emulator. A "local transport" connects
// through TCP (for the emulator), while a "usb transport" through USB (for real
// devices).
//
// Note that kTransportHost doesn't really correspond to a real transport
// object, it's a special value used to indicate that a client wants to connect
// to a service implemented within the ADB server itself.
enum TransportType {
    kTransportUsb,
    kTransportLocal,
@@ -182,47 +183,59 @@ enum ConnectionState {
    kCsUnauthorized,
};

struct atransport
{
    atransport *next;
    atransport *prev;
class atransport {
public:
    // TODO(danalbert): We expose waaaaaaay too much stuff because this was
    // historically just a struct, but making the whole thing a more idiomatic
    // class in one go is a very large change. Given how bad our testing is,
    // it's better to do this piece by piece.

    int (*read_from_remote)(apacket *p, atransport *t);
    int (*write_to_remote)(apacket *p, atransport *t);
    void (*close)(atransport *t);
    void (*kick)(atransport *t);
    atransport() {
        auth_fde = {};
        transport_fde = {};
    }

    int fd;
    int transport_socket;
    virtual ~atransport() {}

    int (*read_from_remote)(apacket* p, atransport* t) = nullptr;
    int (*write_to_remote)(apacket* p, atransport* t) = nullptr;
    void (*close)(atransport* t) = nullptr;
    void (*kick)(atransport* t) = nullptr;

    int fd = -1;
    int transport_socket = -1;
    fdevent transport_fde;
    int ref_count;
    unsigned sync_token;
    int connection_state;
    int online;
    TransportType type;

        /* usb handle or socket fd as needed */
    usb_handle *usb;
    int sfd;

        /* used to identify transports for clients */
    char *serial;
    char *product;
    char *model;
    char *device;
    char *devpath;
    int adb_port; // Use for emulators (local transport)

        /* a list of adisconnect callbacks called when the transport is kicked */
    int          kicked;
    adisconnect  disconnects;

    void *key;
    unsigned char token[TOKEN_SIZE];
    int ref_count = 0;
    uint32_t sync_token = 0;
    ConnectionState connection_state = kCsOffline;
    bool online = false;
    TransportType type = kTransportAny;

    // USB handle or socket fd as needed.
    usb_handle* usb = nullptr;
    int sfd = -1;

    // Used to identify transports for clients.
    char* serial = nullptr;
    char* product = nullptr;
    char* model = nullptr;
    char* device = nullptr;
    char* devpath = nullptr;
    int adb_port = -1;  // Use for emulators (local transport)
    bool kicked = false;

    // A list of adisconnect callbacks called when the transport is kicked.
    adisconnect disconnects = {};

    void* key = nullptr;
    unsigned char token[TOKEN_SIZE] = {};
    fdevent auth_fde;
    unsigned failed_auth_attempts;
    size_t failed_auth_attempts = 0;

    const char* connection_state_name() const;

private:
    DISALLOW_COPY_AND_ASSIGN(atransport);
};


+60 −94
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@
#include <string.h>
#include <unistd.h>

#include <list>

#include <base/stringprintf.h>

#include "adb.h"
@@ -33,15 +35,8 @@

static void transport_unref(atransport *t);

static atransport transport_list = {
    .next = &transport_list,
    .prev = &transport_list,
};

static atransport pending_list = {
    .next = &pending_list,
    .prev = &pending_list,
};
static std::list<atransport*> transport_list;
static std::list<atransport*> pending_list;

ADB_MUTEX_DEFINE( transport_lock );

@@ -553,8 +548,7 @@ static void transport_registration_func(int _fd, unsigned ev, void *data)
        adb_close(t->fd);

        adb_mutex_lock(&transport_lock);
        t->next->prev = t->prev;
        t->prev->next = t->next;
        transport_list.remove(t);
        adb_mutex_unlock(&transport_lock);

        run_transport_disconnects(t);
@@ -570,8 +564,7 @@ static void transport_registration_func(int _fd, unsigned ev, void *data)
        if (t->devpath)
            free(t->devpath);

        memset(t,0xee,sizeof(atransport));
        free(t);
        delete t;

        update_transports();
        return;
@@ -608,14 +601,8 @@ static void transport_registration_func(int _fd, unsigned ev, void *data)
    }

    adb_mutex_lock(&transport_lock);
    /* remove from pending list */
    t->next->prev = t->prev;
    t->prev->next = t->next;
    /* put us on the master device list */
    t->next = &transport_list;
    t->prev = transport_list.prev;
    t->next->prev = t;
    t->prev->next = t;
    pending_list.remove(t);
    transport_list.push_front(t);
    adb_mutex_unlock(&transport_lock);

    t->disconnects.next = t->disconnects.prev = &t->disconnects;
@@ -740,7 +727,6 @@ static int qual_match(const char *to_test,

atransport* acquire_one_transport(ConnectionState state, TransportType type,
                                  const char* serial, std::string* error_out) {
    atransport *t;
    atransport *result = NULL;
    int ambiguous = 0;

@@ -748,7 +734,7 @@ retry:
    if (error_out) *error_out = android::base::StringPrintf("device '%s' not found", serial);

    adb_mutex_lock(&transport_lock);
    for (t = transport_list.next; t != &transport_list; t = t->next) {
    for (auto t : transport_list) {
        if (t->connection_state == kCsNoPerm) {
            if (error_out) *error_out = "insufficient permissions for device";
            continue;
@@ -866,7 +852,8 @@ static void append_transport_info(std::string* result, const char* key,
    }
}

static void append_transport(atransport* t, std::string* result, bool long_listing) {
static void append_transport(const atransport* t, std::string* result,
                             bool long_listing) {
    const char* serial = t->serial;
    if (!serial || !serial[0]) {
        serial = "(no serial number)";
@@ -890,7 +877,7 @@ static void append_transport(atransport* t, std::string* result, bool long_listi
std::string list_transports(bool long_listing) {
    std::string result;
    adb_mutex_lock(&transport_lock);
    for (atransport* t = transport_list.next; t != &transport_list; t = t->next) {
    for (const auto t : transport_list) {
        append_transport(t, &result, long_listing);
    }
    adb_mutex_unlock(&transport_lock);
@@ -898,10 +885,9 @@ std::string list_transports(bool long_listing) {
}

/* hack for osx */
void close_usb_devices()
{
void close_usb_devices() {
    adb_mutex_lock(&transport_lock);
    for (atransport* t = transport_list.next; t != &transport_list; t = t->next) {
    for (auto t : transport_list) {
        if (!t->kicked) {
            t->kicked = 1;
            t->kick(t);
@@ -911,47 +897,39 @@ void close_usb_devices()
}
#endif // ADB_HOST

int register_socket_transport(int s, const char *serial, int port, int local)
{
    atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport)));
    if (t == nullptr) {
        return -1;
    }

    atransport *n;
    char buff[32];
int register_socket_transport(int s, const char *serial, int port, int local) {
    atransport* t = new atransport();

    if (!serial) {
        snprintf(buff, sizeof buff, "T-%p", t);
        serial = buff;
        char buf[32];
        snprintf(buf, sizeof(buf), "T-%p", t);
        serial = buf;
    }

    D("transport: %s init'ing for socket %d, on port %d\n", serial, s, port);
    if (init_socket_transport(t, s, port, local) < 0) {
        free(t);
        delete t;
        return -1;
    }

    adb_mutex_lock(&transport_lock);
    for (n = pending_list.next; n != &pending_list; n = n->next) {
        if (n->serial && !strcmp(serial, n->serial)) {
    for (auto transport : pending_list) {
        if (transport->serial && strcmp(serial, transport->serial) == 0) {
            adb_mutex_unlock(&transport_lock);
            free(t);
            delete t;
            return -1;
        }
    }

    for (n = transport_list.next; n != &transport_list; n = n->next) {
        if (n->serial && !strcmp(serial, n->serial)) {
    for (auto transport : transport_list) {
        if (transport->serial && strcmp(serial, transport->serial) == 0) {
            adb_mutex_unlock(&transport_lock);
            free(t);
            delete t;
            return -1;
        }
    }

    t->next = &pending_list;
    t->prev = pending_list.prev;
    t->next->prev = t;
    t->prev->next = t;
    pending_list.push_front(t);
    t->serial = strdup(serial);
    adb_mutex_unlock(&transport_lock);

@@ -960,52 +938,47 @@ int register_socket_transport(int s, const char *serial, int port, int local)
}

#if ADB_HOST
atransport *find_transport(const char *serial)
{
    atransport *t;
atransport *find_transport(const char *serial) {
    atransport* result = nullptr;

    adb_mutex_lock(&transport_lock);
    for(t = transport_list.next; t != &transport_list; t = t->next) {
        if (t->serial && !strcmp(serial, t->serial)) {
    for (auto t : transport_list) {
        if (t->serial && strcmp(serial, t->serial) == 0) {
            result = t;
            break;
        }
    }
    adb_mutex_unlock(&transport_lock);

    if (t != &transport_list)
        return t;
    else
        return 0;
    return result;
}

void unregister_transport(atransport *t)
{
    adb_mutex_lock(&transport_lock);
    t->next->prev = t->prev;
    t->prev->next = t->next;
    transport_list.remove(t);
    adb_mutex_unlock(&transport_lock);

    kick_transport(t);
    transport_unref(t);
}

// unregisters all non-emulator TCP transports
void unregister_all_tcp_transports()
{
    atransport *t, *next;
// Unregisters all non-emulator TCP transports.
void unregister_all_tcp_transports() {
    adb_mutex_lock(&transport_lock);
    for (t = transport_list.next; t != &transport_list; t = next) {
        next = t->next;
    for (auto it = transport_list.begin(); it != transport_list.end(); ) {
        atransport* t = *it;
        if (t->type == kTransportLocal && t->adb_port == 0) {
            t->next->prev = t->prev;
            t->prev->next = next;
            // we cannot call kick_transport when holding transport_lock
            if (!t->kicked)
            {
            // We cannot call kick_transport when holding transport_lock.
            if (!t->kicked) {
                t->kicked = 1;
                t->kick(t);
            }
            transport_unref_locked(t);

            it = transport_list.erase(it);
        } else {
            ++it;
        }
    }

@@ -1014,25 +987,23 @@ void unregister_all_tcp_transports()

#endif

void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable)
{
    atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport)));
    if (t == nullptr) fatal("cannot allocate USB atransport");
void register_usb_transport(usb_handle* usb, const char* serial,
                            const char* devpath, unsigned writeable) {
    atransport* t = new atransport();

    D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
      serial ? serial : "");
    init_usb_transport(t, usb, (writeable ? kCsOffline : kCsNoPerm));
    if(serial) {
        t->serial = strdup(serial);
    }

    if (devpath) {
        t->devpath = strdup(devpath);
    }

    adb_mutex_lock(&transport_lock);
    t->next = &pending_list;
    t->prev = pending_list.prev;
    t->next->prev = t;
    t->prev->next = t;
    pending_list.push_front(t);
    adb_mutex_unlock(&transport_lock);

    register_transport(t);
@@ -1041,14 +1012,9 @@ void register_usb_transport(usb_handle *usb, const char *serial, const char *dev
// This should only be used for transports with connection_state == kCsNoPerm.
void unregister_usb_transport(usb_handle *usb) {
    adb_mutex_lock(&transport_lock);
    for (atransport* t = transport_list.next; t != &transport_list;
         t = t->next) {
        if (t->usb == usb && t->connection_state == kCsNoPerm) {
            t->next->prev = t->prev;
            t->prev->next = t->next;
            break;
        }
    }
    transport_list.remove_if([usb](atransport* t) {
        return t->usb == usb && t->connection_state == kCsNoPerm;
    });
    adb_mutex_unlock(&transport_lock);
}

+58 −7
Original line number Diff line number Diff line
@@ -20,34 +20,85 @@

#include "adb.h"

class TestTransport : public atransport {
public:
    bool operator==(const atransport& rhs) const {
        EXPECT_EQ(read_from_remote, rhs.read_from_remote);
        EXPECT_EQ(write_to_remote, rhs.write_to_remote);
        EXPECT_EQ(close, rhs.close);
        EXPECT_EQ(kick, rhs.kick);

        EXPECT_EQ(fd, rhs.fd);
        EXPECT_EQ(transport_socket, rhs.transport_socket);

        EXPECT_EQ(
            0, memcmp(&transport_fde, &rhs.transport_fde, sizeof(fdevent)));

        EXPECT_EQ(ref_count, rhs.ref_count);
        EXPECT_EQ(sync_token, rhs.sync_token);
        EXPECT_EQ(connection_state, rhs.connection_state);
        EXPECT_EQ(online, rhs.online);
        EXPECT_EQ(type, rhs.type);

        EXPECT_EQ(usb, rhs.usb);
        EXPECT_EQ(sfd, rhs.sfd);

        EXPECT_EQ(serial, rhs.serial);
        EXPECT_EQ(product, rhs.product);
        EXPECT_EQ(model, rhs.model);
        EXPECT_EQ(device, rhs.device);
        EXPECT_EQ(devpath, rhs.devpath);
        EXPECT_EQ(adb_port, rhs.adb_port);
        EXPECT_EQ(kicked, rhs.kicked);

        EXPECT_EQ(
            0, memcmp(&disconnects, &rhs.disconnects, sizeof(adisconnect)));

        EXPECT_EQ(key, rhs.key);
        EXPECT_EQ(0, memcmp(token, rhs.token, TOKEN_SIZE));
        EXPECT_EQ(0, memcmp(&auth_fde, &rhs.auth_fde, sizeof(fdevent)));
        EXPECT_EQ(failed_auth_attempts, rhs.failed_auth_attempts);

        return true;
    }
};

TEST(transport, kick_transport) {
  atransport t = {};
  TestTransport t;

  // Mutate some member so we can test that the function is run.
  t.kick = [](atransport* trans) { trans->fd = 42; };
  atransport expected = t;

  TestTransport expected;
  expected.kick = t.kick;
  expected.fd = 42;
  expected.kicked = 1;

  kick_transport(&t);
  ASSERT_EQ(42, t.fd);
  ASSERT_EQ(1, t.kicked);
  ASSERT_EQ(0, memcmp(&expected, &t, sizeof(atransport)));
  ASSERT_EQ(expected, t);
}

TEST(transport, kick_transport_already_kicked) {
  // Ensure that the transport is not modified if the transport has already been
  // kicked.
  atransport t = {};
  TestTransport t;
  t.kicked = 1;
  t.kick = [](atransport*) { FAIL() << "Kick should not have been called"; };
  atransport expected = t;

  TestTransport expected;
  expected.kicked = 1;
  expected.kick = t.kick;

  kick_transport(&t);
  ASSERT_EQ(0, memcmp(&expected, &t, sizeof(atransport)));
  ASSERT_EQ(expected, t);
}

// Disabled because the function currently segfaults for a zeroed atransport. I
// want to make sure I understand how this is working at all before I try fixing
// that.
TEST(transport, DISABLED_run_transport_disconnects_zeroed_atransport) {
  atransport t = {};
  atransport t;
  run_transport_disconnects(&t);
}