DO NOT MERGE : Add simple control request handling

Control request handling was already added in master,
but it is causing a few problems on Windows. This patch
simplifies the main patch and only responds to get
status requests with STATUS_OK. This fixes situations
where Windows stops communicating if it doesn't get a
response from this request.

Bug: 65423303
Test: Transfer files on windows
Change-Id: Ib7a53aa5b679f011b3a8ac6dff549ca051d579e0
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index dbca53e..8d894c1 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -62,6 +62,8 @@
 constexpr int USB_FFS_MAX_WRITE = MTP_BUFFER_SIZE;
 constexpr int USB_FFS_MAX_READ = MTP_BUFFER_SIZE;
 
+constexpr unsigned FFS_NUM_EVENTS = 5;
+
 static_assert(USB_FFS_MAX_WRITE > 0, "Max r/w values must be > 0!");
 static_assert(USB_FFS_MAX_READ > 0, "Max r/w values must be > 0!");
 
@@ -315,6 +317,11 @@
     .Reserved2 = {0},
 };
 
+struct mtp_device_status {
+    uint16_t  wLength;
+    uint16_t  wCode;
+};
+
 } // anonymous namespace
 
 namespace android {
@@ -392,6 +399,88 @@
     mControl.reset();
 }
 
+void MtpFfsHandle::controlLoop() {
+    while (!handleEvent()) {}
+    LOG(DEBUG) << "Mtp server shutting down";
+}
+
+int MtpFfsHandle::handleEvent() {
+    std::vector<usb_functionfs_event> events(FFS_NUM_EVENTS);
+    usb_functionfs_event *event = events.data();
+    int nbytes = TEMP_FAILURE_RETRY(::read(mControl, event,
+                events.size() * sizeof(usb_functionfs_event)));
+    if (nbytes == -1) {
+        return -1;
+    }
+    int ret = 0;
+    for (size_t n = nbytes / sizeof *event; n; --n, ++event) {
+        switch (event->type) {
+        case FUNCTIONFS_BIND:
+        case FUNCTIONFS_ENABLE:
+        case FUNCTIONFS_RESUME:
+            ret = 0;
+            errno = 0;
+            break;
+        case FUNCTIONFS_SUSPEND:
+        case FUNCTIONFS_UNBIND:
+        case FUNCTIONFS_DISABLE:
+            errno = ESHUTDOWN;
+            ret = -1;
+            break;
+        case FUNCTIONFS_SETUP:
+            if (handleControlRequest(&event->u.setup) == -1)
+                ret = -1;
+            break;
+        default:
+            LOG(DEBUG) << "Mtp Event " << event->type << " (unknown)";
+        }
+    }
+    return ret;
+}
+
+int MtpFfsHandle::handleControlRequest(const struct usb_ctrlrequest *setup) {
+    uint8_t type = setup->bRequestType;
+    uint8_t code = setup->bRequest;
+    uint16_t length = setup->wLength;
+    uint16_t index = setup->wIndex;
+    uint16_t value = setup->wValue;
+    std::vector<char> buf;
+    buf.resize(length);
+
+    if (!(type & USB_DIR_IN)) {
+        if (::read(mControl, buf.data(), length) != length) {
+            PLOG(DEBUG) << "Mtp error ctrlreq read data";
+        }
+    }
+
+    if ((type & USB_TYPE_MASK) == USB_TYPE_CLASS && index == 0 && value == 0) {
+        switch(code) {
+        case MTP_REQ_GET_DEVICE_STATUS:
+        {
+            if (length < sizeof(struct mtp_device_status)) {
+                return -1;
+            }
+            struct mtp_device_status *st = reinterpret_cast<struct mtp_device_status*>(buf.data());
+            st->wLength = htole16(sizeof(st));
+            st->wCode = MTP_RESPONSE_OK;
+            length = st->wLength;
+            break;
+        }
+        default:
+            LOG(DEBUG) << "Unrecognized Mtp class request! " << code;
+        }
+    } else {
+        LOG(DEBUG) << "Unrecognized request type " << type;
+    }
+
+    if (type & USB_DIR_IN) {
+        if (::write(mControl, buf.data(), length) != length) {
+            PLOG(DEBUG) << "Mtp error ctrlreq write data";
+        }
+    }
+    return 0;
+}
+
 int MtpFfsHandle::writeHandle(int fd, const void* data, int len) {
     LOG(VERBOSE) << "MTP about to write fd = " << fd << ", len=" << len;
     int ret = 0;
@@ -491,6 +580,10 @@
     posix_madvise(mBuffer2.data(), MAX_FILE_CHUNK_SIZE,
             POSIX_MADV_SEQUENTIAL | POSIX_MADV_WILLNEED);
 
+    // Handle control requests.
+    std::thread t([this]() { this->controlLoop(); });
+    t.detach();
+
     // Get device specific r/w size
     mMaxWrite = android::base::GetIntProperty("sys.usb.ffs.max_write", USB_FFS_MAX_WRITE);
     mMaxRead = android::base::GetIntProperty("sys.usb.ffs.max_read", USB_FFS_MAX_READ);