Merge "adb: use the actual wMaxPacketSize for usb endpoints."

am: c7988b1f68

Change-Id: Ia81c0e97857823759c7f71ecfca252259d41fee5
This commit is contained in:
Josh Gao 2017-05-04 00:16:41 +00:00 committed by android-build-merger
commit ff9d6425d4
8 changed files with 122 additions and 62 deletions

View file

@ -48,3 +48,9 @@ void usb_kick(usb_handle* h) {
should_use_libusb() ? libusb::usb_kick(reinterpret_cast<libusb::usb_handle*>(h)) should_use_libusb() ? libusb::usb_kick(reinterpret_cast<libusb::usb_handle*>(h))
: native::usb_kick(reinterpret_cast<native::usb_handle*>(h)); : native::usb_kick(reinterpret_cast<native::usb_handle*>(h));
} }
size_t usb_get_max_packet_size(usb_handle* h) {
return should_use_libusb()
? libusb::usb_get_max_packet_size(reinterpret_cast<libusb::usb_handle*>(h))
: native::usb_get_max_packet_size(reinterpret_cast<native::usb_handle*>(h));
}

View file

@ -91,7 +91,7 @@ namespace libusb {
struct usb_handle : public ::usb_handle { struct usb_handle : public ::usb_handle {
usb_handle(const std::string& device_address, const std::string& serial, usb_handle(const std::string& device_address, const std::string& serial,
unique_device_handle&& device_handle, uint8_t interface, uint8_t bulk_in, unique_device_handle&& device_handle, uint8_t interface, uint8_t bulk_in,
uint8_t bulk_out, size_t zero_mask) uint8_t bulk_out, size_t zero_mask, size_t max_packet_size)
: device_address(device_address), : device_address(device_address),
serial(serial), serial(serial),
closing(false), closing(false),
@ -100,7 +100,8 @@ struct usb_handle : public ::usb_handle {
write("write", zero_mask, true), write("write", zero_mask, true),
interface(interface), interface(interface),
bulk_in(bulk_in), bulk_in(bulk_in),
bulk_out(bulk_out) {} bulk_out(bulk_out),
max_packet_size(max_packet_size) {}
~usb_handle() { ~usb_handle() {
Close(); Close();
@ -143,6 +144,8 @@ struct usb_handle : public ::usb_handle {
uint8_t interface; uint8_t interface;
uint8_t bulk_in; uint8_t bulk_in;
uint8_t bulk_out; uint8_t bulk_out;
size_t max_packet_size;
}; };
static auto& usb_handles = *new std::unordered_map<std::string, std::unique_ptr<usb_handle>>(); static auto& usb_handles = *new std::unordered_map<std::string, std::unique_ptr<usb_handle>>();
@ -206,6 +209,7 @@ static void poll_for_devices() {
size_t interface_num; size_t interface_num;
uint16_t zero_mask; uint16_t zero_mask;
uint8_t bulk_in = 0, bulk_out = 0; uint8_t bulk_in = 0, bulk_out = 0;
size_t packet_size = 0;
bool found_adb = false; bool found_adb = false;
for (interface_num = 0; interface_num < config->bNumInterfaces; ++interface_num) { for (interface_num = 0; interface_num < config->bNumInterfaces; ++interface_num) {
@ -252,6 +256,14 @@ static void poll_for_devices() {
found_in = true; found_in = true;
bulk_in = endpoint_addr; bulk_in = endpoint_addr;
} }
size_t endpoint_packet_size = endpoint_desc.wMaxPacketSize;
CHECK(endpoint_packet_size != 0);
if (packet_size == 0) {
packet_size = endpoint_packet_size;
} else {
CHECK(packet_size == endpoint_packet_size);
}
} }
if (found_in && found_out) { if (found_in && found_out) {
@ -280,7 +292,7 @@ static void poll_for_devices() {
} }
libusb_device_handle* handle_raw; libusb_device_handle* handle_raw;
rc = libusb_open(list[i], &handle_raw); rc = libusb_open(device, &handle_raw);
if (rc != 0) { if (rc != 0) {
LOG(WARNING) << "failed to open usb device at " << device_address << ": " LOG(WARNING) << "failed to open usb device at " << device_address << ": "
<< libusb_error_name(rc); << libusb_error_name(rc);
@ -324,9 +336,9 @@ static void poll_for_devices() {
} }
} }
auto result = auto result = std::make_unique<usb_handle>(device_address, device_serial,
std::make_unique<usb_handle>(device_address, device_serial, std::move(handle), std::move(handle), interface_num, bulk_in,
interface_num, bulk_in, bulk_out, zero_mask); bulk_out, zero_mask, packet_size);
usb_handle* usb_handle_raw = result.get(); usb_handle* usb_handle_raw = result.get();
{ {
@ -507,4 +519,10 @@ int usb_close(usb_handle* h) {
void usb_kick(usb_handle* h) { void usb_kick(usb_handle* h) {
h->Close(); h->Close();
} }
size_t usb_get_max_packet_size(usb_handle* h) {
CHECK(h->max_packet_size != 0);
return h->max_packet_size;
}
} // namespace libusb } // namespace libusb

View file

@ -65,6 +65,7 @@ struct usb_handle : public ::usb_handle {
unsigned char ep_in; unsigned char ep_in;
unsigned char ep_out; unsigned char ep_out;
size_t max_packet_size;
unsigned zero_mask; unsigned zero_mask;
unsigned writeable = 1; unsigned writeable = 1;
@ -120,9 +121,9 @@ static inline bool contains_non_digit(const char* name) {
} }
static void find_usb_device(const std::string& base, static void find_usb_device(const std::string& base,
void (*register_device_callback) void (*register_device_callback)(const char*, const char*,
(const char*, const char*, unsigned char, unsigned char, int, int, unsigned)) unsigned char, unsigned char, int, int,
{ unsigned, size_t)) {
std::unique_ptr<DIR, int(*)(DIR*)> bus_dir(opendir(base.c_str()), closedir); std::unique_ptr<DIR, int(*)(DIR*)> bus_dir(opendir(base.c_str()), closedir);
if (!bus_dir) return; if (!bus_dir) return;
@ -144,6 +145,7 @@ static void find_usb_device(const std::string& base,
struct usb_interface_descriptor* interface; struct usb_interface_descriptor* interface;
struct usb_endpoint_descriptor *ep1, *ep2; struct usb_endpoint_descriptor *ep1, *ep2;
unsigned zero_mask = 0; unsigned zero_mask = 0;
size_t max_packet_size = 0;
unsigned vid, pid; unsigned vid, pid;
if (contains_non_digit(de->d_name)) continue; if (contains_non_digit(de->d_name)) continue;
@ -251,7 +253,8 @@ static void find_usb_device(const std::string& base,
continue; continue;
} }
/* aproto 01 needs 0 termination */ /* aproto 01 needs 0 termination */
if(interface->bInterfaceProtocol == 0x01) { if (interface->bInterfaceProtocol == 0x01) {
max_packet_size = ep1->wMaxPacketSize;
zero_mask = ep1->wMaxPacketSize - 1; zero_mask = ep1->wMaxPacketSize - 1;
} }
@ -281,9 +284,9 @@ static void find_usb_device(const std::string& base,
} }
} }
register_device_callback(dev_name.c_str(), devpath, register_device_callback(dev_name.c_str(), devpath, local_ep_in,
local_ep_in, local_ep_out, local_ep_out, interface->bInterfaceNumber,
interface->bInterfaceNumber, device->iSerialNumber, zero_mask); device->iSerialNumber, zero_mask, max_packet_size);
break; break;
} }
} else { } else {
@ -497,10 +500,13 @@ int usb_close(usb_handle* h) {
return 0; return 0;
} }
static void register_device(const char* dev_name, const char* dev_path, size_t usb_get_max_packet_size(usb_handle* h) {
unsigned char ep_in, unsigned char ep_out, return h->max_packet_size;
int interface, int serial_index, }
unsigned zero_mask) {
static void register_device(const char* dev_name, const char* dev_path, unsigned char ep_in,
unsigned char ep_out, int interface, int serial_index,
unsigned zero_mask, size_t max_packet_size) {
// Since Linux will not reassign the device ID (and dev_name) as long as the // Since Linux will not reassign the device ID (and dev_name) as long as the
// device is open, we can add to the list here once we open it and remove // device is open, we can add to the list here once we open it and remove
// from the list when we're finally closed and everything will work out // from the list when we're finally closed and everything will work out
@ -523,6 +529,7 @@ static void register_device(const char* dev_name, const char* dev_path,
usb->ep_in = ep_in; usb->ep_in = ep_in;
usb->ep_out = ep_out; usb->ep_out = ep_out;
usb->zero_mask = zero_mask; usb->zero_mask = zero_mask;
usb->max_packet_size = max_packet_size;
// Initialize mark so we don't get garbage collected after the device scan. // Initialize mark so we don't get garbage collected after the device scan.
usb->mark = true; usb->mark = true;

View file

@ -51,15 +51,21 @@ struct usb_handle
UInt8 bulkOut; UInt8 bulkOut;
IOUSBInterfaceInterface190** interface; IOUSBInterfaceInterface190** interface;
unsigned int zero_mask; unsigned int zero_mask;
size_t max_packet_size;
// For garbage collecting disconnected devices. // For garbage collecting disconnected devices.
bool mark; bool mark;
std::string devpath; std::string devpath;
std::atomic<bool> dead; std::atomic<bool> dead;
usb_handle() : bulkIn(0), bulkOut(0), interface(nullptr), usb_handle()
zero_mask(0), mark(false), dead(false) { : bulkIn(0),
} bulkOut(0),
interface(nullptr),
zero_mask(0),
max_packet_size(0),
mark(false),
dead(false) {}
}; };
static std::atomic<bool> usb_inited_flag; static std::atomic<bool> usb_inited_flag;
@ -390,6 +396,7 @@ CheckInterface(IOUSBInterfaceInterface190 **interface, UInt16 vendor, UInt16 pro
} }
handle->zero_mask = maxPacketSize - 1; handle->zero_mask = maxPacketSize - 1;
handle->max_packet_size = maxPacketSize;
} }
handle->interface = interface; handle->interface = interface;
@ -558,4 +565,9 @@ void usb_kick(usb_handle *handle) {
std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex); std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
usb_kick_locked(handle); usb_kick_locked(handle);
} }
size_t usb_get_max_packet_size(usb_handle* handle) {
return handle->max_packet_size;
}
} // namespace native } // namespace native

View file

@ -65,6 +65,9 @@ struct usb_handle {
/// Interface name /// Interface name
wchar_t* interface_name; wchar_t* interface_name;
/// Maximum packet size.
unsigned max_packet_size;
/// Mask for determining when to use zero length packets /// Mask for determining when to use zero length packets
unsigned zero_mask; unsigned zero_mask;
}; };
@ -522,6 +525,10 @@ int usb_close(usb_handle* handle) {
return 0; return 0;
} }
size_t usb_get_max_packet_size(usb_handle* handle) {
return handle->max_packet_size;
}
int recognized_device(usb_handle* handle) { int recognized_device(usb_handle* handle) {
if (NULL == handle) if (NULL == handle)
return 0; return 0;
@ -557,6 +564,7 @@ int recognized_device(usb_handle* handle) {
AdbEndpointInformation endpoint_info; AdbEndpointInformation endpoint_info;
// assuming zero is a valid bulk endpoint ID // assuming zero is a valid bulk endpoint ID
if (AdbGetEndpointInformation(handle->adb_interface, 0, &endpoint_info)) { if (AdbGetEndpointInformation(handle->adb_interface, 0, &endpoint_info)) {
handle->max_packet_size = endpoint_info.max_packet_size;
handle->zero_mask = endpoint_info.max_packet_size - 1; handle->zero_mask = endpoint_info.max_packet_size - 1;
D("device zero_mask: 0x%x", handle->zero_mask); D("device zero_mask: 0x%x", handle->zero_mask);
} else { } else {

View file

@ -1259,6 +1259,26 @@ class DeviceOfflineTest(DeviceTest):
self.assertEqual(self._get_device_state(serialno), 'device') self.assertEqual(self._get_device_state(serialno), 'device')
def test_packet_size_regression(self):
"""Test for http://b/37783561
Receiving packets of a length divisible by 512 but not 1024 resulted in
the adb client waiting indefinitely for more input.
"""
# The values that trigger things are 507 (512 - 5 bytes from shell protocol) + 1024*n
# Probe some surrounding values as well, for the hell of it.
for length in [506, 507, 508, 1018, 1019, 1020, 1530, 1531, 1532]:
cmd = ['dd', 'if=/dev/zero', 'bs={}'.format(length), 'count=1', '2>/dev/null;'
'echo', 'foo']
rc, stdout, _ = self.device.shell_nocheck(cmd)
self.assertEqual(0, rc)
# Output should be '\0' * length, followed by "foo\n"
self.assertEqual(length, len(stdout) - 4)
self.assertEqual(stdout, "\0" * length + "foo\n")
def main(): def main():
random.seed(0) random.seed(0)
if len(adb.get_devices()) > 0: if len(adb.get_devices()) > 0:

View file

@ -27,57 +27,43 @@
#if ADB_HOST #if ADB_HOST
static constexpr size_t MAX_USB_BULK_PACKET_SIZE = 1024u; // Call usb_read using a buffer having a multiple of usb_get_max_packet_size() bytes
// Call usb_read using a buffer having a multiple of MAX_USB_BULK_PACKET_SIZE bytes
// to avoid overflow. See http://libusb.sourceforge.net/api-1.0/packetoverflow.html. // to avoid overflow. See http://libusb.sourceforge.net/api-1.0/packetoverflow.html.
static int UsbReadMessage(usb_handle* h, amessage* msg) { static int UsbReadMessage(usb_handle* h, amessage* msg) {
D("UsbReadMessage"); D("UsbReadMessage");
char buffer[MAX_USB_BULK_PACKET_SIZE];
int n = usb_read(h, buffer, sizeof(buffer)); size_t usb_packet_size = usb_get_max_packet_size(h);
if (n == sizeof(*msg)) { CHECK(usb_packet_size >= sizeof(*msg));
memcpy(msg, buffer, sizeof(*msg)); CHECK(usb_packet_size < 4096);
char buffer[4096];
int n = usb_read(h, buffer, usb_packet_size);
if (n != sizeof(*msg)) {
D("usb_read returned unexpected length %d (expected %zu)", n, sizeof(*msg));
return -1;
} }
memcpy(msg, buffer, sizeof(*msg));
return n; return n;
} }
// Call usb_read using a buffer having a multiple of MAX_USB_BULK_PACKET_SIZE bytes // Call usb_read using a buffer having a multiple of usb_get_max_packet_size() bytes
// to avoid overflow. See http://libusb.sourceforge.net/api-1.0/packetoverflow.html. // to avoid overflow. See http://libusb.sourceforge.net/api-1.0/packetoverflow.html.
static int UsbReadPayload(usb_handle* h, apacket* p) { static int UsbReadPayload(usb_handle* h, apacket* p) {
D("UsbReadPayload"); D("UsbReadPayload(%d)", p->msg.data_length);
size_t need_size = p->msg.data_length;
size_t data_pos = 0u; size_t usb_packet_size = usb_get_max_packet_size(h);
while (need_size > 0u) { CHECK(sizeof(p->data) % usb_packet_size == 0);
int n = 0;
if (data_pos + MAX_USB_BULK_PACKET_SIZE <= sizeof(p->data)) { // Round the data length up to the nearest packet size boundary.
// Read directly to p->data. // The device won't send a zero packet for packet size aligned payloads,
size_t rem_size = need_size % MAX_USB_BULK_PACKET_SIZE; // so don't read any more packets than needed.
size_t direct_read_size = need_size - rem_size; size_t len = p->msg.data_length;
if (rem_size && size_t rem_size = len % usb_packet_size;
data_pos + direct_read_size + MAX_USB_BULK_PACKET_SIZE <= sizeof(p->data)) { if (rem_size) {
direct_read_size += MAX_USB_BULK_PACKET_SIZE; len += usb_packet_size - rem_size;
}
n = usb_read(h, &p->data[data_pos], direct_read_size);
if (n < 0) {
D("usb_read(size %zu) failed", direct_read_size);
return n;
}
} else {
// Read indirectly using a buffer.
char buffer[MAX_USB_BULK_PACKET_SIZE];
n = usb_read(h, buffer, sizeof(buffer));
if (n < 0) {
D("usb_read(size %zu) failed", sizeof(buffer));
return -1;
}
size_t copy_size = std::min(static_cast<size_t>(n), need_size);
D("usb read %d bytes, need %zu bytes, copy %zu bytes", n, need_size, copy_size);
memcpy(&p->data[data_pos], buffer, copy_size);
}
data_pos += n;
need_size -= std::min(static_cast<size_t>(n), need_size);
} }
return static_cast<int>(data_pos); CHECK(len <= sizeof(p->data));
return usb_read(h, &p->data, len);
} }
static int remote_read(apacket* p, atransport* t) { static int remote_read(apacket* p, atransport* t) {

View file

@ -16,6 +16,8 @@
#pragma once #pragma once
#include <sys/types.h>
// USB host/client interface. // USB host/client interface.
#define ADB_USB_INTERFACE(handle_ref_type) \ #define ADB_USB_INTERFACE(handle_ref_type) \
@ -23,7 +25,8 @@
int usb_write(handle_ref_type h, const void* data, int len); \ int usb_write(handle_ref_type h, const void* data, int len); \
int usb_read(handle_ref_type h, void* data, int len); \ int usb_read(handle_ref_type h, void* data, int len); \
int usb_close(handle_ref_type h); \ int usb_close(handle_ref_type h); \
void usb_kick(handle_ref_type h) void usb_kick(handle_ref_type h); \
size_t usb_get_max_packet_size(handle_ref_type)
#if defined(_WIN32) || !ADB_HOST #if defined(_WIN32) || !ADB_HOST
// Windows and the daemon have a single implementation. // Windows and the daemon have a single implementation.