Wait for threads to finish before returning.

Prevents the thread struct from being deallocated
before the thread has finished.

Bug: 35152606
Test: Transfer files in both directions, verify behavior when
interrupted

Change-Id: Ic247072234977709711366636e6a39031fbc125a
diff --git a/media/mtp/AsyncIO.cpp b/media/mtp/AsyncIO.cpp
index e77ad38..bfb07dc 100644
--- a/media/mtp/AsyncIO.cpp
+++ b/media/mtp/AsyncIO.cpp
@@ -96,6 +96,10 @@
 
 } // end anonymous namespace
 
+aiocb::~aiocb() {
+    CHECK(!thread.joinable());
+}
+
 void aio_pool_init(void(f)(int)) {
     CHECK(done == 1);
     done = 0;
diff --git a/media/mtp/AsyncIO.h b/media/mtp/AsyncIO.h
index f7515a2..ed80828 100644
--- a/media/mtp/AsyncIO.h
+++ b/media/mtp/AsyncIO.h
@@ -48,6 +48,8 @@
     std::thread thread;
     ssize_t ret;
     int error;
+
+    ~aiocb();
 };
 
 // Submit a request for IO to be completed
@@ -58,9 +60,13 @@
 
 // Suspend current thread until given IO is complete, at which point
 // its return value and any errors can be accessed
+// All submitted requests must have a corresponding suspend.
+// aiocb->aio_buf must refer to valid memory until after the suspend call
 int aio_suspend(struct aiocb *[], int, const struct timespec *);
 int aio_error(const struct aiocb *);
 ssize_t aio_return(struct aiocb *);
+
+// (Currently unimplemented)
 int aio_cancel(int, struct aiocb *);
 
 // Initialize a threadpool to perform IO. Only one pool can be
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 0ea70fa..565a2fe 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -541,14 +541,12 @@
         if (file_length > 0) {
             length = std::min(static_cast<uint32_t>(MAX_FILE_CHUNK_SIZE), file_length);
 
-            // Read data from USB
-            if ((ret = readHandle(mBulkOut, data, length)) == -1) {
-                return -1;
-            }
+            // Read data from USB, handle errors after waiting for write thread.
+            ret = readHandle(mBulkOut, data, length);
 
             if (file_length != MAX_MTP_FILE_SIZE && ret < static_cast<int>(length)) {
+                ret = -1;
                 errno = EIO;
-                return -1;
             }
             read = true;
         }
@@ -569,6 +567,11 @@
             write = false;
         }
 
+        // If there was an error reading above
+        if (ret == -1) {
+            return -1;
+        }
+
         if (read) {
             // Enqueue a new write request
             aio.aio_buf = data;
@@ -626,6 +629,7 @@
     aio.aio_fildes = mfr.fd;
     struct aiocb *aiol[] = {&aio};
     int ret, length;
+    int error = 0;
     bool read = false;
     bool write = false;
 
@@ -669,6 +673,10 @@
             write = true;
         }
 
+        if (error == -1) {
+            return -1;
+        }
+
         if (file_length > 0) {
             length = std::min(static_cast<uint64_t>(MAX_FILE_CHUNK_SIZE), file_length);
             // Queue up another read
@@ -680,8 +688,9 @@
         }
 
         if (write) {
-            if (writeHandle(mBulkIn, data2, ret) == -1)
-                return -1;
+            if (writeHandle(mBulkIn, data2, ret) == -1) {
+                error = -1;
+            }
             write = false;
         }
     }