Add getPartialObject method to MtpDevice.

The CL adds getPartialObject operation to MtpDevice (host side
implementation).

BUG=26284424

Change-Id: Ia8f41b0ebb7dfb4572729eacb5902f21360c8db1
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 23e432e..30843a7 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -53,12 +53,16 @@
 
 namespace {
 
-bool writeToFd(void* data, int /* unused_offset */, int length, void* clientData) {
+bool writeToFd(void* data, uint32_t /* unused_offset */, uint32_t length, void* clientData) {
     const int fd = *static_cast<int*>(clientData);
-    return write(fd, data, length) == length;
+    const ssize_t result = write(fd, data, length);
+    if (result < 0) {
+        return false;
+    }
+    return static_cast<uint32_t>(result) == length;
 }
 
-}
+}  // namespace
 
 MtpDevice* MtpDevice::open(const char* deviceName, int fd) {
     struct usb_device *device = usb_device_new(deviceName, fd);
@@ -611,7 +615,7 @@
 
 bool MtpDevice::readObject(MtpObjectHandle handle,
                            ReadObjectCallback callback,
-                           size_t expectedLength,
+                           uint32_t expectedLength,
                            void* clientData) {
     return readObjectInternal(handle, callback, &expectedLength, clientData);
 }
@@ -643,7 +647,7 @@
 
 bool MtpDevice::readObjectInternal(MtpObjectHandle handle,
                                    ReadObjectCallback callback,
-                                   const size_t* expectedLength,
+                                   const uint32_t* expectedLength,
                                    void* clientData) {
     Mutex::Autolock autoLock(mMutex);
 
@@ -654,11 +658,23 @@
         return false;
     }
 
+    return readData(callback, expectedLength, nullptr, clientData);
+}
+
+bool MtpDevice::readData(ReadObjectCallback callback,
+                            const uint32_t* expectedLength,
+                            uint32_t* writtenSize,
+                            void* clientData) {
     if (!mData.readDataHeader(mRequestIn1)) {
         ALOGE("Failed to read header.");
         return false;
     }
 
+    if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
+        mResponse.copyFrom(mData);
+        return mResponse.getResponseCode() == MTP_RESPONSE_OK ? 0 : -1;
+    }
+
     // If object size 0 byte, the remote device can reply response packet
     // without sending any data packets.
     if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
@@ -667,13 +683,16 @@
     }
 
     const uint32_t fullLength = mData.getContainerLength();
-    if ((!expectedLength && fullLength < MTP_CONTAINER_HEADER_SIZE) ||
-        (expectedLength && *expectedLength + MTP_CONTAINER_HEADER_SIZE != fullLength)) {
+    if (fullLength < MTP_CONTAINER_HEADER_SIZE) {
+        ALOGE("fullLength is too short: %d", fullLength);
+        return false;
+    }
+    const uint32_t length = fullLength - MTP_CONTAINER_HEADER_SIZE;
+    if (expectedLength && length != *expectedLength) {
         ALOGE("readObject error length: %d", fullLength);
         return false;
     }
 
-    const uint32_t length = fullLength - MTP_CONTAINER_HEADER_SIZE;
     uint32_t offset = 0;
     bool writingError = false;
 
@@ -718,8 +737,8 @@
             // Queue up a read request.
             const size_t remaining = length - nextOffset;
             req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
-            req->buffer_length =
-                    remaining > MTP_BUFFER_SIZE ? static_cast<size_t>(MTP_BUFFER_SIZE) : remaining;
+            req->buffer_length = remaining > MTP_BUFFER_SIZE ?
+                    static_cast<size_t>(MTP_BUFFER_SIZE) : remaining;
             if (mData.readDataAsync(req) != 0) {
                 ALOGE("readDataAsync failed");
                 return false;
@@ -736,7 +755,30 @@
         offset = nextOffset;
     }
 
-    return readResponse() == MTP_RESPONSE_OK && !writingError;
+    if (writtenSize) {
+        *writtenSize = length;
+    }
+
+    return readResponse() == MTP_RESPONSE_OK;
+}
+
+bool MtpDevice::readPartialObject(MtpObjectHandle handle,
+                                  uint32_t offset,
+                                  uint32_t size,
+                                  uint32_t *writtenSize,
+                                  ReadObjectCallback callback,
+                                  void* clientData) {
+    Mutex::Autolock autoLock(mMutex);
+
+    mRequest.reset();
+    mRequest.setParameter(1, handle);
+    mRequest.setParameter(2, offset);
+    mRequest.setParameter(3, size);
+    if (!sendRequest(MTP_OPERATION_GET_PARTIAL_OBJECT)) {
+        ALOGE("Failed to send a read request.");
+        return false;
+    }
+    return readData(callback, NULL /* expected size */, writtenSize, clientData);
 }
 
 bool MtpDevice::sendRequest(MtpOperationCode operation) {
diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h
index 87b3b90..60f08ba 100644
--- a/media/mtp/MtpDevice.h
+++ b/media/mtp/MtpDevice.h
@@ -68,11 +68,14 @@
     Mutex                   mEventMutexForInterrupt;
 
 public:
-    typedef bool (*ReadObjectCallback)(void* data, int offset, int length, void* clientData);
-                            MtpDevice(struct usb_device* device, int interface,
-                                    const struct usb_endpoint_descriptor *ep_in,
-                                    const struct usb_endpoint_descriptor *ep_out,
-                                    const struct usb_endpoint_descriptor *ep_intr);
+    typedef bool (*ReadObjectCallback)
+            (void* data, uint32_t offset, uint32_t length, void* clientData);
+
+    MtpDevice(struct usb_device* device,
+              int interface,
+              const struct usb_endpoint_descriptor *ep_in,
+              const struct usb_endpoint_descriptor *ep_out,
+              const struct usb_endpoint_descriptor *ep_intr);
 
     static MtpDevice*       open(const char* deviceName, int fd);
 
@@ -105,10 +108,16 @@
     MtpProperty*            getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format);
 
     bool                    readObject(MtpObjectHandle handle, ReadObjectCallback callback,
-                                    size_t objectSize, void* clientData);
+                                    uint32_t objectSize, void* clientData);
     bool                    readObject(MtpObjectHandle handle, const char* destPath, int group,
                                     int perm);
     bool                    readObject(MtpObjectHandle handle, int fd);
+    bool                    readPartialObject(MtpObjectHandle handle,
+                                              uint32_t offset,
+                                              uint32_t size,
+                                              uint32_t *writtenSize,
+                                              ReadObjectCallback callback,
+                                              void* clientData);
     // Starts a request to read MTP event from MTP device. It returns a request handle that
     // can be used for blocking read or cancel. If other thread has already been processing an
     // event returns -1.
@@ -124,8 +133,15 @@
 
 private:
     // If |objectSize| is not NULL, it checks object size before reading data bytes.
-    bool                    readObjectInternal(MtpObjectHandle handle, ReadObjectCallback callback,
-                                     const size_t* objectSize, void* clientData);
+    bool                    readObjectInternal(MtpObjectHandle handle,
+                                               ReadObjectCallback callback,
+                                               const uint32_t* objectSize,
+                                               void* clientData);
+    // If |objectSize| is not NULL, it checks object size before reading data bytes.
+    bool                    readData(ReadObjectCallback callback,
+                                     const uint32_t* objectSize,
+                                     uint32_t* writtenData,
+                                     void* clientData);
     bool                    sendRequest(MtpOperationCode operation);
     bool                    sendData();
     bool                    readData();