Fix file transfer corner cases.
Fix zero packet read/write in corner cases
with initial read/writes. This affects transfers
of 16372 bytes to the device and transfers of
1012 bytes (or packet size - 12) from the device.
Test: Transfer various length files
Bug: 37175601
Change-Id: Ic1281e8757d1a33d78c66d2c57319b5ee38d6a46
diff --git a/media/mtp/IMtpHandle.h b/media/mtp/IMtpHandle.h
index 9185255..0557596 100644
--- a/media/mtp/IMtpHandle.h
+++ b/media/mtp/IMtpHandle.h
@@ -27,7 +27,7 @@
virtual int write(const void *data, int len) = 0;
// Return 0 if send/receive is successful, or -1 and errno is set
- virtual int receiveFile(mtp_file_range mfr) = 0;
+ virtual int receiveFile(mtp_file_range mfr, bool zero_packet) = 0;
virtual int sendFile(mtp_file_range mfr) = 0;
virtual int sendEvent(mtp_event me) = 0;
diff --git a/media/mtp/MtpDevHandle.cpp b/media/mtp/MtpDevHandle.cpp
index afc0525..9aa0aec 100644
--- a/media/mtp/MtpDevHandle.cpp
+++ b/media/mtp/MtpDevHandle.cpp
@@ -45,7 +45,7 @@
int read(void *data, int len);
int write(const void *data, int len);
- int receiveFile(mtp_file_range mfr);
+ int receiveFile(mtp_file_range mfr, bool);
int sendFile(mtp_file_range mfr);
int sendEvent(mtp_event me);
@@ -68,7 +68,7 @@
return ::write(mFd, data, len);
}
-int MtpDevHandle::receiveFile(mtp_file_range mfr) {
+int MtpDevHandle::receiveFile(mtp_file_range mfr, bool) {
return ioctl(mFd, MTP_RECEIVE_FILE, reinterpret_cast<unsigned long>(&mfr));
}
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index c78002c..c50af2f 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -516,7 +516,7 @@
}
/* Read from USB and write to a local file. */
-int MtpFfsHandle::receiveFile(mtp_file_range mfr) {
+int MtpFfsHandle::receiveFile(mtp_file_range mfr, bool zero_packet) {
// When receiving files, the incoming length is given in 32 bits.
// A >4G file is given as 0xFFFFFFFF
uint32_t file_length = mfr.length;
@@ -538,7 +538,7 @@
aio.aio_fildes = mfr.fd;
aio.aio_buf = nullptr;
struct aiocb *aiol[] = {&aio};
- int ret;
+ int ret = -1;
size_t length;
bool read = false;
bool write = false;
@@ -590,11 +590,6 @@
} 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;
@@ -610,6 +605,11 @@
read = false;
}
}
+ if (ret % packet_size == 0 || zero_packet) {
+ if (TEMP_FAILURE_RETRY(::read(mBulkOut, data, packet_size)) != 0) {
+ return -1;
+ }
+ }
return 0;
}
@@ -660,10 +660,9 @@
sizeof(mtp_data_header), init_read_len, offset))
!= init_read_len) return -1;
if (writeHandle(mBulkIn, data, sizeof(mtp_data_header) + init_read_len) == -1) return -1;
- if (file_length == static_cast<unsigned>(init_read_len)) return 0;
file_length -= init_read_len;
offset += init_read_len;
- ret = 0;
+ ret = init_read_len + sizeof(mtp_data_header);
// Break down the file into pieces that fit in buffers
while(file_length > 0) {
diff --git a/media/mtp/MtpFfsHandle.h b/media/mtp/MtpFfsHandle.h
index 7491a1b..98669ff 100644
--- a/media/mtp/MtpFfsHandle.h
+++ b/media/mtp/MtpFfsHandle.h
@@ -55,7 +55,7 @@
int read(void *data, int len);
int write(const void *data, int len);
- int receiveFile(mtp_file_range mfr);
+ int receiveFile(mtp_file_range mfr, bool zero_packet);
int sendFile(mtp_file_range mfr);
int sendEvent(mtp_event me);
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 88dabff..5c33265 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -1052,23 +1052,22 @@
ALOGE("failed to write initial data");
result = MTP_RESPONSE_GENERAL_ERROR;
} else {
- if (mSendObjectFileSize - initialData > 0) {
- mfr.offset = initialData;
- if (mSendObjectFileSize == 0xFFFFFFFF) {
- // tell driver to read until it receives a short packet
- mfr.length = 0xFFFFFFFF;
- } else {
- mfr.length = mSendObjectFileSize - initialData;
- }
+ mfr.offset = initialData;
+ if (mSendObjectFileSize == 0xFFFFFFFF) {
+ // tell driver to read until it receives a short packet
+ mfr.length = 0xFFFFFFFF;
+ } else {
+ mfr.length = mSendObjectFileSize - initialData;
+ }
- mfr.command = 0;
- mfr.transaction_id = 0;
+ mfr.command = 0;
+ mfr.transaction_id = 0;
- // transfer the file
- ret = sHandle->receiveFile(mfr);
- if ((ret < 0) && (errno == ECANCELED)) {
- isCanceled = true;
- }
+ // transfer the file
+ ret = sHandle->receiveFile(mfr, mfr.length == 0 &&
+ initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
+ if ((ret < 0) && (errno == ECANCELED)) {
+ isCanceled = true;
}
}
struct stat sstat;
@@ -1256,19 +1255,18 @@
if (ret < 0) {
ALOGE("failed to write initial data");
} else {
- if (length > 0) {
- mtp_file_range mfr;
- mfr.fd = edit->mFD;
- mfr.offset = offset;
- mfr.length = length;
- mfr.command = 0;
- mfr.transaction_id = 0;
+ mtp_file_range mfr;
+ mfr.fd = edit->mFD;
+ mfr.offset = offset;
+ mfr.length = length;
+ mfr.command = 0;
+ mfr.transaction_id = 0;
- // transfer the file
- ret = sHandle->receiveFile(mfr);
- if ((ret < 0) && (errno == ECANCELED)) {
- isCanceled = true;
- }
+ // transfer the file
+ ret = sHandle->receiveFile(mfr, mfr.length == 0 &&
+ initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
+ if ((ret < 0) && (errno == ECANCELED)) {
+ isCanceled = true;
}
}
if (ret < 0) {
diff --git a/media/mtp/tests/MtpFfsHandle_test.cpp b/media/mtp/tests/MtpFfsHandle_test.cpp
index e575148..554f867 100644
--- a/media/mtp/tests/MtpFfsHandle_test.cpp
+++ b/media/mtp/tests/MtpFfsHandle_test.cpp
@@ -116,7 +116,7 @@
ss << dummyDataStr;
EXPECT_EQ(write(bulk_out, ss.str().c_str(), size), size);
- EXPECT_EQ(handle->receiveFile(mfr), 0);
+ EXPECT_EQ(handle->receiveFile(mfr, false), 0);
EXPECT_EQ(read(dummy_file.fd, buf, size), size);
@@ -136,7 +136,7 @@
ss << dummyDataStr;
EXPECT_EQ(write(bulk_out, ss.str().c_str(), size), size);
- EXPECT_EQ(handle->receiveFile(mfr), 0);
+ EXPECT_EQ(handle->receiveFile(mfr, false), 0);
EXPECT_EQ(read(dummy_file.fd, buf, size), size);