Add functions to read MTP events from MTP devices.

BUG=23368533

Change-Id: I2003dda961339677caf56e57ae90cf6df7bd7430
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 9878f90..01117e6 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -204,7 +204,9 @@
         mDeviceInfo(NULL),
         mSessionID(0),
         mTransactionID(0),
-        mReceivedResponse(false)
+        mReceivedResponse(false),
+        mProcessingEvent(false),
+        mCurrentEventHandle(0)
 {
     mRequestIn1 = usb_request_new(device, ep_in);
     mRequestIn2 = usb_request_new(device, ep_in);
@@ -794,4 +796,40 @@
     }
 }
 
+int MtpDevice::submitEventRequest() {
+    if (mEventMutex.tryLock()) {
+        // An event is being reaped on another thread.
+        return -1;
+    }
+    if (mProcessingEvent) {
+        // An event request was submitted, but no reapEventRequest called so far.
+        return -1;
+    }
+    Mutex::Autolock autoLock(mEventMutexForInterrupt);
+    mEventPacket.sendRequest(mRequestIntr);
+    const int currentHandle = ++mCurrentEventHandle;
+    mProcessingEvent = true;
+    mEventMutex.unlock();
+    return currentHandle;
+}
+
+int MtpDevice::reapEventRequest(int handle) {
+    Mutex::Autolock autoLock(mEventMutex);
+    if (!mProcessingEvent || mCurrentEventHandle != handle) {
+        return -1;
+    }
+    mProcessingEvent = false;
+    const int readSize = mEventPacket.readResponse(mRequestIntr->dev);
+    const int result = mEventPacket.getEventCode();
+    return readSize == 0 ? 0 : result;
+}
+
+void MtpDevice::discardEventRequest(int handle) {
+    Mutex::Autolock autoLock(mEventMutexForInterrupt);
+    if (mCurrentEventHandle != handle) {
+        return;
+    }
+    usb_request_cancel(mRequestIntr);
+}
+
 }  // namespace android
diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h
index d2c6d67..87b3b90 100644
--- a/media/mtp/MtpDevice.h
+++ b/media/mtp/MtpDevice.h
@@ -17,8 +17,9 @@
 #ifndef _MTP_DEVICE_H
 #define _MTP_DEVICE_H
 
-#include "MtpRequestPacket.h"
+#include "MtpEventPacket.h"
 #include "MtpDataPacket.h"
+#include "MtpRequestPacket.h"
 #include "MtpResponsePacket.h"
 #include "MtpTypes.h"
 
@@ -31,6 +32,7 @@
 namespace android {
 
 class MtpDeviceInfo;
+class MtpEventPacket;
 class MtpObjectInfo;
 class MtpStorageInfo;
 
@@ -53,11 +55,17 @@
     MtpRequestPacket        mRequest;
     MtpDataPacket           mData;
     MtpResponsePacket       mResponse;
+    MtpEventPacket          mEventPacket;
+
     // set to true if we received a response packet instead of a data packet
     bool                    mReceivedResponse;
+    bool                    mProcessingEvent;
+    int                     mCurrentEventHandle;
 
     // to ensure only one MTP transaction at a time
     Mutex                   mMutex;
+    Mutex                   mEventMutex;
+    Mutex                   mEventMutexForInterrupt;
 
 public:
     typedef bool (*ReadObjectCallback)(void* data, int offset, int length, void* clientData);
@@ -101,6 +109,18 @@
     bool                    readObject(MtpObjectHandle handle, const char* destPath, int group,
                                     int perm);
     bool                    readObject(MtpObjectHandle handle, int fd);
+    // 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.
+    int                     submitEventRequest();
+    // Waits for MTP event from the device and returns MTP event code. It blocks the current thread
+    // until it receives an event from the device. |handle| should be a request handle returned
+    // by |submitEventRequest|. Returns 0 for cancellations. Returns -1 for errors.
+    int                     reapEventRequest(int handle);
+    // Cancels an event request. |handle| should be request handle returned by
+    // |submitEventRequest|. If there is a thread blocked by |reapEventRequest| with the same
+    // |handle|, the thread will resume.
+    void                    discardEventRequest(int handle);
 
 private:
     // If |objectSize| is not NULL, it checks object size before reading data bytes.
@@ -111,7 +131,6 @@
     bool                    readData();
     bool                    writeDataHeader(MtpOperationCode operation, int dataLength);
     MtpResponseCode         readResponse();
-
 };
 
 }; // namespace android
diff --git a/media/mtp/MtpEventPacket.cpp b/media/mtp/MtpEventPacket.cpp
index d2fca42..8e13ea9 100644
--- a/media/mtp/MtpEventPacket.cpp
+++ b/media/mtp/MtpEventPacket.cpp
@@ -54,17 +54,26 @@
 #endif
 
 #ifdef MTP_HOST
-int MtpEventPacket::read(struct usb_request *request) {
+int MtpEventPacket::sendRequest(struct usb_request *request) {
     request->buffer = mBuffer;
     request->buffer_length = mBufferSize;
-    int ret = transfer(request);
-     if (ret >= 0)
-        mPacketSize = ret;
-    else
-        mPacketSize = 0;
-    return ret;
+    mPacketSize = 0;
+    if (usb_request_queue(request)) {
+        ALOGE("usb_endpoint_queue failed, errno: %d", errno);
+        return -1;
+    }
+    return 0;
+}
+
+int MtpEventPacket::readResponse(struct usb_device *device) {
+    struct usb_request* const req = usb_request_wait(device);
+    if (req) {
+        mPacketSize = req->actual_length;
+        return req->actual_length;
+    } else {
+        return -1;
+    }
 }
 #endif
 
 }  // namespace android
-
diff --git a/media/mtp/MtpEventPacket.h b/media/mtp/MtpEventPacket.h
index 660baad..a8779fd 100644
--- a/media/mtp/MtpEventPacket.h
+++ b/media/mtp/MtpEventPacket.h
@@ -35,7 +35,8 @@
 
 #ifdef MTP_HOST
     // read our buffer with the given request
-    int                 read(struct usb_request *request);
+    int                 sendRequest(struct usb_request *request);
+    int                 readResponse(struct usb_device *device);
 #endif
 
     inline MtpEventCode     getEventCode() const { return getContainerCode(); }
diff --git a/media/mtp/MtpPacket.h b/media/mtp/MtpPacket.h
index 037722a..0e96309 100644
--- a/media/mtp/MtpPacket.h
+++ b/media/mtp/MtpPacket.h
@@ -19,6 +19,7 @@
 
 #include "MtpTypes.h"
 
+struct usb_device;
 struct usb_request;
 
 namespace android {