CB-8119 Restart adb when we detect it's hung
diff --git a/bin/templates/cordova/lib/build.js b/bin/templates/cordova/lib/build.js
index 85a6e7c..0d4d004 100644
--- a/bin/templates/cordova/lib/build.js
+++ b/bin/templates/cordova/lib/build.js
@@ -398,12 +398,44 @@
  * Returns "arm" or "x86".
  */
 module.exports.detectArchitecture = function(target) {
-    return exec('adb -s ' + target + ' shell cat /proc/cpuinfo')
-    .then(function(output) {
-        if (/intel/i.exec(output)) {
-            return 'x86';
+    function helper() {
+        return exec('adb -s ' + target + ' shell cat /proc/cpuinfo')
+        .then(function(output) {
+            if (/intel/i.exec(output)) {
+                return 'x86';
+            }
+            return 'arm';
+        });
+    }
+    // It sometimes happens (at least on OS X), that this command will hang forever.
+    // To fix it, either unplug & replug device, or restart adb server.
+    return helper().timeout(1000, 'Device communication timed out. Try unplugging & replugging the device.')
+    .then(null, function(err) {
+        if (/timed out/.exec('' + err)) {
+            // adb kill-server doesn't seem to do the trick.
+            // Could probably find a x-platform version of killall, but I'm not actually
+            // sure that this scenario even happens on non-OSX machines.
+            return exec('killall adb')
+            .then(function() {
+                console.log('adb seems hung. retrying.');
+                return helper()
+                .then(null, function() {
+                    // The double kill is sadly often necessary, at least on mac.
+                    console.log('Now device not found... restarting adb again.');
+                    return exec('killall adb')
+                    .then(function() {
+                        return helper()
+                        .then(null, function() {
+                            return Q.reject('USB is flakey. Try unplugging & replugging the device.');
+                        });
+                    });
+                });
+            }, function() {
+                // For non-killall OS's.
+                return Q.reject(err);
+            })
         }
-        return 'arm';
+        throw err;
     });
 };
 
diff --git a/bin/templates/cordova/lib/device.js b/bin/templates/cordova/lib/device.js
index 6be55e3..6430d73 100644
--- a/bin/templates/cordova/lib/device.js
+++ b/bin/templates/cordova/lib/device.js
@@ -28,23 +28,43 @@
 
 /**
  * Returns a promise for the list of the device ID's found
+ * @param lookHarder When true, try restarting adb if no devices are found.
  */
-module.exports.list = function() {
-    return exec('adb devices')
-    .then(function(output) {
-        var response = output.split('\n');
-        var device_list = [];
-        for (var i = 1; i < response.length; i++) {
-            if (response[i].match(/\w+\tdevice/) && !response[i].match(/emulator/)) {
-                device_list.push(response[i].replace(/\tdevice/, '').replace('\r', ''));
+module.exports.list = function(lookHarder) {
+    function helper() {
+        return exec('adb devices')
+        .then(function(output) {
+            var response = output.split('\n');
+            var device_list = [];
+            for (var i = 1; i < response.length; i++) {
+                if (response[i].match(/\w+\tdevice/) && !response[i].match(/emulator/)) {
+                    device_list.push(response[i].replace(/\tdevice/, '').replace('\r', ''));
+                }
             }
+            return device_list;
+        });
+    }
+    return helper()
+    .then(function(list) {
+        if (list.length === 0 && lookHarder) {
+            // adb kill-server doesn't seem to do the trick.
+            // Could probably find a x-platform version of killall, but I'm not actually
+            // sure that this scenario even happens on non-OSX machines.
+            return exec('killall adb')
+            .then(function() {
+                console.log('Restarting adb to see if more devices are detected.');
+                return helper();
+            }, function() {
+                // For non-killall OS's.
+                return list;
+            });
         }
-        return device_list;
+        return list;
     });
 }
 
 module.exports.resolveTarget = function(target) {
-    return this.list()
+    return this.list(true)
     .then(function(device_list) {
         if (!device_list || !device_list.length) {
             return Q.reject('ERROR: Failed to deploy to device, no devices found.');