Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b52063b authored by Daichi Hirono's avatar Daichi Hirono Committed by android-build-merger
Browse files

Don't send short URB packet when sending MtpDataPacket.

am: d95d34d4

Change-Id: Iafc27d47bfd1fe9bd17f6dbf0920572eb66944e9
parents 8e7be6ff d95d34d4
Loading
Loading
Loading
Loading
+118 −22
Original line number Diff line number Diff line
@@ -16,18 +16,39 @@

#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"
#include "IMtpHandle.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)
@@ -512,29 +533,104 @@ int MtpDataPacket::readDataHeader(struct usb_request *request) {
    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);

    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,
                         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;
    request->buffer_length = mPacketSize;
    int ret = transfer(request);
    return (ret < 0 ? ret : 0);
    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;
        }

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);
        // Update variables.
        processedBytes += bulkTransferSize;
    }

    return readError ? -1 : processedBytes;
}

#endif // MTP_HOST
+9 −4
Original line number Diff line number Diff line
@@ -94,7 +94,6 @@ public:
    inline void         putEmptyString() { putUInt8(0); }
    inline void         putEmptyArray() { putUInt32(0); }


#ifdef MTP_DEVICE
    // fill our buffer with data from the given usb handle
    int                 read(IMtpHandle *h);
@@ -111,9 +110,15 @@ public:
    int                 readDataWait(struct usb_device *device);
    int                 readDataHeader(struct usb_request *ep);

    int                 writeDataHeader(struct usb_request *ep, uint32_t length);
    int                 write(struct usb_request *ep);
    int                 write(struct usb_request *ep, void* buffer, uint32_t length);
    // Write a whole data packet with payload to the end point given by a request. |divisionMode|
    // specifies whether to divide header and payload. See |UrbPacketDivisionMode| for meanings of
    // each value. Return the number of bytes (including header size) sent to the device on success.
    // Otherwise -1.
    int                 write(struct usb_request *request, UrbPacketDivisionMode divisionMode);
    // Similar to previous write method but it reads the payload from |fd|. If |size| is larger than
    // MTP_BUFFER_SIZE, the data will be sent by multiple bulk transfer requests.
    int                 write(struct usb_request *request, UrbPacketDivisionMode divisionMode,
                              int fd, size_t size);
#endif

    inline bool         hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; }
+19 −31
Original line number Diff line number Diff line
@@ -222,7 +222,8 @@ MtpDevice::MtpDevice(struct usb_device* device, int interface,
        mProcessingEvent(false),
        mCurrentEventHandle(0),
        mLastSendObjectInfoTransactionID(0),
        mLastSendObjectInfoObjectHandle(0)
        mLastSendObjectInfoObjectHandle(0),
        mPacketDivisionMode(FIRST_PACKET_HAS_PAYLOAD)
{
    mRequestIn1 = usb_request_new(device, ep_in);
    mRequestIn2 = usb_request_new(device, ep_in);
@@ -512,30 +513,15 @@ bool MtpDevice::sendObject(MtpObjectHandle handle, int size, int srcFD) {
        return false;
    }

    int remaining = size;
    mRequest.reset();
    bool error = false;
    if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
        // send data header
        writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);

        // USB writes greater than 16K don't work
        char buffer[MTP_BUFFER_SIZE];
        while (remaining > 0) {
            int count = read(srcFD, buffer, sizeof(buffer));
            if (count > 0) {
                if (mData.write(mRequestOut, buffer, count) < 0) {
                    error = true;
                }
                // FIXME check error
                remaining -= count;
            } else {
                break;
            }
        }
        mData.setOperationCode(mRequest.getOperationCode());
        mData.setTransactionID(mRequest.getTransactionID());
        const int writeResult = mData.write(mRequestOut, mPacketDivisionMode, srcFD, size);
        const MtpResponseCode ret = readResponse();
        return ret == MTP_RESPONSE_OK && writeResult > 0;
    }
    MtpResponseCode ret = readResponse();
    return (remaining == 0 && ret == MTP_RESPONSE_OK && !error);
    return false;
}

bool MtpDevice::deleteObject(MtpObjectHandle handle) {
@@ -707,8 +693,8 @@ bool MtpDevice::readData(ReadObjectCallback callback,
        return false;
    }

    // If object size 0 byte, the remote device can reply response packet
    // without sending any data packets.
    // If object size 0 byte, the remote device may reply a response packet without sending any data
    // packets.
    if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
        mResponse.copyFrom(mData);
        return mResponse.getResponseCode() == MTP_RESPONSE_OK;
@@ -731,6 +717,14 @@ bool MtpDevice::readData(ReadObjectCallback callback,
    {
        int initialDataLength = 0;
        void* const initialData = mData.getData(&initialDataLength);
        if (fullLength > MTP_CONTAINER_HEADER_SIZE && initialDataLength == 0) {
            // According to the MTP spec, the responder (MTP device) can choose two ways of sending
            // data. a) The first packet contains the head and as much of the payload as possible
            // b) The first packet contains only the header. The initiator (MTP host) needs
            // to remember which way the responder used, and send upcoming data in the same way.
            ALOGD("Found short packet that contains only a header.");
            mPacketDivisionMode = FIRST_PACKET_ONLY_HEADER;
        }
        if (initialData) {
            if (initialDataLength > 0) {
                if (!callback(initialData, offset, initialDataLength, clientData)) {
@@ -854,7 +848,7 @@ bool MtpDevice::sendData() {
    ALOGV("sendData\n");
    mData.setOperationCode(mRequest.getOperationCode());
    mData.setTransactionID(mRequest.getTransactionID());
    int ret = mData.write(mRequestOut);
    int ret = mData.write(mRequestOut, mPacketDivisionMode);
    mData.dump();
    return (ret >= 0);
}
@@ -881,12 +875,6 @@ bool MtpDevice::readData() {
    }
}

bool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) {
    mData.setOperationCode(operation);
    mData.setTransactionID(mRequest.getTransactionID());
    return (!mData.writeDataHeader(mRequestOut, dataLength));
}

MtpResponseCode MtpDevice::readResponse() {
    ALOGV("readResponse\n");
    if (mReceivedResponse) {
+3 −0
Original line number Diff line number Diff line
@@ -71,6 +71,9 @@ private:
    Mutex                   mEventMutex;
    Mutex                   mEventMutexForInterrupt;

    // Remember the device's packet division mode.
    UrbPacketDivisionMode   mPacketDivisionMode;

public:
    typedef bool (*ReadObjectCallback)
            (void* data, uint32_t offset, uint32_t length, void* clientData);
+7 −0
Original line number Diff line number Diff line
@@ -73,6 +73,13 @@ typedef UInt32List MtpStorageIDList;

typedef String8    MtpString;

enum UrbPacketDivisionMode {
    // First packet only contains a header.
    FIRST_PACKET_ONLY_HEADER,
    // First packet contains payload much as possible.
    FIRST_PACKET_HAS_PAYLOAD
};

}; // namespace android

#endif // _MTP_TYPES_H