Loading media/mtp/MtpDataPacket.cpp +118 −22 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -511,29 +532,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 Loading media/mtp/MtpDataPacket.h +9 −4 Original line number Diff line number Diff line Loading @@ -93,7 +93,6 @@ public: inline void putEmptyString() { putUInt8(0); } inline void putEmptyArray() { putUInt32(0); } #ifdef MTP_DEVICE // fill our buffer with data from the given file descriptor int read(int fd); Loading @@ -110,9 +109,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; } Loading media/mtp/MtpDevice.cpp +19 −31 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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)) { Loading Loading @@ -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); } Loading @@ -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) { Loading media/mtp/MtpDevice.h +3 −0 Original line number Diff line number Diff line Loading @@ -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); Loading media/mtp/MtpTypes.h +7 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
media/mtp/MtpDataPacket.cpp +118 −22 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -511,29 +532,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 Loading
media/mtp/MtpDataPacket.h +9 −4 Original line number Diff line number Diff line Loading @@ -93,7 +93,6 @@ public: inline void putEmptyString() { putUInt8(0); } inline void putEmptyArray() { putUInt32(0); } #ifdef MTP_DEVICE // fill our buffer with data from the given file descriptor int read(int fd); Loading @@ -110,9 +109,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; } Loading
media/mtp/MtpDevice.cpp +19 −31 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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)) { Loading Loading @@ -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); } Loading @@ -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) { Loading
media/mtp/MtpDevice.h +3 −0 Original line number Diff line number Diff line Loading @@ -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); Loading
media/mtp/MtpTypes.h +7 −0 Original line number Diff line number Diff line Loading @@ -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