Fix flutter run --use-application-binary (#6106)

When using --use-application-binary:

- [x] Stop flutter run from checking for a pubspec.yaml in current directory
- [x] Stop flutter run from invoking pub get
- [x] Set 'shouldBuild' based on --use-application-binary
- [x] Stop requiring 'lib/main.dart' to be present before running.
- [x] Stop building an FLX when launching on Android
diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart
index e4c2a5c..0234e07 100644
--- a/packages/flutter_tools/lib/src/android/android_device.dart
+++ b/packages/flutter_tools/lib/src/android/android_device.dart
@@ -274,12 +274,15 @@
   }) async {
     printTrace('$this startBundle');
 
-    if (!FileSystemEntity.isFileSync(bundlePath)) {
-      printError('Cannot find $bundlePath');
-      return new LaunchResult.failed();
-    }
+    if (bundlePath != null) {
+      if (!FileSystemEntity.isFileSync(bundlePath)) {
+        printError('Cannot find $bundlePath');
+        return new LaunchResult.failed();
+      }
 
-    runCheckedSync(adbCommandForDevice(<String>['push', bundlePath, _deviceBundlePath]));
+      runCheckedSync(
+          adbCommandForDevice(<String>['push', bundlePath, _deviceBundlePath]));
+    }
 
     ProtocolDiscovery observatoryDiscovery;
     ProtocolDiscovery diagnosticDiscovery;
@@ -289,13 +292,26 @@
       diagnosticDiscovery = new ProtocolDiscovery(logReader, ProtocolDiscovery.kDiagnosticService);
     }
 
-    List<String> cmd = adbCommandForDevice(<String>[
-      'shell', 'am', 'start',
-      '-a', 'android.intent.action.RUN',
-      '-d', _deviceBundlePath,
-      '-f', '0x20000000',  // FLAG_ACTIVITY_SINGLE_TOP
-      '--ez', 'enable-background-compilation', 'true',
-    ]);
+    List<String> cmd;
+
+    if (bundlePath != null) {
+      // Specify in the RUN intent the path to the local bundle pushed.
+      cmd = adbCommandForDevice(<String>[
+        'shell', 'am', 'start',
+        '-a', 'android.intent.action.RUN',
+        '-d', _deviceBundlePath,
+        '-f', '0x20000000',  // FLAG_ACTIVITY_SINGLE_TOP
+        '--ez', 'enable-background-compilation', 'true',
+      ]);
+    } else {
+      cmd = adbCommandForDevice(<String>[
+        'shell', 'am', 'start',
+        '-a', 'android.intent.action.RUN',
+        '-f', '0x20000000',  // FLAG_ACTIVITY_SINGLE_TOP
+        '--ez', 'enable-background-compilation', 'true',
+      ]);
+    }
+
     if (traceStartup)
       cmd.addAll(<String>['--ez', 'trace-startup', 'true']);
     if (route != null)
@@ -372,19 +388,23 @@
     String mainPath,
     String route,
     DebuggingOptions debuggingOptions,
-    Map<String, dynamic> platformArgs
+    Map<String, dynamic> platformArgs,
+    bool prebuiltApplication: false
   }) async {
     if (!_checkForSupportedAdbVersion() || !_checkForSupportedAndroidVersion())
       return new LaunchResult.failed();
 
-    String localBundlePath = await flx.buildFlx(
-      mainPath: mainPath,
-      precompiledSnapshot: isAotBuildMode(debuggingOptions.buildMode),
-      includeRobotoFonts: false
-    );
+    String localBundlePath;
 
-    if (localBundlePath == null)
-      return new LaunchResult.failed();
+    if (!prebuiltApplication) {
+      localBundlePath = await flx.buildFlx(
+        mainPath: mainPath,
+        precompiledSnapshot: isAotBuildMode(debuggingOptions.buildMode),
+        includeRobotoFonts: false
+      );
+      if (localBundlePath == null)
+        return new LaunchResult.failed();
+    }
 
     printTrace('Starting bundle for $this.');
 
@@ -430,10 +450,15 @@
     ApplicationPackage package,
     LaunchResult result, {
     String mainPath,
-    VMService observatory
+    VMService observatory,
+    bool prebuiltApplication: false
   }) async {
     Directory tempDir = await Directory.systemTemp.createTemp('flutter_tools');
 
+    if (prebuiltApplication) {
+      return false;
+    }
+
     try {
       String snapshotPath = path.join(tempDir.path, 'snapshot_blob.bin');
       int result = await flx.createSnapshot(mainPath: mainPath, snapshotPath: snapshotPath);
diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart
index 0680d7f..8d11f75 100644
--- a/packages/flutter_tools/lib/src/commands/run.dart
+++ b/packages/flutter_tools/lib/src/commands/run.dart
@@ -81,6 +81,15 @@
     // results out to 'refresh_benchmark.json', and exit. This flag is intended
     // for use in generating automated flutter benchmarks.
     argParser.addFlag('benchmark', negatable: false, hide: !verboseHelp);
+
+    commandValidator = () {
+      if (!runningWithPrebuiltApplication) {
+        return commonCommandValidator();
+      }
+      // When running with a prebuilt application, no command validation is
+      // necessary.
+      return true;
+    };
   }
 
   Device device;
@@ -108,10 +117,24 @@
     }
   }
 
-  bool shouldUseHotMode() {
-    return argResults['hot'] && (getBuildMode() == BuildMode.debug);
+  @override
+  bool get shouldRunPub {
+    // If we are running with a prebuilt application, do not run pub.
+    if (runningWithPrebuiltApplication)
+      return false;
+
+    return super.shouldRunPub;
   }
 
+  bool shouldUseHotMode() {
+    bool hotArg = argResults['hot'] ?? false;
+    final bool shouldUseHotMode = hotArg && !runningWithPrebuiltApplication;
+    return (getBuildMode() == BuildMode.debug) && shouldUseHotMode;
+  }
+
+  bool get runningWithPrebuiltApplication =>
+      argResults['use-application-binary'] != null;
+
   @override
   Future<int> verifyThenRunCommand() async {
     if (!commandValidator())
@@ -191,7 +214,7 @@
       );
     }
 
-    return runner.run(route: route, shouldBuild: argResults['build']);
+    return runner.run(route: route, shouldBuild: !runningWithPrebuiltApplication && argResults['build']);
   }
 }
 
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart
index c9d454e..4ca2505 100644
--- a/packages/flutter_tools/lib/src/device.dart
+++ b/packages/flutter_tools/lib/src/device.dart
@@ -182,7 +182,8 @@
     String mainPath,
     String route,
     DebuggingOptions debuggingOptions,
-    Map<String, dynamic> platformArgs
+    Map<String, dynamic> platformArgs,
+    bool prebuiltApplication: false
   });
 
   /// Does this device implement support for hot reloading / restarting?
@@ -205,7 +206,8 @@
     ApplicationPackage package,
     LaunchResult result, {
     String mainPath,
-    VMService observatory
+    VMService observatory,
+    bool prebuiltApplication: false
   }) async {
     throw 'unsupported';
   }
diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart
index 3e4c378..5bd1a0c 100644
--- a/packages/flutter_tools/lib/src/ios/devices.dart
+++ b/packages/flutter_tools/lib/src/ios/devices.dart
@@ -181,7 +181,8 @@
     String mainPath,
     String route,
     DebuggingOptions debuggingOptions,
-    Map<String, dynamic> platformArgs
+    Map<String, dynamic> platformArgs,
+    bool prebuiltApplication: false
   }) async {
     // TODO(chinmaygarde): Use checked, mainPath, route.
     // TODO(devoncarew): Handle startPaused, debugPort.
diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart
index 981cc3d..49201a3 100644
--- a/packages/flutter_tools/lib/src/ios/simulators.dart
+++ b/packages/flutter_tools/lib/src/ios/simulators.dart
@@ -412,7 +412,8 @@
     String mainPath,
     String route,
     DebuggingOptions debuggingOptions,
-    Map<String, dynamic> platformArgs
+    Map<String, dynamic> platformArgs,
+    bool prebuiltApplication: false
   }) async {
     printTrace('Building ${app.name} for $id.');
 
diff --git a/packages/flutter_tools/lib/src/run.dart b/packages/flutter_tools/lib/src/run.dart
index f9ace41..b4e5d30 100644
--- a/packages/flutter_tools/lib/src/run.dart
+++ b/packages/flutter_tools/lib/src/run.dart
@@ -38,6 +38,8 @@
   final bool benchmark;
   final String applicationBinary;
 
+  bool get prebuiltMode => applicationBinary != null;
+
   @override
   Future<int> run({
     Completer<DebugConnectionInfo> connectionInfoCompleter,
@@ -46,6 +48,7 @@
   }) {
     // Don't let uncaught errors kill the process.
     return runZoned(() {
+      assert(shouldBuild == !prebuiltMode);
       return _run(
         traceStartup: traceStartup,
         benchmark: benchmark,
@@ -78,7 +81,8 @@
         _package,
         _result,
         mainPath: _mainPath,
-        observatory: vmService
+        observatory: vmService,
+        prebuiltApplication: prebuiltMode
       );
 
       status.stop(showElapsedTime: true);
@@ -99,13 +103,15 @@
     String route,
     bool shouldBuild: true
   }) async {
-    _mainPath = findMainDartFile(target);
-    if (!FileSystemEntity.isFileSync(_mainPath)) {
-      String message = 'Tried to run $_mainPath, but that file does not exist.';
-      if (target == null)
-        message += '\nConsider using the -t option to specify the Dart file to start.';
-      printError(message);
-      return 1;
+    if (!prebuiltMode) {
+      _mainPath = findMainDartFile(target);
+      if (!FileSystemEntity.isFileSync(_mainPath)) {
+        String message = 'Tried to run $_mainPath, but that file does not exist.';
+        if (target == null)
+          message += '\nConsider using the -t option to specify the Dart file to start.';
+        printError(message);
+        return 1;
+      }
     }
 
     _package = getApplicationPackageForPlatform(device.platform, applicationBinary: applicationBinary);
@@ -153,7 +159,12 @@
       platformArgs = <String, dynamic>{ 'trace-startup': traceStartup };
 
     await startEchoingDeviceLog();
-    printStatus('Running ${getDisplayPath(_mainPath)} on ${device.name}...');
+    if (_mainPath == null) {
+      assert(prebuiltMode);
+      printStatus('Running ${_package.displayName} on ${device.name}');
+    } else {
+      printStatus('Running ${getDisplayPath(_mainPath)} on ${device.name}...');
+    }
 
     _result = await device.startApp(
       _package,
@@ -161,7 +172,8 @@
       mainPath: _mainPath,
       debuggingOptions: debuggingOptions,
       platformArgs: platformArgs,
-      route: route
+      route: route,
+      prebuiltApplication: prebuiltMode
     );
 
     if (!_result.started) {
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index 6099969..80869ec 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -22,7 +22,7 @@
 
 abstract class FlutterCommand extends Command {
   FlutterCommand() {
-    commandValidator = _commandValidator;
+    commandValidator = commonCommandValidator;
   }
 
   @override
@@ -206,7 +206,7 @@
   // This is a field so that you can modify the value for testing.
   Validator commandValidator;
 
-  bool _commandValidator() {
+  bool commonCommandValidator() {
     if (!PackageMap.isUsingCustomPackagesPath) {
       // Don't expect a pubspec.yaml file if the user passed in an explicit .packages file path.
       if (!FileSystemEntity.isFileSync('pubspec.yaml')) {