MTP: Remove race condition in initial device enumeration for host mode.

Change-Id: Iee01aaae3f8cca4234daa289bef6631da4d6c2b6
Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/media/mtp/MtpClient.cpp b/media/mtp/MtpClient.cpp
index b4c47af..8d10c27 100644
--- a/media/mtp/MtpClient.cpp
+++ b/media/mtp/MtpClient.cpp
@@ -27,7 +27,6 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <errno.h>
-#include <utils/threads.h>
 
 #include <usbhost/usbhost.h>
 #include <linux/version.h>
@@ -67,6 +66,8 @@
 }
 
 bool MtpClient::start() {
+    Mutex::Autolock autoLock(mMutex);
+
     if (mThread)
         return true;
 
@@ -76,6 +77,8 @@
 
     mThread = new MtpClientThread(this);
     mThread->run("MtpClientThread");
+    // wait for the thread to do initial device discovery before returning
+    mThreadStartCondition.wait(mMutex);
 
     return true;
 }
@@ -84,6 +87,15 @@
     mDone = true;
 }
 
+MtpDevice* MtpClient::getDevice(int id) {
+    for (int i = 0; i < mDeviceList.size(); i++) {
+        MtpDevice* device = mDeviceList[i];
+        if (device->getID() == id)
+            return device;
+    }
+    return NULL;
+}
+
 bool MtpClient::usbDeviceAdded(const char *devname) {
     struct usb_descriptor_header* desc;
     struct usb_descriptor_iter iter;
@@ -159,15 +171,6 @@
     return mDone;
 }
 
-MtpDevice* MtpClient::getDevice(int id) {
-    for (int i = 0; i < mDeviceList.size(); i++) {
-        MtpDevice* device = mDeviceList[i];
-        if (device->getID() == id)
-            return device;
-    }
-    return NULL;
-}
-
 bool MtpClient::usbDeviceRemoved(const char *devname) {
     for (int i = 0; i < mDeviceList.size(); i++) {
         MtpDevice* device = mDeviceList[i];
@@ -182,8 +185,14 @@
     return mDone;
 }
 
+bool MtpClient::usbDiscoveryDone() {
+    Mutex::Autolock autoLock(mMutex);
+    mThreadStartCondition.signal();
+    return mDone;
+}
+
 bool MtpClient::threadLoop() {
-    usb_host_run(mUsbHostContext, usb_device_added, usb_device_removed, this);
+    usb_host_run(mUsbHostContext, usb_device_added, usb_device_removed, usb_discovery_done, this);
     return false;
 }
 
@@ -197,4 +206,9 @@
     return ((MtpClient *)client_data)->usbDeviceRemoved(devname);
 }
 
+int MtpClient::usb_discovery_done(void* client_data) {
+    LOGD("usb_discovery_done\n");
+    return ((MtpClient *)client_data)->usbDiscoveryDone();
+}
+
 }  // namespace android
diff --git a/media/mtp/MtpClient.h b/media/mtp/MtpClient.h
index 907a80b..fa5c527 100644
--- a/media/mtp/MtpClient.h
+++ b/media/mtp/MtpClient.h
@@ -19,6 +19,8 @@
 
 #include "MtpTypes.h"
 
+#include <utils/threads.h>
+
 struct usb_host_context;
 
 namespace android {
@@ -29,6 +31,8 @@
 private:
     MtpDeviceList               mDeviceList;
     MtpClientThread*            mThread;
+    Condition                   mThreadStartCondition;
+    Mutex                       mMutex;
     struct usb_host_context*    mUsbHostContext;
     bool                        mDone;
 
@@ -50,11 +54,13 @@
     // these return true if we should stop monitoring USB and clean up
     bool                    usbDeviceAdded(const char *devname);
     bool                    usbDeviceRemoved(const char *devname);
+    bool                    usbDiscoveryDone();
 
     friend class MtpClientThread;
     bool                    threadLoop();
     static int              usb_device_added(const char *devname, void* client_data);
     static int              usb_device_removed(const char *devname, void* client_data);
+    static int              usb_discovery_done(void* client_data);
 };
 
 }; // namespace android