Fix zero length packet handling
Ensure that a zero length packet is properly sent
/ received when handling data that is a multiple of the
endpoint size.
This fixes an issue where files whose size is a multiple
of the endpoint size would hang during transfer.
Bug: 37175601
Test: check successful file transfer.
Change-Id: Iaf3cea18422234d65b59f5961ef9fb3f3ee2049a
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 565a2fe..c78002c 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -520,7 +520,16 @@
// When receiving files, the incoming length is given in 32 bits.
// A >4G file is given as 0xFFFFFFFF
uint32_t file_length = mfr.length;
- uint64_t offset = lseek(mfr.fd, 0, SEEK_CUR);
+ uint64_t offset = mfr.offset;
+ struct usb_endpoint_descriptor mBulkOut_desc;
+ int packet_size;
+
+ if (ioctl(mBulkOut, FUNCTIONFS_ENDPOINT_DESC, reinterpret_cast<unsigned long>(&mBulkOut_desc))) {
+ PLOG(ERROR) << "Could not get FFS bulk-out descriptor";
+ packet_size = MAX_PACKET_SIZE_HS;
+ } else {
+ packet_size = mBulkOut_desc.wMaxPacketSize;
+ }
char *data = mBuffer1.data();
char *data2 = mBuffer2.data();
@@ -573,21 +582,26 @@
}
if (read) {
- // Enqueue a new write request
- aio.aio_buf = data;
- aio.aio_sink = mfr.fd;
- aio.aio_offset = offset;
- aio.aio_nbytes = ret;
- aio_write(&aio);
-
if (file_length == MAX_MTP_FILE_SIZE) {
// For larger files, receive until a short packet is received.
if (static_cast<size_t>(ret) < length) {
file_length = 0;
}
} else {
+ // Receive an empty packet if size is a multiple of the endpoint size.
file_length -= ret;
+ if (file_length == 0 && ret % packet_size == 0) {
+ if (TEMP_FAILURE_RETRY(::read(mBulkOut, data, packet_size)) != 0) {
+ return -1;
+ }
+ }
}
+ // Enqueue a new write request
+ aio.aio_buf = data;
+ aio.aio_sink = mfr.fd;
+ aio.aio_offset = offset;
+ aio.aio_nbytes = ret;
+ aio_write(&aio);
offset += ret;
std::swap(data, data2);
@@ -695,9 +709,11 @@
}
}
- if (given_length == MAX_MTP_FILE_SIZE && ret % packet_size == 0) {
+ if (ret % packet_size == 0) {
// If the last packet wasn't short, send a final empty packet
- if (writeHandle(mBulkIn, data, 0) == -1) return -1;
+ if (TEMP_FAILURE_RETRY(::write(mBulkIn, data, 0)) != 0) {
+ return -1;
+ }
}
return 0;