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

Commit 4e1fe188 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Don't send short URB packet when sending MtpDataPacket."

parents 72e8bfdd d4b4296b
Loading
Loading
Loading
Loading
+118 −22
Original line number Original line Diff line number Diff line
@@ -16,17 +16,38 @@


#define LOG_TAG "MtpDataPacket"
#define LOG_TAG "MtpDataPacket"


#include "MtpDataPacket.h"

#include <algorithm>
#include <fcntl.h>
#include <stdio.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/types.h>
#include <fcntl.h>

#include <usbhost/usbhost.h>
#include <usbhost/usbhost.h>

#include "MtpDataPacket.h"
#include "MtpStringBuffer.h"
#include "MtpStringBuffer.h"


namespace android {
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()
MtpDataPacket::MtpDataPacket()
    :   MtpPacket(MTP_BUFFER_SIZE),   // MAX_USBFS_BUFFER_SIZE
    :   MtpPacket(MTP_BUFFER_SIZE),   // MAX_USBFS_BUFFER_SIZE
        mOffset(MTP_CONTAINER_HEADER_SIZE)
        mOffset(MTP_CONTAINER_HEADER_SIZE)
@@ -511,29 +532,104 @@ int MtpDataPacket::readDataHeader(struct usb_request *request) {
    return length;
    return length;
}
}


int MtpDataPacket::writeDataHeader(struct usb_request *request, uint32_t length) {
int MtpDataPacket::write(struct usb_request *request, UrbPacketDivisionMode divisionMode) {
    MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length);
    if (mPacketSize < MTP_CONTAINER_HEADER_SIZE || mPacketSize > MTP_BUFFER_SIZE) {
    MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
        ALOGE("Illegal packet size.");
    request->buffer = mBuffer;
        return -1;
    request->buffer_length = MTP_CONTAINER_HEADER_SIZE;
    int ret = transfer(request);
    return (ret < 0 ? ret : 0);
    }
    }


int MtpDataPacket::write(struct usb_request *request) {
    MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
    MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
    MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
    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 = mBuffer;
    request->buffer_length = mPacketSize;
    allocate(maxBulkTransferSize);
    int ret = transfer(request);

    return (ret < 0 ? ret : 0);
    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) {
        // Update variables.
    request->buffer = buffer;
        processedBytes += bulkTransferSize;
    request->buffer_length = length;
    }
    int ret = transfer(request);

    return (ret < 0 ? ret : 0);
    return readError ? -1 : processedBytes;
}
}


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



#ifdef MTP_DEVICE
#ifdef MTP_DEVICE
    // fill our buffer with data from the given file descriptor
    // fill our buffer with data from the given file descriptor
    int                 read(int fd);
    int                 read(int fd);
@@ -110,9 +109,15 @@ public:
    int                 readDataWait(struct usb_device *device);
    int                 readDataWait(struct usb_device *device);
    int                 readDataHeader(struct usb_request *ep);
    int                 readDataHeader(struct usb_request *ep);


    int                 writeDataHeader(struct usb_request *ep, uint32_t length);
    // Write a whole data packet with payload to the end point given by a request. |divisionMode|
    int                 write(struct usb_request *ep);
    // specifies whether to divide header and payload. See |UrbPacketDivisionMode| for meanings of
    int                 write(struct usb_request *ep, void* buffer, uint32_t length);
    // 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
#endif


    inline bool         hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; }
    inline bool         hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; }
+19 −31
Original line number Original line Diff line number Diff line
@@ -222,7 +222,8 @@ MtpDevice::MtpDevice(struct usb_device* device, int interface,
        mProcessingEvent(false),
        mProcessingEvent(false),
        mCurrentEventHandle(0),
        mCurrentEventHandle(0),
        mLastSendObjectInfoTransactionID(0),
        mLastSendObjectInfoTransactionID(0),
        mLastSendObjectInfoObjectHandle(0)
        mLastSendObjectInfoObjectHandle(0),
        mPacketDivisionMode(FIRST_PACKET_HAS_PAYLOAD)
{
{
    mRequestIn1 = usb_request_new(device, ep_in);
    mRequestIn1 = usb_request_new(device, ep_in);
    mRequestIn2 = 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;
        return false;
    }
    }


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

        const int writeResult = mData.write(mRequestOut, mPacketDivisionMode, srcFD, size);
        // USB writes greater than 16K don't work
        const MtpResponseCode ret = readResponse();
        char buffer[MTP_BUFFER_SIZE];
        return ret == MTP_RESPONSE_OK && writeResult > 0;
        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;
            }
        }
    }
    }
    MtpResponseCode ret = readResponse();
    return false;
    return (remaining == 0 && ret == MTP_RESPONSE_OK && !error);
}
}


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


    // If object size 0 byte, the remote device can reply response packet
    // If object size 0 byte, the remote device may reply a response packet without sending any data
    // without sending any data packets.
    // packets.
    if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
    if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
        mResponse.copyFrom(mData);
        mResponse.copyFrom(mData);
        return mResponse.getResponseCode() == MTP_RESPONSE_OK;
        return mResponse.getResponseCode() == MTP_RESPONSE_OK;
@@ -731,6 +717,14 @@ bool MtpDevice::readData(ReadObjectCallback callback,
    {
    {
        int initialDataLength = 0;
        int initialDataLength = 0;
        void* const initialData = mData.getData(&initialDataLength);
        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 (initialData) {
            if (initialDataLength > 0) {
            if (initialDataLength > 0) {
                if (!callback(initialData, offset, initialDataLength, clientData)) {
                if (!callback(initialData, offset, initialDataLength, clientData)) {
@@ -854,7 +848,7 @@ bool MtpDevice::sendData() {
    ALOGV("sendData\n");
    ALOGV("sendData\n");
    mData.setOperationCode(mRequest.getOperationCode());
    mData.setOperationCode(mRequest.getOperationCode());
    mData.setTransactionID(mRequest.getTransactionID());
    mData.setTransactionID(mRequest.getTransactionID());
    int ret = mData.write(mRequestOut);
    int ret = mData.write(mRequestOut, mPacketDivisionMode);
    mData.dump();
    mData.dump();
    return (ret >= 0);
    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() {
MtpResponseCode MtpDevice::readResponse() {
    ALOGV("readResponse\n");
    ALOGV("readResponse\n");
    if (mReceivedResponse) {
    if (mReceivedResponse) {
+3 −0
Original line number Original line Diff line number Diff line
@@ -71,6 +71,9 @@ private:
    Mutex                   mEventMutex;
    Mutex                   mEventMutex;
    Mutex                   mEventMutexForInterrupt;
    Mutex                   mEventMutexForInterrupt;


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

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


typedef String8    MtpString;
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
}; // namespace android


#endif // _MTP_TYPES_H
#endif // _MTP_TYPES_H