Merge changes from topic 'adb_perf' am: 42aa9a1415 am: 14e71a4af2
am: 3b36116ac7

Change-Id: I25e052d39b54b575efec8f9db198410ca3f17968
diff --git a/adb/adb.h b/adb/adb.h
index 6a38f18..a30e297 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -34,6 +34,8 @@
 constexpr size_t MAX_PAYLOAD_V2 = 256 * 1024;
 constexpr size_t MAX_PAYLOAD = MAX_PAYLOAD_V2;
 
+constexpr size_t LINUX_MAX_SOCKET_SIZE = 4194304;
+
 #define A_SYNC 0x434e5953
 #define A_CNXN 0x4e584e43
 #define A_OPEN 0x4e45504f
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index a35c210..6d77f4b 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -49,16 +49,23 @@
 #define MAX_PACKET_SIZE_HS 512
 #define MAX_PACKET_SIZE_SS 1024
 
-// Writes larger than 16k fail on some devices (seed with 3.10.49-g209ea2f in particular).
-#define USB_FFS_MAX_WRITE 16384
-
-// The kernel allocates a contiguous buffer for reads, which can fail for large ones due to
-// fragmentation. 16k chosen arbitrarily to match the write limit.
-#define USB_FFS_MAX_READ 16384
+// 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
 
 #define cpu_to_le16(x) htole16(x)
 #define cpu_to_le32(x) htole32(x)
 
+#define FUNCTIONFS_ENDPOINT_ALLOC       _IOR('g', 231, __u32)
+
+static constexpr size_t ENDPOINT_ALLOC_RETRIES = 10;
+
 static int dummy_fd = -1;
 
 struct func_desc {
@@ -173,6 +180,7 @@
     .source_comp = {
         .bLength = sizeof(ss_descriptors.source_comp),
         .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+        .bMaxBurst = 4,
     },
     .sink = {
         .bLength = sizeof(ss_descriptors.sink),
@@ -184,6 +192,7 @@
     .sink_comp = {
         .bLength = sizeof(ss_descriptors.sink_comp),
         .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+        .bMaxBurst = 4,
     },
 };
 
@@ -229,6 +238,7 @@
     ssize_t ret;
     struct desc_v1 v1_descriptor;
     struct desc_v2 v2_descriptor;
+    size_t retries = 0;
 
     v2_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
     v2_descriptor.header.length = cpu_to_le32(sizeof(v2_descriptor));
@@ -287,6 +297,29 @@
         goto err;
     }
 
+    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));
+        int errno_in = errno;
+        int ret_out = ioctl(h->bulk_out, FUNCTIONFS_ENDPOINT_ALLOC, static_cast<__u32>(h->max_rw));
+        int errno_out = errno;
+
+        if (ret_in || ret_out) {
+            if (errno_in == ENODEV || errno_out == ENODEV) {
+                std::this_thread::sleep_for(100ms);
+                retries += 1;
+                continue;
+            }
+            h->max_rw /= 2;
+        } else {
+            return true;
+        }
+    }
+
+    D("[ adb: cannot call endpoint alloc: errno=%d ]", errno);
+    // Kernel pre-allocation could have failed for recoverable reasons.
+    // Continue running with a safe max rw size.
+    h->max_rw *= 2;
     return true;
 
 err:
@@ -340,7 +373,7 @@
 
     const char* buf = static_cast<const char*>(data);
     while (len > 0) {
-        int write_len = std::min(USB_FFS_MAX_WRITE, len);
+        int write_len = std::min(h->max_rw, len);
         int n = adb_write(h->bulk_in, buf, write_len);
         if (n < 0) {
             D("ERROR: fd = %d, n = %d: %s", h->bulk_in, n, strerror(errno));
@@ -359,7 +392,7 @@
 
     char* buf = static_cast<char*>(data);
     while (len > 0) {
-        int read_len = std::min(USB_FFS_MAX_READ, len);
+        int read_len = std::min(h->max_rw, len);
         int n = adb_read(h->bulk_out, buf, read_len);
         if (n < 0) {
             D("ERROR: fd = %d, n = %d: %s", h->bulk_out, n, strerror(errno));
diff --git a/adb/daemon/usb.h b/adb/daemon/usb.h
index 1d85405..55b5995 100644
--- a/adb/daemon/usb.h
+++ b/adb/daemon/usb.h
@@ -20,13 +20,6 @@
 #include <condition_variable>
 #include <mutex>
 
-// Writes larger than 16k fail on some devices (seed with 3.10.49-g209ea2f in particular).
-#define USB_FFS_MAX_WRITE 16384
-
-// The kernel allocates a contiguous buffer for reads, which can fail for large ones due to
-// fragmentation. 16k chosen arbitrarily to match the write limit.
-#define USB_FFS_MAX_READ 16384
-
 struct usb_handle {
     usb_handle() : kicked(false) {
     }
@@ -45,6 +38,8 @@
     int control = -1;
     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 */
+
+    int max_rw;
 };
 
 bool init_functionfs(struct usb_handle* h);
diff --git a/adb/services.cpp b/adb/services.cpp
index df1b134..a48d855 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -242,6 +242,15 @@
     }
     D("socketpair: (%d,%d)", s[0], s[1]);
 
+#if !ADB_HOST
+    if (func == &file_sync_service) {
+        // Set file sync service socket to maximum size
+        int max_buf = LINUX_MAX_SOCKET_SIZE;
+        adb_setsockopt(s[0], SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
+        adb_setsockopt(s[1], SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
+    }
+#endif // !ADB_HOST
+
     stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
     if (sti == nullptr) {
         fatal("cannot allocate stinfo");