Merge pull request #467 from RedBrogdon/nomono

Updates compilation and analysis to use an unforked version of the Flutter SDK
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..1f2e1eb
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,4 @@
+# Docker should ignore the local copy of Flutter and install its own,
+# since the Docker container is likely running a different OS than the
+# developer's machine.
+flutter
diff --git a/.gitmodules b/.gitmodules
index d9a07c4..37aa38f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +1,3 @@
-[submodule "flutter_web"]
-	path = flutter_web
-	url = https://github.com/flutter/flutter_web.git
-	branch = master
+[submodule "flutter"]
+	path = flutter
+	url = https://github.com/flutter/flutter.git
diff --git a/.travis.yml b/.travis.yml
index 9215045..9762685 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,4 +14,11 @@
 
 branches:
   only: [master]
+before_script:
+  - git submodule init
+  - git submodule update
+  - export PATH=$PATH:$PWD/flutter/bin
+  - flutter doctor
+  - flutter config --enable-web
+  - flutter precache --web --no-android --no-ios --no-linux --no-windows --no-macos --no-fuchsia
 script: ./tool/travis.sh
diff --git a/Dockerfile b/Dockerfile
index 195f826..fed533c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,12 +1,16 @@
 # Keep aligned with min SDK in pubspec.yaml and Dart test version in .travis.yml
 FROM google/dart:2.6.0
 
+# The specific commit that dart-services should use. This should be kept
+# in sync with the flutter submodule in the dart-services repo.
+# (run `git rev-parse HEAD` from the flutter submodule to retrieve this value.
+ARG FLUTTER_COMMIT=fbabb264e0ab3e090d6ec056e0744aaeb1586735
+
 WORKDIR /app
 ADD tool/dart_run.sh /dart_runtime/
 RUN chmod 755 /dart_runtime/dart_run.sh && \
   chown root:root /dart_runtime/dart_run.sh
 ADD pubspec.* /app/
-ADD third_party /app/third_party
 RUN find -name "*" -print
 RUN pub get
 ADD . /app
@@ -16,12 +20,37 @@
 # docker image diff small.
 RUN apt-get update && \
   apt-get install -y unzip && \
-  cp -a third_party/pkg ../pkg && \
   rm -rf /var/lib/apt/lists/*
 
+# The Flutter tool won't perform its actions when run as root.
+RUN groupadd --system dart && \
+  useradd --no-log-init --system --home /home/dart --create-home -g dart dart
+
+RUN mkdir flutter && chown dart:dart flutter
+
+# Switch to a new, non-root user to use the flutter tool.
+USER dart
+
+ENV PATH="/home/dart/.pub-cache/bin:${PATH}"
+
+# Clone the flutter repo and set it to the same commit as the flutter submodule.
+RUN git clone https://github.com/flutter/flutter.git
+RUN cd flutter && git checkout $FLUTTER_COMMIT
+
+# Set the Flutter SDK up for web compilation.
+RUN flutter/bin/flutter doctor
+RUN flutter/bin/flutter config --enable-web
+RUN flutter/bin/flutter precache --web --no-android --no-ios --no-linux \
+  --no-windows --no-macos --no-fuchsia
+RUN cat flutter/bin/cache/dart-sdk/version
+
 EXPOSE 8080 8181 5858
 
 # Clear out any arguments the base images might have set and ensure we start
 # the Dart app using custom script enabling debug modes.
 CMD []
+
+# Switch back to root to run the application.
+USER root
+
 ENTRYPOINT /bin/bash /dart_runtime/dart_run.sh
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 425f5e2..80e87de 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -7,4 +7,4 @@
     - 'dart-sdk/**'
     - 'third_party/**'
     - 'doc/generated/**'
-    - 'flutter_web/**'
+    - 'flutter/**'
diff --git a/benchmark/bench.dart b/benchmark/bench.dart
index 84c234a..88b9f23 100644
--- a/benchmark/bench.dart
+++ b/benchmark/bench.dart
@@ -6,6 +6,7 @@
 
 import 'dart:async';
 
+import 'package:dart_services/src/sdk_manager.dart';
 import 'package:logging/logging.dart';
 
 import 'package:dart_services/src/analysis_server.dart';
@@ -19,10 +20,12 @@
 
   final BenchmarkHarness harness = BenchmarkHarness(asJson: json);
 
-  final FlutterWebManager flutterWebManager = FlutterWebManager(sdkPath);
+  final FlutterWebManager flutterWebManager =
+      FlutterWebManager(SdkManager.flutterSdk);
   await flutterWebManager.initFlutterWeb();
 
-  var compiler = Compiler(sdkPath, flutterWebManager);
+  var compiler =
+      Compiler(SdkManager.sdk, SdkManager.flutterSdk, flutterWebManager);
 
   Logger.root.level = Level.WARNING;
   Logger.root.onRecord.listen((LogRecord record) {
diff --git a/bin/server.dart b/bin/server.dart
index 49bc5ab..5750d57 100644
--- a/bin/server.dart
+++ b/bin/server.dart
@@ -15,6 +15,7 @@
   // Ensure the Dart SDK is downloaded (if already up-to-date, no work is
   // performed).
   await SdkManager.sdk.init();
+  await SdkManager.flutterSdk.init();
 
   server.main(args);
 }
diff --git a/bin/server_dev.dart b/bin/server_dev.dart
index 50799e0..79ae125 100644
--- a/bin/server_dev.dart
+++ b/bin/server_dev.dart
@@ -12,6 +12,7 @@
 
 Future<void> main(List<String> args) async {
   await SdkManager.sdk.init();
+  await SdkManager.flutterSdk.init();
 
   services_dev.main(args);
 }
diff --git a/flutter b/flutter
new file mode 160000
index 0000000..fbabb26
--- /dev/null
+++ b/flutter
@@ -0,0 +1 @@
+Subproject commit fbabb264e0ab3e090d6ec056e0744aaeb1586735
diff --git a/flutter_web b/flutter_web
deleted file mode 160000
index c04fb50..0000000
--- a/flutter_web
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit c04fb502b842859de07e36954a9390465a5426c0
diff --git a/lib/services_dev.dart b/lib/services_dev.dart
index 3483203..842ee24 100644
--- a/lib/services_dev.dart
+++ b/lib/services_dev.dart
@@ -10,6 +10,7 @@
 import 'dart:io';
 
 import 'package:args/args.dart';
+import 'package:dart_services/src/sdk_manager.dart';
 import 'package:logging/logging.dart';
 import 'package:rpc/rpc.dart';
 import 'package:shelf/shelf.dart';
@@ -50,7 +51,7 @@
     if (result['relay'] as bool) {
       EndpointsServer.generateRelayDiscovery(sdk, serverUrl).then(printExit);
     } else {
-      EndpointsServer.generateDiscovery(sdk, serverUrl).then(printExit);
+      EndpointsServer.generateDiscovery(SdkManager.flutterSdk, serverUrl).then(printExit);
     }
     return;
   }
@@ -79,8 +80,8 @@
   }
 
   static Future<String> generateDiscovery(
-      String sdkPath, String serverUrl) async {
-    FlutterWebManager flutterWebManager = FlutterWebManager(sdkPath);
+      FlutterSdk flutterSdk, String serverUrl) async {
+    FlutterWebManager flutterWebManager = FlutterWebManager(flutterSdk);
     CommonServer commonServer =
         CommonServer(sdkPath, flutterWebManager, _ServerContainer(), _Cache());
     await commonServer.init();
@@ -124,7 +125,7 @@
   EndpointsServer._(String sdkPath, this.port) {
     discoveryEnabled = false;
 
-    flutterWebManager = FlutterWebManager(sdkPath);
+    flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
     commonServer =
         CommonServer(sdkPath, flutterWebManager, _ServerContainer(), _Cache());
     commonServer.init();
diff --git a/lib/services_gae.dart b/lib/services_gae.dart
index e3c11fc..887a1d4 100644
--- a/lib/services_gae.dart
+++ b/lib/services_gae.dart
@@ -8,6 +8,7 @@
 import 'dart:io' as io;
 
 import 'package:appengine/appengine.dart' as ae;
+import 'package:dart_services/src/sdk_manager.dart';
 import 'package:logging/logging.dart';
 import 'package:rpc/rpc.dart' as rpc;
 
@@ -42,7 +43,7 @@
       io.stdout.write(out);
     }
   });
-  log.info('''Initializing dart-services: 
+  log.info('''Initializing dart-services:
     port: $gaePort
     sdkPath: $sdkPath
     REDIS_SERVER_URI: ${io.Platform.environment['REDIS_SERVER_URI']}
@@ -70,7 +71,7 @@
 
     discoveryEnabled = false;
     fileRelayServer = FileRelayServer();
-    flutterWebManager = FlutterWebManager(sdkPath);
+    flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
     commonServer = CommonServer(
         sdkPath,
         flutterWebManager,
diff --git a/lib/src/analysis_server.dart b/lib/src/analysis_server.dart
index 952d874..416c449 100644
--- a/lib/src/analysis_server.dart
+++ b/lib/src/analysis_server.dart
@@ -66,7 +66,7 @@
         '--client-id=DartPad',
         '--client-version=$_sdkVersion'
       ];
-      _logger.info('About to start with server with args: $serverArgs');
+      _logger.info('About to start with server with SDK path `$sdkPath` and args: $serverArgs');
 
       _init = AnalysisServer.create(
         onRead: onRead,
@@ -94,6 +94,8 @@
         await _sendRemoveOverlays();
 
         return analysisServer;
+      }).catchError((err, st) {
+        _logger.severe('Error starting analysis server ($sdkPath): $err.\n$st');
       });
     }
 
diff --git a/lib/src/common.dart b/lib/src/common.dart
index 876289a..760abd2 100644
--- a/lib/src/common.dart
+++ b/lib/src/common.dart
@@ -9,6 +9,25 @@
 import 'sdk_manager.dart';
 
 const kMainDart = 'main.dart';
+const kBootstrapDart = 'bootstrap.dart';
+
+const kBootstrapFlutterCode = r'''
+import 'dart:ui' as ui;
+import 'main.dart' as user_code;
+
+void main() async {
+  await ui.webOnlyInitializePlatform();
+  user_code.main();
+}
+''';
+
+const kBootstrapDartCode = r'''
+import 'main.dart' as user_code;
+
+void main() {
+  user_code.main();
+}
+''';
 
 const sampleCode = '''
 void main() {
@@ -25,6 +44,28 @@
 }
 """;
 
+const sampleCodeFlutter = '''
+import 'package:flutter/material.dart';
+
+void main() async {
+  runApp(
+    MaterialApp(
+      debugShowCheckedModeBanner: false,
+      home: Scaffold(
+        appBar: AppBar(
+          title: Text('Hey there, boo!'),
+        ),
+        body: Center(
+          child: Text(
+            'You are pretty okay.',
+          ),
+        ),
+      ),
+    ),
+  );
+}
+''';
+
 const sampleCodeMultiFoo = """
 import 'bar.dart';
 
@@ -74,16 +115,6 @@
 }
 """;
 
-const sampleDart2OK = """
-class Foo {
-  String toString() => 'hello';
-}
-
-void main(List<String> argv) {
-  print (Foo());
-}
-""";
-
 const sampleDart2Error = '''
 class Foo {
   final bool isAlwaysNull;
diff --git a/lib/src/common_server.dart b/lib/src/common_server.dart
index 8fb3b85..297c32b 100644
--- a/lib/src/common_server.dart
+++ b/lib/src/common_server.dart
@@ -155,12 +155,13 @@
         });
   }
 
-  /// Build a key that includes the server version, and Dart SDK Version.
+  /// Build a key that includes the server version, Dart SDK version, and
+  /// Flutter SDK version.
   ///
-  /// We don't use the existing key directly so that different AppEngine versions
-  /// using the same redis cache do not have collisions.
+  /// We don't use the existing key directly so that different AppEngine
+  /// versions using the same redis cache do not have collisions.
   String _genKey(String key) =>
-      'server:$serverVersion:dart:${SdkManager.sdk.versionFull}+$key';
+      'server:$serverVersion:dart:${SdkManager.sdk.versionFull}:flutter:${SdkManager.flutterSdk.versionFull}+$key';
 
   @override
   Future<String> get(String key) async {
@@ -268,6 +269,7 @@
 
   Compiler compiler;
   AnalysisServerWrapper analysisServer;
+  AnalysisServerWrapper flutterAnalysisServer;
 
   CommonServer(
     this.sdkPath,
@@ -280,10 +282,19 @@
   }
 
   Future<void> init() async {
+    log.info('Beginning CommonServer init().');
     analysisServer = AnalysisServerWrapper(sdkPath, flutterWebManager);
-    compiler = Compiler(sdkPath, flutterWebManager);
+    flutterAnalysisServer = AnalysisServerWrapper(
+        flutterWebManager.flutterSdk.sdkPath, flutterWebManager);
+
+    compiler =
+        Compiler(SdkManager.sdk, SdkManager.flutterSdk, flutterWebManager);
 
     await analysisServer.init();
+    log.info('Dart analysis server initialized.');
+
+    await flutterAnalysisServer.init();
+    log.info('Flutter analysis server initialized.');
 
     unawaited(analysisServer.onExit.then((int code) {
       log.severe('analysisServer exited, code: $code');
@@ -291,12 +302,20 @@
         exit(code);
       }
     }));
+
+    unawaited(flutterAnalysisServer.onExit.then((int code) {
+      log.severe('flutterAnalysisServer exited, code: $code');
+      if (code != 0) {
+        exit(code);
+      }
+    }));
   }
 
   Future<void> warmup({bool useHtml = false}) async {
     await flutterWebManager.warmup();
     await compiler.warmup(useHtml: useHtml);
     await analysisServer.warmup(useHtml: useHtml);
+    await flutterAnalysisServer.warmup(useHtml: useHtml);
   }
 
   Future<void> restart() async {
@@ -313,6 +332,7 @@
   Future<dynamic> shutdown() {
     return Future.wait(<Future<dynamic>>[
       analysisServer.shutdown(),
+      flutterAnalysisServer.shutdown(),
       compiler.dispose(),
       Future<dynamic>.sync(cache.shutdown)
     ]);
@@ -420,7 +440,8 @@
     try {
       final Stopwatch watch = Stopwatch()..start();
 
-      AnalysisResults results = await analysisServer.analyze(source);
+      AnalysisResults results =
+          await getCorrectAnalysisServer(source).analyze(source);
       int lineCount = source.split('\n').length;
       int ms = watch.elapsedMilliseconds;
       log.info('PERF: Analyzed $lineCount lines of Dart in ${ms}ms.');
@@ -554,7 +575,7 @@
     Stopwatch watch = Stopwatch()..start();
     try {
       Map<String, String> docInfo =
-          await analysisServer.dartdoc(source, offset);
+          await getCorrectAnalysisServer(source).dartdoc(source, offset);
       docInfo ??= <String, String>{};
       log.info('PERF: Computed dartdoc in ${watch.elapsedMilliseconds}ms.');
       return DocumentResponse(docInfo);
@@ -584,7 +605,8 @@
 
     Stopwatch watch = Stopwatch()..start();
     try {
-      CompleteResponse response = await analysisServer.complete(source, offset);
+      CompleteResponse response =
+          await getCorrectAnalysisServer(source).complete(source, offset);
       log.info('PERF: Computed completions in ${watch.elapsedMilliseconds}ms.');
       return response;
     } catch (e, st) {
@@ -605,7 +627,8 @@
     await _checkPackageReferencesInitFlutterWeb(source);
 
     Stopwatch watch = Stopwatch()..start();
-    FixesResponse response = await analysisServer.getFixes(source, offset);
+    FixesResponse response =
+        await getCorrectAnalysisServer(source).getFixes(source, offset);
     log.info('PERF: Computed fixes in ${watch.elapsedMilliseconds}ms.');
     return response;
   }
@@ -621,7 +644,8 @@
     await _checkPackageReferencesInitFlutterWeb(source);
 
     Stopwatch watch = Stopwatch()..start();
-    var response = await analysisServer.getAssists(source, offset);
+    var response =
+        await getCorrectAnalysisServer(source).getAssists(source, offset);
     log.info('PERF: Computed assists in ${watch.elapsedMilliseconds}ms.');
     return response;
   }
@@ -634,7 +658,8 @@
 
     Stopwatch watch = Stopwatch()..start();
 
-    FormatResponse response = await analysisServer.format(source, offset);
+    FormatResponse response =
+        await getCorrectAnalysisServer(source).format(source, offset);
     log.info('PERF: Computed format in ${watch.elapsedMilliseconds}ms.');
     return response;
   }
@@ -646,7 +671,7 @@
 
   /// Check that the set of packages referenced is valid.
   ///
-  /// If there are uses of package:flutter_web, ensure that support there is
+  /// If there are uses of package:flutter, ensure that support there is
   /// initialized.
   Future<void> _checkPackageReferencesInitFlutterWeb(String source) async {
     Set<String> imports = getAllImportsFor(source);
@@ -660,11 +685,18 @@
       try {
         await flutterWebManager.initFlutterWeb();
       } catch (e) {
-        log.warning('unable to init package:flutter_web');
+        log.warning('unable to init package:flutter: $e');
         return;
       }
     }
   }
+
+  AnalysisServerWrapper getCorrectAnalysisServer(String source) {
+    Set<String> imports = getAllImportsFor(source);
+    return flutterWebManager.usesFlutterWeb(imports)
+        ? flutterAnalysisServer
+        : analysisServer;
+  }
 }
 
 String _printCompileProblem(CompilationProblem problem) => problem.message;
diff --git a/lib/src/compiler.dart b/lib/src/compiler.dart
index ada8d87..b2898814 100644
--- a/lib/src/compiler.dart
+++ b/lib/src/compiler.dart
@@ -22,27 +22,23 @@
 /// An interface to the dart2js compiler. A compiler object can process one
 /// compile at a time.
 class Compiler {
-  final String sdkPath;
-  final FlutterWebManager flutterWebManager;
-
+  final Sdk _sdk;
+  final FlutterSdk _flutterSdk;
+  final FlutterWebManager _flutterWebManager;
+  final String _dartdevcPath;
   final BazelWorkerDriver _ddcDriver;
-  String _sdkVersion;
 
-  Compiler(this.sdkPath, this.flutterWebManager)
-      : _ddcDriver = BazelWorkerDriver(
-            () => Process.start(path.join(sdkPath, 'bin', 'dartdevc'),
-                <String>['--persistent_worker']),
-            maxWorkers: 1) {
-    _sdkVersion = SdkManager.sdk.version;
-  }
+  Compiler(this._sdk, this._flutterSdk, this._flutterWebManager)
+      : _dartdevcPath = path.join(_flutterSdk.sdkPath, 'bin', 'dartdevc'),
+        _ddcDriver = BazelWorkerDriver(
+            () => Process.start(
+                  path.join(_flutterSdk.sdkPath, 'bin', 'dartdevc'),
+                  <String>['--persistent_worker'],
+                ),
+            maxWorkers: 1);
 
   bool importsOkForCompile(Set<String> imports) {
-    return !flutterWebManager.hasUnsupportedImport(imports);
-  }
-
-  /// The version of the SDK this copy of dart2js is based on.
-  String get version {
-    return File(path.join(sdkPath, 'version')).readAsStringSync().trim();
+    return !_flutterWebManager.hasUnsupportedImport(imports);
   }
 
   Future<CompilationResults> warmup({bool useHtml = false}) {
@@ -58,23 +54,23 @@
     if (!importsOkForCompile(imports)) {
       return CompilationResults(problems: <CompilationProblem>[
         CompilationProblem._(
-          'unsupported import: ${flutterWebManager.getUnsupportedImport(imports)}',
+          'unsupported import: ${_flutterWebManager.getUnsupportedImport(imports)}',
         ),
       ]);
     }
 
     Directory temp = await Directory.systemTemp.createTemp('dartpad');
+    _logger.info('Temp directory created: ${temp.path}');
 
     try {
       List<String> arguments = <String>[
         '--suppress-hints',
         '--terse',
+        if (!returnSourceMap) '--no-source-maps',
+        '--packages=${_flutterWebManager.packagesFilePath}',
+        ...['-o', '$kMainDart.js'],
+        kMainDart,
       ];
-      if (!returnSourceMap) arguments.add('--no-source-maps');
-
-      arguments.add('--packages=${flutterWebManager.packagesFilePath}');
-      arguments.add('-o$kMainDart.js');
-      arguments.add(kMainDart);
 
       String compileTarget = path.join(temp.path, kMainDart);
       File mainDart = File(compileTarget);
@@ -83,7 +79,7 @@
       File mainJs = File(path.join(temp.path, '$kMainDart.js'));
       File mainSourceMap = File(path.join(temp.path, '$kMainDart.js.map'));
 
-      final String dart2JSPath = path.join(sdkPath, 'bin', 'dart2js');
+      final String dart2JSPath = path.join(_sdk.sdkPath, 'bin', 'dart2js');
       _logger.info('About to exec: $dart2JSPath $arguments');
 
       ProcessResult result = await Process.run(dart2JSPath, arguments,
@@ -121,38 +117,48 @@
     if (!importsOkForCompile(imports)) {
       return DDCCompilationResults.failed(<CompilationProblem>[
         CompilationProblem._(
-          'unsupported import: ${flutterWebManager.getUnsupportedImport(imports)}',
+          'unsupported import: ${_flutterWebManager.getUnsupportedImport(imports)}',
         ),
       ]);
     }
 
     Directory temp = await Directory.systemTemp.createTemp('dartpad');
+    _logger.info('Temp directory created: ${temp.path}');
 
     try {
+      final usingFlutter = _flutterWebManager.usesFlutterWeb(imports);
+
+      final mainPath = path.join(temp.path, kMainDart);
+      final bootstrapPath = path.join(temp.path, kBootstrapDart);
+      final bootstrapContents =
+          usingFlutter ? kBootstrapFlutterCode : kBootstrapDartCode;
+
+      await File(bootstrapPath).writeAsString(bootstrapContents);
+      await File(mainPath).writeAsString(input);
+
       List<String> arguments = <String>[
         '--modules=amd',
+        if (usingFlutter) ...[
+          '-k',
+          '-s',
+          _flutterWebManager.summaryFilePath,
+          '-s',
+          '${_flutterSdk.flutterBinPath}/cache/flutter_web_sdk/flutter_web_sdk/kernel/flutter_ddc_sdk.dill'
+        ],
+        ...['-o', path.join(temp.path, '$kMainDart.js')],
+        '--single-out-file',
+        ...['--module-name', 'dartpad_main'],
+        bootstrapPath,
+        '--packages=${_flutterWebManager.packagesFilePath}',
       ];
 
-      if (flutterWebManager.usesFlutterWeb(imports)) {
-        arguments.addAll(<String>['-s', flutterWebManager.summaryFilePath]);
-      }
-
-      String compileTarget = path.join(temp.path, kMainDart);
-      File mainDart = File(compileTarget);
-      await mainDart.writeAsString(input);
-
-      arguments.addAll(<String>['-o', path.join(temp.path, '$kMainDart.js')]);
-      arguments.add('--single-out-file');
-      arguments.addAll(<String>['--module-name', 'dartpad_main']);
-      arguments.add(compileTarget);
-      arguments.addAll(<String>['--library-root', temp.path]);
-
       File mainJs = File(path.join(temp.path, '$kMainDart.js'));
 
-      _logger.info('About to exec dartdevc with:  $arguments');
+      _logger.info('About to exec "$_dartdevcPath ${arguments.join(' ')}"');
+      _logger.info('Compiling: $input');
 
-      final WorkResponse response =
-          await _ddcDriver.doWork(WorkRequest()..arguments.addAll(arguments));
+      final WorkResponse response = await _ddcDriver
+          .doWork(WorkRequest()..arguments.addAll(arguments));
 
       if (response.exitCode != 0) {
         return DDCCompilationResults.failed(<CompilationProblem>[
@@ -162,7 +168,7 @@
         final DDCCompilationResults results = DDCCompilationResults(
           compiledJS: await mainJs.readAsString(),
           modulesBaseUrl: 'https://storage.googleapis.com/'
-              'compilation_artifacts/$_sdkVersion/',
+              'compilation_artifacts/${_flutterSdk.versionFull}/',
         );
         return results;
       }
@@ -218,6 +224,7 @@
 
   /// This is true if there were no errors.
   bool get success => problems.isEmpty;
+
   @override
   String toString() => success
       ? 'CompilationResults: Success'
diff --git a/lib/src/flutter_web.dart b/lib/src/flutter_web.dart
index 612a015..90d3561 100644
--- a/lib/src/flutter_web.dart
+++ b/lib/src/flutter_web.dart
@@ -15,13 +15,13 @@
 
 /// Handle provisioning package:flutter_web and related work.
 class FlutterWebManager {
-  final String sdkPath;
+  final FlutterSdk flutterSdk;
 
   Directory _projectDirectory;
 
   bool _initedFlutterWeb = false;
 
-  FlutterWebManager(this.sdkPath) {
+  FlutterWebManager(this.flutterSdk) {
     _projectDirectory = Directory.systemTemp.createTempSync('dartpad');
     _init();
   }
@@ -36,7 +36,7 @@
 
   void _init() {
     // create a pubspec.yaml file
-    String pubspec = createPubspec(false);
+    String pubspec = createPubspec(true);
     File(path.join(_projectDirectory.path, 'pubspec.yaml'))
         .writeAsStringSync(pubspec);
 
@@ -71,26 +71,29 @@
 
     await _runPubGet();
 
-    final String sdkVersion = SdkManager.sdk.version;
+    final String sdkVersion = flutterSdk.versionFull;
 
-    // download and save the flutter_web.sum file
+    // Download and save the flutter_web.dill file.
     String url = 'https://storage.googleapis.com/compilation_artifacts/'
-        '$sdkVersion/flutter_web.sum';
+        '$sdkVersion/flutter_web.dill';
+
+    _logger.info('Attempting download of $url');
+
     Uint8List summaryContents = await http.readBytes(url);
-    await File(path.join(_projectDirectory.path, 'flutter_web.sum'))
+    await File(path.join(_projectDirectory.path, 'flutter_web.dill'))
         .writeAsBytes(summaryContents);
 
+    _logger.info('Wrote flutter_web.dill');
+
     _initedFlutterWeb = true;
   }
 
   String get summaryFilePath {
-    return path.join(_projectDirectory.path, 'flutter_web.sum');
+    return path.join(_projectDirectory.path, 'flutter_web.dill');
   }
 
   static final Set<String> _flutterWebImportPrefixes = <String>{
-    'package:flutter_web',
-    'package:flutter_web_ui',
-    'package:flutter_web_test',
+    'package:flutter',
   };
 
   bool usesFlutterWeb(Set<String> imports) {
@@ -106,9 +109,6 @@
   }
 
   String getUnsupportedImport(Set<String> imports) {
-    // TODO(devoncarew): Should we support a white-listed set of package:
-    // imports?
-
     for (String import in imports) {
       // All dart: imports are ok;
       if (import.startsWith('dart:')) {
@@ -133,24 +133,62 @@
   }
 
   Future<void> _runPubGet() async {
-    _logger.info('running pub get (${_projectDirectory.path})');
+    _logger.info('running flutter pub get (${_projectDirectory.path})');
 
-    ProcessResult result = await Process.run(
-      path.join(sdkPath, 'bin', 'pub'),
-      <String>['get', '--no-precompile'],
+    final observatoryPort = await _findFreePort();
+
+    // The DART_VM_OPTIONS flag is included here to override the one sent by the
+    // Dart SDK during tests. Without the flag, the Flutter tool will attempt to
+    // spin up its own observatory on the same port as the one already
+    // instantiated by the Dart SDK running the test, causing a hang.
+    //
+    // The value should be an available port number.
+    final result = await Process.start(
+      path.join(flutterSdk.flutterBinPath, 'flutter'),
+      ['pub', 'get'],
       workingDirectory: _projectDirectory.path,
+      environment: {'DART_VM_OPTIONS': '--enable-vm-service=$observatoryPort'},
     );
 
     _logger.info('${result.stdout}'.trim());
 
-    if (result.exitCode != 0) {
+    final code = await result.exitCode;
+
+    if (code != 0) {
       _logger.warning('pub get failed: ${result.exitCode}');
       _logger.warning(result.stderr);
 
-      throw 'pub get failed: ${result.exitCode}';
+      throw 'pub get failed: ${result.exitCode}: ${result.stderr}';
     }
   }
 
+  Future<int> _findFreePort({bool ipv6 = false}) async {
+    var port = 0;
+    ServerSocket serverSocket;
+    final InternetAddress loopback =
+        ipv6 ? InternetAddress.loopbackIPv6 : InternetAddress.loopbackIPv4;
+
+    try {
+      serverSocket = await ServerSocket.bind(loopback, 0);
+      port = serverSocket.port;
+    } on SocketException catch (e) {
+      // If ipv4 loopback bind fails, try ipv6.
+      if (!ipv6) {
+        return _findFreePort(ipv6: true);
+      }
+      _logger.severe('Could not find free port for `pub get`: $e');
+    } catch (e) {
+      // Failures are signaled by a return value of 0 from this function.
+      _logger.severe('Could not find free port for `pub get`: $e');
+    } finally {
+      if (serverSocket != null) {
+        await serverSocket.close();
+      }
+    }
+
+    return port;
+  }
+
   static const String _samplePackageName = 'dartpad_sample';
 
   static String createPubspec(bool includeFlutterWeb) {
@@ -161,25 +199,10 @@
     if (includeFlutterWeb) {
       content += '''
 dependencies:
-  flutter_web:
-    git:
-      url: https://github.com/flutter/flutter_web
-      path: packages/flutter_web
-  flutter_web_test:
-    git:
-      url: https://github.com/flutter/flutter_web
-      path: packages/flutter_web_test
-  flutter_web_ui:
-    git:
-      url: https://github.com/flutter/flutter_web
-      path: packages/flutter_web_ui
-dependency_overrides:
-  flutter_web:
-    path: ${Directory.current.path}/flutter_web/packages/flutter_web
-  flutter_web_test:
-    path: ${Directory.current.path}/flutter_web/packages/flutter_web_test
-  flutter_web_ui:
-    path: ${Directory.current.path}/flutter_web/packages/flutter_web_ui
+  flutter:
+    sdk: flutter
+  flutter_test:
+    sdk: flutter
 ''';
     }
 
diff --git a/lib/src/sdk_manager.dart b/lib/src/sdk_manager.dart
index be63403..b1757f7 100644
--- a/lib/src/sdk_manager.dart
+++ b/lib/src/sdk_manager.dart
@@ -11,11 +11,21 @@
 class SdkManager {
   static Sdk get sdk => _sdk ?? (_sdk = PlatformSdk());
 
+  static FlutterSdk get flutterSdk => _flutterSdk ?? (_flutterSdk = FlutterSdk());
+
   static void setSdk(Sdk value) {
     _sdk = sdk;
   }
 
+  static void setFlutterSdk(FlutterSdk value) {
+    _flutterSdk = value;
+  }
+
+  // The installed Dart SDK.
   static Sdk _sdk;
+
+  // The installed Flutter SDK.
+  static FlutterSdk _flutterSdk;
 }
 
 abstract class Sdk {
@@ -37,6 +47,7 @@
   String get sdkPath;
 }
 
+/// Represents a Dart SDK present on the server.
 class PlatformSdk extends Sdk {
   String _versionFull = '';
 
@@ -44,7 +55,6 @@
   Future<void> init() async {
     _versionFull =
         (await File(path.join(sdkPath, 'version')).readAsString()).trim();
-    return;
   }
 
   @override
@@ -53,3 +63,25 @@
   @override
   String get sdkPath => path.dirname(path.dirname(Platform.resolvedExecutable));
 }
+
+/// Represents a Flutter SDK installation (which includes its own version of the
+/// Dart SDK) present on the server.
+///
+/// This class assumes the Flutter SDK is available at `./flutter`.
+class FlutterSdk extends Sdk {
+  String _versionFull = '';
+
+  @override
+  Future<void> init() async {
+    _versionFull =
+        (await File(path.join(sdkPath, 'version')).readAsString()).trim();
+  }
+
+  @override
+  String get sdkPath => path.join(flutterBinPath, 'cache/dart-sdk');
+
+  String get flutterBinPath => path.join(Directory.current.path, 'flutter/bin');
+
+  @override
+  String get versionFull => _versionFull;
+}
diff --git a/pubspec.lock b/pubspec.lock
index d5985f6..0e3a5f9 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -548,4 +548,4 @@
     source: hosted
     version: "2.2.0"
 sdks:
-  dart: ">=2.6.0-dev.8.2 <3.0.0"
+  dart: ">=2.6.0 <3.0.0"
diff --git a/test/analysis_server_test.dart b/test/analysis_server_test.dart
index cd749bd..0f7bda2 100644
--- a/test/analysis_server_test.dart
+++ b/test/analysis_server_test.dart
@@ -8,6 +8,7 @@
 import 'package:dart_services/src/api_classes.dart';
 import 'package:dart_services/src/common.dart';
 import 'package:dart_services/src/flutter_web.dart';
+import 'package:dart_services/src/sdk_manager.dart';
 import 'package:test/test.dart';
 
 const completionCode = r'''
@@ -63,9 +64,9 @@
   AnalysisServerWrapper analysisServer;
   FlutterWebManager flutterWebManager;
 
-  group('analysis_server', () {
+  group('Platform SDK analysis_server', () {
     setUp(() async {
-      flutterWebManager = FlutterWebManager(sdkPath);
+      flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
       analysisServer = AnalysisServerWrapper(sdkPath, flutterWebManager);
       await analysisServer.init();
     });
@@ -179,18 +180,6 @@
       expect(issue.kind, 'error');
     });
 
-    test('analyze dart-2', () async {
-      await analysisServer.shutdown();
-
-      flutterWebManager = FlutterWebManager(sdkPath);
-
-      analysisServer = AnalysisServerWrapper(sdkPath, flutterWebManager);
-      await analysisServer.init();
-
-      AnalysisResults results = await analysisServer.analyze(sampleDart2OK);
-      expect(results.issues, hasLength(0));
-    });
-
     test('filter completions', () async {
       // just after A
       var idx = 61;
@@ -204,6 +193,26 @@
       expect(completionsContains(results, 'ZZ'), false);
     });
   });
+
+  group('Flutter cached SDK analysis_server', () {
+    setUp(() async {
+      flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
+      analysisServer = AnalysisServerWrapper(SdkManager.flutterSdk.sdkPath, flutterWebManager);
+      await analysisServer.init();
+    });
+
+    tearDown(() => analysisServer.shutdown());
+
+    test('analyze working Dart code', () async {
+      AnalysisResults results = await analysisServer.analyze(sampleCode);
+      expect(results.issues, isEmpty);
+    });
+
+    test('analyze working Flutter code', () async {
+      AnalysisResults results = await analysisServer.analyze(sampleCode);
+      expect(results.issues, isEmpty);
+    });
+  });
 }
 
 bool completionsContains(CompleteResponse response, String completion) =>
diff --git a/test/common_server_test.dart b/test/common_server_test.dart
index a299cd1..284bf20 100644
--- a/test/common_server_test.dart
+++ b/test/common_server_test.dart
@@ -298,7 +298,7 @@
     setUpAll(() async {
       container = MockContainer();
       cache = MockCache();
-      flutterWebManager = FlutterWebManager(sdkPath);
+      flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
 
       server = CommonServer(sdkPath, flutterWebManager, container, cache);
       await server.init();
@@ -338,16 +338,26 @@
 
     tearDown(log.clearListeners);
 
-    test('analyze', () async {
+    test('analyze Dart', () async {
       var jsonData = {'source': sampleCode};
       var response =
-          await _sendPostRequest('dartservices/v1/analyze', jsonData);
+      await _sendPostRequest('dartservices/v1/analyze', jsonData);
       expect(response.status, 200);
       var data = await response.body.first;
       expect(
           json.decode(utf8.decode(data)), {'issues': [], 'packageImports': []});
     });
 
+    test('analyze Flutter', () async {
+      var jsonData = {'source': sampleCodeFlutter};
+      var response =
+      await _sendPostRequest('dartservices/v1/analyze', jsonData);
+      expect(response.status, 200);
+      var data = await response.body.first;
+      expect(
+          json.decode(utf8.decode(data)), {'issues': [], 'packageImports': ['flutter']});
+    });
+
     test('analyze errors', () async {
       var jsonData = {'source': sampleCodeError};
       var response =
diff --git a/test/compiler_test.dart b/test/compiler_test.dart
index ba27522..a9afa97 100644
--- a/test/compiler_test.dart
+++ b/test/compiler_test.dart
@@ -7,6 +7,7 @@
 import 'package:dart_services/src/common.dart';
 import 'package:dart_services/src/compiler.dart';
 import 'package:dart_services/src/flutter_web.dart';
+import 'package:dart_services/src/sdk_manager.dart';
 import 'package:test/test.dart';
 
 void main() => defineTests();
@@ -17,9 +18,14 @@
 
   group('compiler', () {
     setUpAll(() async {
-      flutterWebManager = FlutterWebManager(sdkPath);
+      await SdkManager.sdk.init();
+      await SdkManager.flutterSdk.init();
 
-      compiler = Compiler(sdkPath, flutterWebManager);
+      flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
+      await flutterWebManager.initFlutterWeb();
+
+      compiler =
+          Compiler(SdkManager.sdk, SdkManager.flutterSdk, flutterWebManager);
     });
 
     tearDownAll(() async {
@@ -60,6 +66,20 @@
       });
     });
 
+    test('compileDDC with Flutter', () {
+      return compiler
+          .compileDDC(sampleCodeFlutter)
+          .then((DDCCompilationResults result) {
+        print(result.problems);
+
+        expect(result.success, true);
+        expect(result.compiledJS, isNotEmpty);
+        expect(result.modulesBaseUrl, isNotEmpty);
+
+        expect(result.compiledJS, contains("define('dartpad_main', ["));
+      });
+    });
+
     test('compileDDC with async', () {
       return compiler
           .compileDDC(sampleCodeAsync)
@@ -113,8 +133,6 @@
       return compiler
           .compile(sampleCode, returnSourceMap: true)
           .then((CompilationResults result) {
-        expect(compiler.version, isNotNull);
-        expect(compiler.version, startsWith('2.'));
         expect(result.sourceMap, isNotNull);
         expect(result.sourceMap, isNotEmpty);
       });
diff --git a/test/flutter_web_test.dart b/test/flutter_web_test.dart
index 3c5839f..069842e 100644
--- a/test/flutter_web_test.dart
+++ b/test/flutter_web_test.dart
@@ -4,7 +4,6 @@
 
 import 'dart:io';
 
-import 'package:dart_services/src/common.dart';
 import 'package:dart_services/src/flutter_web.dart';
 import 'package:dart_services/src/sdk_manager.dart';
 import 'package:test/test.dart';
@@ -17,7 +16,8 @@
 
     setUp(() async {
       await SdkManager.sdk.init();
-      flutterWebManager = FlutterWebManager(sdkPath);
+      await SdkManager.flutterSdk.init();
+      flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
     });
 
     tearDown(() {
@@ -53,7 +53,9 @@
     FlutterWebManager flutterWebManager;
 
     setUpAll(() async {
-      flutterWebManager = FlutterWebManager(sdkPath);
+      await SdkManager.sdk.init();
+      await SdkManager.flutterSdk.init();
+      flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
       await flutterWebManager.initFlutterWeb();
     });
 
@@ -67,7 +69,7 @@
 
       File file = File(packagesPath);
       List<String> lines = file.readAsLinesSync();
-      expect(lines, anyElement(startsWith('flutter_web:file://')));
+      expect(lines, anyElement(startsWith('flutter:file://')));
     });
 
     test('summaryFilePath', () {
diff --git a/third_party/pkg/README b/third_party/pkg/README
deleted file mode 100644
index db43505..0000000
--- a/third_party/pkg/README
+++ /dev/null
@@ -1,2 +0,0 @@
-Place dependency overrides here if it is necessary
-to deploy a dart-services with them.
diff --git a/tool/fuzz_driver.dart b/tool/fuzz_driver.dart
index 01cfe5e..3d6471e 100644
--- a/tool/fuzz_driver.dart
+++ b/tool/fuzz_driver.dart
@@ -18,6 +18,7 @@
 import 'package:dart_services/src/common_server.dart';
 import 'package:dart_services/src/compiler.dart' as comp;
 import 'package:dart_services/src/flutter_web.dart';
+import 'package:dart_services/src/sdk_manager.dart';
 import 'package:rpc/rpc.dart';
 
 bool _SERVER_BASED_CALL = false;
@@ -123,7 +124,7 @@
 
   print('SdKPath: $sdkPath');
 
-  FlutterWebManager flutterWebManager = FlutterWebManager(sdkPath);
+  FlutterWebManager flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
 
   container = MockContainer();
   cache = MockCache();
@@ -140,7 +141,7 @@
   await analysisServer.warmup();
 
   print('Warming up compiler');
-  compiler = comp.Compiler(sdkPath, flutterWebManager);
+  compiler = comp.Compiler(SdkManager.sdk, SdkManager.flutterSdk, flutterWebManager);
   await compiler.warmup();
   print('SetupTools done');
 }
diff --git a/tool/grind.dart b/tool/grind.dart
index c080350..437dc5f 100644
--- a/tool/grind.dart
+++ b/tool/grind.dart
@@ -12,9 +12,11 @@
 import 'package:grinder/grinder.dart';
 import 'package:grinder/grinder_files.dart';
 import 'package:http/http.dart' as http;
+import 'package:path/path.dart' as path;
 
 Future<void> main(List<String> args) async {
   await SdkManager.sdk.init();
+  await SdkManager.flutterSdk.init();
   return grind(args);
 }
 
@@ -33,7 +35,7 @@
 @Task()
 void serve() {
   // You can run the `grind serve` command, or just run
-  // `dart bin/server_dev.dart --port 8002` locally.
+  // `dart bin/server_dev.dart --port 8082` locally.
 
   Process.runSync(
       Platform.executable, ['bin/server_dev.dart', '--port', '8082']);
@@ -59,13 +61,13 @@
 final List<String> compilationArtifacts = [
   'dart_sdk.js',
   'flutter_web.js',
-  'flutter_web.sum',
+  'flutter_web.dill',
 ];
 
 @Task('validate that we have the correct compilation artifacts available in '
     'google storage')
 void validateStorageArtifacts() async {
-  String version = SdkManager.sdk.version;
+  String version = SdkManager.flutterSdk.versionFull;
 
   const String urlBase =
       'https://storage.googleapis.com/compilation_artifacts/';
@@ -89,7 +91,7 @@
 
 @Task('build the sdk compilation artifacts for upload to google storage')
 void buildStorageArtifacts() {
-  // build and copy dart_sdk.js, flutter_web.js, and flutter_web.sum
+  // build and copy dart_sdk.js, flutter_web.js, and flutter_web.dill
   final Directory temp =
       Directory.systemTemp.createTempSync('flutter_web_sample');
 
@@ -101,18 +103,20 @@
 }
 
 void _buildStorageArtifacts(Directory dir) {
+  final flutterSdkPath =
+      Directory(path.join(Directory.current.path, 'flutter'));
   String pubspec = FlutterWebManager.createPubspec(true);
   joinFile(dir, ['pubspec.yaml']).writeAsStringSync(pubspec);
 
-  // run pub get
-  Pub.get(workingDirectory: dir.path);
+  // run flutter pub get
+  run(
+    path.join(flutterSdkPath.path, 'bin/flutter'),
+    arguments: ['pub', 'get'],
+    workingDirectory: dir.path,
+  );
 
   // locate the artifacts
-  final List<String> flutterPackages = [
-    'flutter_web',
-    'flutter_web_ui',
-    'flutter_web_test',
-  ];
+  final List<String> flutterPackages = ['flutter', 'flutter_test'];
 
   List<String> flutterLibraries = [];
   List<String> packageLines = joinFile(dir, ['.packages']).readAsLinesSync();
@@ -139,34 +143,56 @@
     }
   }
 
-  // build the artifacts using DDC
-  // dartdevc --modules=amd -o flutter_web.js package:flutter_web/animation.dart ...
+  // Make sure flutter/bin/cache/flutter_web_sdk/flutter_web_sdk/kernel/flutter_ddc_sdk.dill
+  // is installed.
   run(
-    'dartdevc',
-    arguments: [
-      '--modules=amd',
-      '-o',
-      'flutter_web.js',
-    ]..addAll(flutterLibraries),
+    path.join(flutterSdkPath.path, 'bin/flutter'),
+    arguments: ['precache', '--web'],
     workingDirectory: dir.path,
   );
 
-  // copy them to the project dir
-  Directory artifactsDir = getDir('artifacts');
+  // Build the artifacts using DDC:
+  // dart-sdk/bin/dartdevc -k -s kernel/flutter_ddc_sdk.dill
+  //     --modules=amd package:flutter_web/animation.dart ...
+  final compilerPath =
+      path.join(flutterSdkPath.path, 'bin/cache/dart-sdk/bin/dartdevc');
+  final dillPath = path.join(flutterSdkPath.path,
+      'bin/cache/flutter_web_sdk/flutter_web_sdk/kernel/flutter_ddc_sdk.dill');
+
+  var args = [
+    '-k',
+    '-s',
+    dillPath,
+    '--modules=amd',
+    '-o',
+    'flutter_web.js',
+    ...flutterLibraries
+  ];
+
+  run(
+    compilerPath,
+    arguments: args,
+    workingDirectory: dir.path,
+  );
+
+  // Copy both to the project directory.
+  final artifactsDir = getDir('artifacts');
   artifactsDir.create();
 
-  copy(getFile('${SdkManager.sdk.sdkPath}/lib/dev_compiler/amd/dart_sdk.js'),
-      artifactsDir);
-  copy(joinFile(dir, ['flutter_web.js']), artifactsDir);
-  copy(joinFile(dir, ['flutter_web.sum']), artifactsDir);
+  final sdkJsPath = path.join(flutterSdkPath.path,
+      'bin/cache/flutter_web_sdk/flutter_web_sdk/kernel/amd/dart_sdk.js');
 
-  // emit some good google storage upload instructions
-  final String version = SdkManager.sdk.version;
+  copy(getFile(sdkJsPath), artifactsDir);
+  copy(joinFile(dir, ['flutter_web.js']), artifactsDir);
+  copy(joinFile(dir, ['flutter_web.dill']), artifactsDir);
+
+  // Emit some good google storage upload instructions.
+  final String version = SdkManager.flutterSdk.versionFull;
   log('\nFrom the dart-services project root dir, run:');
   log('  gsutil -h "Cache-Control:public, max-age=86400" cp -z js '
       'artifacts/*.js gs://compilation_artifacts/$version/');
-  log('  gsutil -h "Cache-Control:public, max-age=86400" cp -z sum '
-      'artifacts/*.sum gs://compilation_artifacts/$version/');
+  log('  gsutil -h "Cache-Control:public, max-age=86400" cp -z dill '
+      'artifacts/*.dill gs://compilation_artifacts/$version/');
 }
 
 @Task()