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);