Don't send short URB packet when sending MtpDataPacket.

When sending a MtpDataPacket to a MTP device, the kernel driver splits
it into multiple URB packets so that the URB packet size does not exceed
the buffer size at the MTP device.

Previously MtpDataPacket sends its header first, then sends the
payload. It means the first URB packet only contains the header of
MtpDataPacket and the URB packet size is smaller than the maximum URB
packet size (short packet). Some MTP devices regard the short packet as
the end of the sequencail URB packets, thus the devices do not accept
the following URB packets that contain the payload.

The MTP spec says if the responder (MTP device) sends the data in a way
where the first pacekt contains only the header, the initiator (MTP
host) must send data in the same way. Otherwise the initiator must not
send a short packet in the sequencial URB packets.

The CL fixes the MTP host implementation so that it remembers how the
MTP device sends data, and uses the same way when sending data
from the host.

Bug: 31165557
Test: Manually invokes MtpDevice#sendObject
Change-Id: Ic76eb4241ed74957414aef2990be08cd77a9f5a9
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 0381edf..0e9bc34 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -16,17 +16,38 @@
 
 #define LOG_TAG "MtpDataPacket"
 
+#include "MtpDataPacket.h"
+
+#include <algorithm>
+#include <fcntl.h>
 #include <stdio.h>
 #include <sys/types.h>
-#include <fcntl.h>
-
 #include <usbhost/usbhost.h>
-
-#include "MtpDataPacket.h"
 #include "MtpStringBuffer.h"
 
 namespace android {
 
+namespace {
+// Reads the exact |count| bytes from |fd| to |buf|.
+// Returns |count| if it succeed to read the bytes. Otherwise returns -1. If it reaches EOF, the
+// function regards it as an error.
+ssize_t readExactBytes(int fd, void* buf, size_t count) {
+    if (count > SSIZE_MAX) {
+        return -1;
+    }
+    size_t read_count = 0;
+    while (read_count < count) {
+        int result = read(fd, static_cast<int8_t*>(buf) + read_count, count - read_count);
+        // Assume that EOF is error.
+        if (result <= 0) {
+            return -1;
+        }
+        read_count += result;
+    }
+    return read_count == count ? count : -1;
+}
+}  // namespace
+
 MtpDataPacket::MtpDataPacket()
     :   MtpPacket(MTP_BUFFER_SIZE),   // MAX_USBFS_BUFFER_SIZE
         mOffset(MTP_CONTAINER_HEADER_SIZE)
@@ -511,29 +532,104 @@
     return length;
 }
 
-int MtpDataPacket::writeDataHeader(struct usb_request *request, uint32_t length) {
-    MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length);
-    MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
-    request->buffer = mBuffer;
-    request->buffer_length = MTP_CONTAINER_HEADER_SIZE;
-    int ret = transfer(request);
-    return (ret < 0 ? ret : 0);
-}
+int MtpDataPacket::write(struct usb_request *request, UrbPacketDivisionMode divisionMode) {
+    if (mPacketSize < MTP_CONTAINER_HEADER_SIZE || mPacketSize > MTP_BUFFER_SIZE) {
+        ALOGE("Illegal packet size.");
+        return -1;
+    }
 
-int MtpDataPacket::write(struct usb_request *request) {
     MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
     MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
-    request->buffer = mBuffer;
-    request->buffer_length = mPacketSize;
-    int ret = transfer(request);
-    return (ret < 0 ? ret : 0);
+
+    size_t processedBytes = 0;
+    while (processedBytes < mPacketSize) {
+        const size_t write_size =
+                processedBytes == 0 && divisionMode == FIRST_PACKET_ONLY_HEADER ?
+                        MTP_CONTAINER_HEADER_SIZE : mPacketSize - processedBytes;
+        request->buffer = mBuffer + processedBytes;
+        request->buffer_length = write_size;
+        const int result = transfer(request);
+        if (result < 0) {
+            ALOGE("Failed to write bytes to the device.");
+            return -1;
+        }
+        processedBytes += result;
+    }
+
+    return processedBytes == mPacketSize ? processedBytes : -1;
 }
 
-int MtpDataPacket::write(struct usb_request *request, void* buffer, uint32_t length) {
-    request->buffer = buffer;
-    request->buffer_length = length;
-    int ret = transfer(request);
-    return (ret < 0 ? ret : 0);
+int MtpDataPacket::write(struct usb_request *request,
+                         UrbPacketDivisionMode divisionMode,
+                         int fd,
+                         size_t payloadSize) {
+    // Obtain the greatest multiple of minimum packet size that is not greater than
+    // MTP_BUFFER_SIZE.
+    if (request->max_packet_size <= 0) {
+        ALOGE("Cannot determine bulk transfer size due to illegal max packet size %d.",
+              request->max_packet_size);
+        return -1;
+    }
+    const size_t maxBulkTransferSize =
+            MTP_BUFFER_SIZE - (MTP_BUFFER_SIZE % request->max_packet_size);
+    const size_t containerLength = payloadSize + MTP_CONTAINER_HEADER_SIZE;
+    size_t processedBytes = 0;
+    bool readError = false;
+
+    // Bind the packet with given request.
+    request->buffer = mBuffer;
+    allocate(maxBulkTransferSize);
+
+    while (processedBytes < containerLength) {
+        size_t bulkTransferSize = 0;
+
+        // prepare header.
+        const bool headerSent = processedBytes != 0;
+        if (!headerSent) {
+            MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, containerLength);
+            MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
+            bulkTransferSize += MTP_CONTAINER_HEADER_SIZE;
+        }
+
+        // Prepare payload.
+        if (headerSent || divisionMode == FIRST_PACKET_HAS_PAYLOAD) {
+            const size_t processedPayloadBytes =
+                    headerSent ? processedBytes - MTP_CONTAINER_HEADER_SIZE : 0;
+            const size_t maxRead = payloadSize - processedPayloadBytes;
+            const size_t maxWrite = maxBulkTransferSize - bulkTransferSize;
+            const size_t bulkTransferPayloadSize = std::min(maxRead, maxWrite);
+            // prepare payload.
+            if (!readError) {
+                const ssize_t result = readExactBytes(
+                        fd,
+                        mBuffer + bulkTransferSize,
+                        bulkTransferPayloadSize);
+                if (result < 0) {
+                    ALOGE("Found an error while reading data from FD. Send 0 data instead.");
+                    readError = true;
+                }
+            }
+            if (readError) {
+                memset(mBuffer + bulkTransferSize, 0, bulkTransferPayloadSize);
+            }
+            bulkTransferSize += bulkTransferPayloadSize;
+        }
+
+        // Bulk transfer.
+        mPacketSize = bulkTransferSize;
+        request->buffer_length = bulkTransferSize;
+        const int result = transfer(request);
+        if (result != static_cast<ssize_t>(bulkTransferSize)) {
+            // Cannot recover writing error.
+            ALOGE("Found an error while write data to MtpDevice.");
+            return -1;
+        }
+
+        // Update variables.
+        processedBytes += bulkTransferSize;
+    }
+
+    return readError ? -1 : processedBytes;
 }
 
 #endif // MTP_HOST