Use ProcessManager for Xcode tool invocations (#10955)

1. Run all Xcode tool invocations through ProcessManager, which allows
us to mock out failures, etc. for tests.

2. Add said tests.
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart
index 2dbca80..3c961e7 100644
--- a/packages/flutter_tools/lib/src/ios/mac.dart
+++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -86,7 +86,7 @@
   String get xcodeSelectPath {
     if (_xcodeSelectPath == null) {
       try {
-        _xcodeSelectPath = runSync(<String>['/usr/bin/xcode-select', '--print-path'])?.trim();
+        _xcodeSelectPath = processManager.runSync(<String>['/usr/bin/xcode-select', '--print-path']).stdout.trim();
       } on ProcessException {
         // Ignore: return null below.
       }
@@ -125,7 +125,7 @@
   String get xcodeVersionText {
     if (_xcodeVersionText == null) {
       try {
-        _xcodeVersionText = runSync(<String>['/usr/bin/xcodebuild', '-version']).replaceAll('\n', ', ');
+        _xcodeVersionText = processManager.runSync(<String>['/usr/bin/xcodebuild', '-version']).stdout.replaceAll('\n', ', ');
       } on ProcessException {
         // Ignore: return null below.
       }
@@ -155,10 +155,15 @@
   }
 
   Future<String> getAvailableDevices() async {
-    final RunResult result = await runAsync(<String>['/usr/bin/instruments', '-s', 'devices']);
-    if (result.exitCode != 0)
+    try {
+      final ProcessResult result = await processManager.run(
+          <String>['/usr/bin/instruments', '-s', 'devices']);
+      if (result.exitCode != 0)
+        throw new ToolExit('/usr/bin/instruments returned an error:\n${result.stderr}');
+      return result.stdout;
+    } on ProcessException {
       throw new ToolExit('Failed to invoke /usr/bin/instruments. Is Xcode installed?');
-    return result.stdout;
+    }
   }
 }