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);