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

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

Merge "adb: Use kernel aio for functionfs."

parents 9f38e19b ecee434f
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -116,7 +116,7 @@ LOCAL_SANITIZE := $(adb_target_sanitize)

# Even though we're building a static library (and thus there's no link step for
# this to take effect), this adds the includes to our path.
LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase
LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase libasyncio

include $(BUILD_STATIC_LIBRARY)

@@ -362,6 +362,7 @@ LOCAL_SANITIZE := $(adb_target_sanitize)
LOCAL_STRIP_MODULE := keep_symbols
LOCAL_STATIC_LIBRARIES := \
    libadbd \
    libasyncio \
    libavb_user \
    libbase \
    libbootloader_message \
+1 −2
Original line number Diff line number Diff line
@@ -31,8 +31,7 @@
#include "usb.h"

constexpr size_t MAX_PAYLOAD_V1 = 4 * 1024;
constexpr size_t MAX_PAYLOAD_V2 = 256 * 1024;
constexpr size_t MAX_PAYLOAD = MAX_PAYLOAD_V2;
constexpr size_t MAX_PAYLOAD = 1024 * 1024;

constexpr size_t LINUX_MAX_SOCKET_SIZE = 4194304;

+105 −10
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>

@@ -49,16 +50,11 @@ using namespace std::chrono_literals;
#define MAX_PACKET_SIZE_HS 512
#define MAX_PACKET_SIZE_SS 1024

// Kernels before 3.3 have a 16KiB transfer limit  That limit was replaced
// with a 16MiB global limit in 3.3, but each URB submitted required a
// contiguous kernel allocation, so you would get ENOMEM if you tried to
// send something larger than the biggest available contiguous kernel
// memory region. Large contiguous allocations could be unreliable
// on a device kernel that has been running for a while fragmenting its
// memory so we start with a larger allocation, and shrink the amount if
// necessary.
#define USB_FFS_BULK_SIZE 16384

// Number of buffers needed to fit MAX_PAYLOAD, with an extra for ZLPs.
#define USB_FFS_NUM_BUFS ((MAX_PAYLOAD / USB_FFS_BULK_SIZE) + 1)

#define cpu_to_le16(x) htole16(x)
#define cpu_to_le32(x) htole32(x)

@@ -234,6 +230,26 @@ static const struct {
    },
};

static void aio_block_init(aio_block* aiob) {
    aiob->iocb.resize(USB_FFS_NUM_BUFS);
    aiob->iocbs.resize(USB_FFS_NUM_BUFS);
    aiob->events.resize(USB_FFS_NUM_BUFS);
    aiob->num_submitted = 0;
    for (unsigned i = 0; i < USB_FFS_NUM_BUFS; i++) {
        aiob->iocbs[i] = &aiob->iocb[i];
    }
}

static int getMaxPacketSize(int ffs_fd) {
    usb_endpoint_descriptor desc;
    if (ioctl(ffs_fd, FUNCTIONFS_ENDPOINT_DESC, reinterpret_cast<unsigned long>(&desc))) {
        D("[ could not get endpoint descriptor! (%d) ]", errno);
        return MAX_PACKET_SIZE_HS;
    } else {
        return desc.wMaxPacketSize;
    }
}

bool init_functionfs(struct usb_handle* h) {
    LOG(INFO) << "initializing functionfs";

@@ -301,6 +317,14 @@ bool init_functionfs(struct usb_handle* h) {
        goto err;
    }

    if (io_setup(USB_FFS_NUM_BUFS, &h->read_aiob.ctx) ||
        io_setup(USB_FFS_NUM_BUFS, &h->write_aiob.ctx)) {
        D("[ aio: got error on io_setup (%d) ]", errno);
    }

    h->read_aiob.fd = h->bulk_out;
    h->write_aiob.fd = h->bulk_in;

    h->max_rw = MAX_PAYLOAD;
    while (h->max_rw >= USB_FFS_BULK_SIZE && retries < ENDPOINT_ALLOC_RETRIES) {
        int ret_in = ioctl(h->bulk_in, FUNCTIONFS_ENDPOINT_ALLOC, static_cast<__u32>(h->max_rw));
@@ -410,6 +434,65 @@ static int usb_ffs_read(usb_handle* h, void* data, int len) {
    return 0;
}

static int usb_ffs_do_aio(usb_handle* h, const void* data, int len, bool read) {
    aio_block* aiob = read ? &h->read_aiob : &h->write_aiob;
    bool zero_packet = false;

    int num_bufs = len / USB_FFS_BULK_SIZE + (len % USB_FFS_BULK_SIZE == 0 ? 0 : 1);
    const char* cur_data = reinterpret_cast<const char*>(data);
    int packet_size = getMaxPacketSize(aiob->fd);

    if (posix_madvise(const_cast<void*>(data), len, POSIX_MADV_SEQUENTIAL | POSIX_MADV_WILLNEED) <
        0) {
        D("[ Failed to madvise: %d ]", errno);
    }

    for (int i = 0; i < num_bufs; i++) {
        int buf_len = std::min(len, USB_FFS_BULK_SIZE);
        io_prep(&aiob->iocb[i], aiob->fd, cur_data, buf_len, 0, read);

        len -= buf_len;
        cur_data += buf_len;

        if (len == 0 && buf_len % packet_size == 0 && read) {
            // adb does not expect the device to send a zero packet after data transfer,
            // but the host *does* send a zero packet for the device to read.
            zero_packet = true;
        }
    }
    if (zero_packet) {
        io_prep(&aiob->iocb[num_bufs], aiob->fd, reinterpret_cast<const void*>(cur_data),
                packet_size, 0, read);
        num_bufs += 1;
    }

    if (io_submit(aiob->ctx, num_bufs, aiob->iocbs.data()) < num_bufs) {
        D("[ aio: got error submitting %s (%d) ]", read ? "read" : "write", errno);
        return -1;
    }
    if (TEMP_FAILURE_RETRY(
            io_getevents(aiob->ctx, num_bufs, num_bufs, aiob->events.data(), nullptr)) < num_bufs) {
        D("[ aio: got error waiting %s (%d) ]", read ? "read" : "write", errno);
        return -1;
    }
    for (int i = 0; i < num_bufs; i++) {
        if (aiob->events[i].res < 0) {
            errno = aiob->events[i].res;
            D("[ aio: got error event on %s (%d) ]", read ? "read" : "write", errno);
            return -1;
        }
    }
    return 0;
}

static int usb_ffs_aio_read(usb_handle* h, void* data, int len) {
    return usb_ffs_do_aio(h, data, len, true);
}

static int usb_ffs_aio_write(usb_handle* h, const void* data, int len) {
    return usb_ffs_do_aio(h, data, len, false);
}

static void usb_ffs_kick(usb_handle* h) {
    int err;

@@ -438,6 +521,9 @@ static void usb_ffs_close(usb_handle* h) {
    h->kicked = false;
    adb_close(h->bulk_out);
    adb_close(h->bulk_in);
    io_destroy(h->read_aiob.ctx);
    io_destroy(h->write_aiob.ctx);

    // Notify usb_adb_open_thread to open a new connection.
    h->lock.lock();
    h->open_new_connection = true;
@@ -450,8 +536,17 @@ static void usb_ffs_init() {

    usb_handle* h = new usb_handle();

    if (android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false)) {
        // Devices on older kernels (< 3.18) will not have aio support for ffs
        // unless backported. Fall back on the non-aio functions instead.
        h->write = usb_ffs_write;
        h->read = usb_ffs_read;
    } else {
        h->write = usb_ffs_aio_write;
        h->read = usb_ffs_aio_read;
        aio_block_init(&h->read_aiob);
        aio_block_init(&h->write_aiob);
    }
    h->kick = usb_ffs_kick;
    h->close = usb_ffs_close;

+16 −1
Original line number Diff line number Diff line
@@ -20,6 +20,17 @@
#include <condition_variable>
#include <mutex>

#include <asyncio/AsyncIO.h>

struct aio_block {
    std::vector<struct iocb> iocb;
    std::vector<struct iocb*> iocbs;
    std::vector<struct io_event> events;
    aio_context_t ctx;
    int num_submitted;
    int fd;
};

struct usb_handle {
    usb_handle() : kicked(false) {
    }
@@ -39,7 +50,11 @@ struct usb_handle {
    int bulk_out = -1; /* "out" from the host's perspective => source for adbd */
    int bulk_in = -1;  /* "in" from the host's perspective => sink for adbd */

    // Access to these blocks is very not thread safe. Have one block for both the
    // read and write threads.
    struct aio_block read_aiob;
    struct aio_block write_aiob;

    int max_rw;
};
bool init_functionfs(struct usb_handle* h);
+1 −1
Original line number Diff line number Diff line
@@ -441,7 +441,7 @@ class SyncConnection {
        syncsendbuf sbuf;
        sbuf.id = ID_DATA;
        while (true) {
            int bytes_read = adb_read(lfd, sbuf.data, max);
            int bytes_read = adb_read(lfd, sbuf.data, max - sizeof(SyncRequest));
            if (bytes_read == -1) {
                Error("reading '%s' locally failed: %s", lpath, strerror(errno));
                adb_close(lfd);
Loading