Revert "Lazily download artifacts (III) (#27903)" (#29064)

This reverts commit 3fd36200d9b89322d75c1b6bad37b3ad7f665b81.
diff --git a/packages/flutter_tools/bin/fuchsia_attach.dart b/packages/flutter_tools/bin/fuchsia_attach.dart
index 30840c4..eb91c2d 100644
--- a/packages/flutter_tools/bin/fuchsia_attach.dart
+++ b/packages/flutter_tools/bin/fuchsia_attach.dart
@@ -134,7 +134,4 @@
     Cache.flutterRoot = '$originalWorkingDirectory/third_party/dart-pkg/git/flutter';
     return super.runCommand();
   }
-
-  @override
-  Future<void> updateCache() async {}
 }
diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh
index 89810c9..1bf2310 100755
--- a/packages/flutter_tools/bin/xcode_backend.sh
+++ b/packages/flutter_tools/bin/xcode_backend.sh
@@ -84,6 +84,7 @@
 
   local framework_path="${FLUTTER_ROOT}/bin/cache/artifacts/engine/${artifact_variant}"
 
+  AssertExists "${framework_path}"
   AssertExists "${project_path}"
 
   local derived_dir="${SOURCE_ROOT}/Flutter"
@@ -122,12 +123,6 @@
     flutter_podspec="${FLUTTER_ENGINE}/out/${LOCAL_ENGINE}/Flutter.podspec"
   fi
 
-  # If the framework path does not exist, ensure that it is downloaded.
-  if [[ ! -e "$1" ]]; then
-    FLUTTER_ALREADY_LOCKED = "true"
-    RunCommand "${FLUTTER_ROOT}/bin/flutter" precache --suppress-analytics
-  fi
-
   if [[ -e "${project_path}/.ios" ]]; then
     RunCommand rm -rf -- "${derived_dir}/engine"
     mkdir "${derived_dir}/engine"
diff --git a/packages/flutter_tools/lib/src/base/net.dart b/packages/flutter_tools/lib/src/base/net.dart
index 788a0d4..742bd8b 100644
--- a/packages/flutter_tools/lib/src/base/net.dart
+++ b/packages/flutter_tools/lib/src/base/net.dart
@@ -37,8 +37,7 @@
   printTrace('Downloading: $url');
   HttpClient httpClient;
   if (context[HttpClientFactory] != null) {
-    final HttpClientFactory httpClientFactory = context[HttpClientFactory];
-    httpClient = httpClientFactory();
+    httpClient = (context[HttpClientFactory] as HttpClientFactory)(); // ignore: avoid_as
   } else {
     httpClient = HttpClient();
   }
@@ -65,9 +64,9 @@
   // If we're making a HEAD request, we're only checking to see if the URL is
   // valid.
   if (onlyHeaders) {
-    return (response.statusCode == HttpStatus.ok) ? <int>[] : null;
+    return (response.statusCode == 200) ? <int>[] : null;
   }
-  if (response.statusCode != HttpStatus.ok) {
+  if (response.statusCode != 200) {
     if (response.statusCode > 0 && response.statusCode < 500) {
       throwToolExit(
         'Download failed.\n'
diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart
index 772a006..7f3aa7a 100644
--- a/packages/flutter_tools/lib/src/cache.dart
+++ b/packages/flutter_tools/lib/src/cache.dart
@@ -13,7 +13,6 @@
 import 'base/net.dart';
 import 'base/os.dart';
 import 'base/platform.dart';
-import 'build_info.dart';
 import 'globals.dart';
 
 /// A wrapper around the `bin/cache/` directory.
@@ -188,24 +187,7 @@
     return isOlderThanReference(entity: entity, referenceFile: flutterToolsStamp);
   }
 
-  UpdateResult isUpToDate({
-    List<BuildMode> buildModes = const <BuildMode>[],
-    List<TargetPlatform> targetPlatforms = const <TargetPlatform>[],
-    bool skipUnknown = true,
-  }) {
-    bool isUpToDate = true;
-    bool clobber = false;
-    for (CachedArtifact artifact in _artifacts) {
-      final UpdateResult result =  artifact.isUpToDate(
-        buildModes: buildModes,
-        targetPlatforms: targetPlatforms,
-        skipUnknown: skipUnknown,
-      );
-      isUpToDate &= result.isUpToDate;
-      clobber |= result.clobber;
-    }
-    return UpdateResult(isUpToDate: isUpToDate, clobber: clobber);
-  }
+  bool isUpToDate() => _artifacts.every((CachedArtifact artifact) => artifact.isUpToDate());
 
   Future<String> getThirdPartyFile(String urlStr, String serviceName) async {
     final Uri url = Uri.parse(urlStr);
@@ -228,40 +210,13 @@
     return cachedFile.path;
   }
 
-  Future<void> updateAll({
-    List<BuildMode> buildModes = const <BuildMode>[],
-    List<TargetPlatform> targetPlatforms = const <TargetPlatform>[],
-    bool skipUnknown = true,
-    bool clobber = false,
-  }) async {
-    if (!_lockEnabled) {
+  Future<void> updateAll() async {
+    if (!_lockEnabled)
       return;
-    }
     try {
       for (CachedArtifact artifact in _artifacts) {
-        bool localClobber = clobber;
-        if (localClobber) {
-          await artifact.update(
-            buildModes: buildModes,
-            targetPlatforms: targetPlatforms,
-            skipUnknown: skipUnknown,
-            clobber: localClobber,
-          );
-        }
-        final UpdateResult result = artifact.isUpToDate(
-          buildModes: buildModes,
-          targetPlatforms: targetPlatforms,
-          skipUnknown: skipUnknown,
-        );
-        localClobber |= result.clobber;
-        if (localClobber || !result.isUpToDate) {
-          await artifact.update(
-            buildModes: buildModes,
-            targetPlatforms: targetPlatforms,
-            skipUnknown: skipUnknown,
-            clobber: localClobber,
-          );
-        }
+        if (!artifact.isUpToDate())
+          await artifact.update();
       }
     } on SocketException catch (e) {
       if (_hostsBlockedInChina.contains(e.address?.host)) {
@@ -277,15 +232,6 @@
   }
 }
 
-class UpdateResult {
-  const UpdateResult({this.isUpToDate, this.clobber = false});
-
-  /// Whether the artifact exists and is the correct version.
-  final bool isUpToDate;
-  /// Whether the artifact needs to be redownloaded.
-  final bool clobber;
-}
-
 /// An artifact managed by the cache.
 abstract class CachedArtifact {
   CachedArtifact(this.name, this.cache);
@@ -302,39 +248,19 @@
   /// starting from scratch.
   final List<File> _downloadedFiles = <File>[];
 
-  @mustCallSuper
-  UpdateResult isUpToDate({
-    List<BuildMode> buildModes = const <BuildMode>[],
-    List<TargetPlatform> targetPlatforms = const <TargetPlatform>[],
-    bool skipUnknown = true,
-  }) {
-    if (!location.existsSync()) {
-      return const UpdateResult(isUpToDate: false, clobber: false);
-    }
-    if (version != cache.getStampFor(name)) {
-      return const UpdateResult(isUpToDate: false, clobber: true);
-    }
-    return const UpdateResult(isUpToDate: true, clobber: false);
+  bool isUpToDate() {
+    if (!location.existsSync())
+      return false;
+    if (version != cache.getStampFor(name))
+      return false;
+    return isUpToDateInner();
   }
 
-  Future<void> update({
-    List<BuildMode> buildModes,
-    List<TargetPlatform> targetPlatforms,
-    bool skipUnknown = true,
-    bool clobber = false,
-  }) async {
-    if (location.existsSync() && clobber) {
+  Future<void> update() async {
+    if (location.existsSync())
       location.deleteSync(recursive: true);
-    }
-    if (!location.existsSync()) {
-      location.createSync(recursive: true);
-    }
-    await updateInner(
-      buildModes: buildModes,
-      targetPlatforms: targetPlatforms,
-      skipUnknown: skipUnknown,
-      clobber: clobber,
-    );
+    location.createSync(recursive: true);
+    await updateInner();
     cache.setStampFor(name, version);
     _removeDownloadedFiles();
   }
@@ -342,9 +268,6 @@
   /// Clear any zip/gzip files downloaded.
   void _removeDownloadedFiles() {
     for (File f in _downloadedFiles) {
-      if (!f.existsSync()) {
-        continue;
-      }
       f.deleteSync();
       for (Directory d = f.parent; d.absolute.path != cache.getDownloadDir().absolute.path; d = d.parent) {
         if (d.listSync().isEmpty) {
@@ -356,13 +279,11 @@
     }
   }
 
+  /// Hook method for extra checks for being up-to-date.
+  bool isUpToDateInner() => true;
+
   /// Template method to perform artifact update.
-  Future<void> updateInner({
-    @required List<BuildMode> buildModes,
-    @required List<TargetPlatform> targetPlatforms,
-    @required bool skipUnknown,
-    @required bool clobber,
-  });
+  Future<void> updateInner();
 
   String get _storageBaseUrl {
     final String overrideUrl = platform.environment['FLUTTER_STORAGE_BASE_URL'];
@@ -430,16 +351,9 @@
   MaterialFonts(Cache cache) : super('material_fonts', cache);
 
   @override
-  Future<void> updateInner({
-    List<BuildMode> buildModes,
-    List<TargetPlatform> targetPlatforms,
-    bool skipUnknown,
-    bool clobber,
-  }) async {
+  Future<void> updateInner() {
     final Uri archiveUri = _toStorageUri(version);
-    if (fs.directory(location).listSync().isEmpty || clobber) {
-      await _downloadZipArchive('Downloading Material fonts...', archiveUri, location);
-    }
+    return _downloadZipArchive('Downloading Material fonts...', archiveUri, location);
   }
 }
 
@@ -447,387 +361,100 @@
 class FlutterEngine extends CachedArtifact {
   FlutterEngine(Cache cache) : super('engine', cache);
 
-  // Return a list of [BinaryArtifact]s to download.
-  @visibleForTesting
-  List<BinaryArtifact> getBinaryDirs({
-    @required List<BuildMode> buildModes,
-    @required List<TargetPlatform> targetPlatforms,
-    @required bool skipUnknown,
-  }) {
-    TargetPlatform hostPlatform;
-    if (cache.includeAllPlatforms) {
-      hostPlatform = null;
-    } if (platform.isMacOS) {
-      hostPlatform = TargetPlatform.darwin_x64;
-    } else if (platform.isLinux) {
-      hostPlatform = TargetPlatform.linux_x64;
-    } else if (platform.isWindows) {
-      hostPlatform = TargetPlatform.windows_x64;
-    }
-    final List<BinaryArtifact> results = _reduceEngineBinaries(
-      buildModes: buildModes,
-      targetPlatforms: targetPlatforms,
-      hostPlatform: hostPlatform,
-      skipUnknown: skipUnknown,
-    ).toList();
-    if (cache.includeAllPlatforms) {
-      return results + _dartSdks;
-    }
-    return results;
+  List<String> _getPackageDirs() => const <String>['sky_engine'];
+
+  // Return a list of (cache directory path, download URL path) tuples.
+  List<List<String>> _getBinaryDirs() {
+    final List<List<String>> binaryDirs = <List<String>>[];
+
+    binaryDirs.add(<String>['common', 'flutter_patched_sdk.zip']);
+
+    if (cache.includeAllPlatforms)
+      binaryDirs
+        ..addAll(_osxBinaryDirs)
+        ..addAll(_linuxBinaryDirs)
+        ..addAll(_windowsBinaryDirs)
+        ..addAll(_androidBinaryDirs)
+        ..addAll(_iosBinaryDirs)
+        ..addAll(_dartSdks);
+    else if (platform.isLinux)
+      binaryDirs
+        ..addAll(_linuxBinaryDirs)
+        ..addAll(_androidBinaryDirs);
+    else if (platform.isMacOS)
+      binaryDirs
+        ..addAll(_osxBinaryDirs)
+        ..addAll(_androidBinaryDirs)
+        ..addAll(_iosBinaryDirs);
+    else if (platform.isWindows)
+      binaryDirs
+        ..addAll(_windowsBinaryDirs)
+        ..addAll(_androidBinaryDirs);
+
+    return binaryDirs;
   }
 
-  Iterable<BinaryArtifact> _reduceEngineBinaries({
-    List<BuildMode> buildModes,
-    List<TargetPlatform> targetPlatforms,
-    TargetPlatform hostPlatform,
-    bool skipUnknown,
-  }) {
-    return _binaries.where((BinaryArtifact engineBinary) {
-      if (hostPlatform != null && engineBinary.hostPlatform != null && engineBinary.hostPlatform != hostPlatform) {
-        return false;
-      }
-      // match if artifact has no restrictions.
-      if (engineBinary.skipChecks || engineBinary.buildMode == null && engineBinary.targetPlatform == null) {
-        return true;
-      }
-      final bool buildModeMatch = buildModes.any((BuildMode buildMode) => buildMode == engineBinary.buildMode);
-      final bool targetPlatformMatch = targetPlatforms.any((TargetPlatform targetPlatform) => targetPlatform == engineBinary.targetPlatform);
-      if (buildModeMatch && targetPlatformMatch  // match if artifact exactly matches requiremnets.
-        || skipUnknown && buildModeMatch && targetPlatforms.isEmpty // match if build mode matches but target platform is unknown.
-        || skipUnknown && targetPlatformMatch && buildModes.isEmpty // match if target platform matches but build mode is null.
-        || !skipUnknown && targetPlatforms.isEmpty && buildModes.isEmpty) { // match if neither are provided but skipUnknown flag is provided.
-          return true;
-      }
-      return false;
-    });
-  }
-
-  List<BinaryArtifact> get _packages => const <BinaryArtifact>[
-    BinaryArtifact(
-      name: 'sky_engine',
-      fileName: 'sky_engine'
-    ),
+  List<List<String>> get _osxBinaryDirs => <List<String>>[
+    <String>['darwin-x64', 'darwin-x64/artifacts.zip'],
+    <String>['android-arm-profile/darwin-x64', 'android-arm-profile/darwin-x64.zip'],
+    <String>['android-arm-release/darwin-x64', 'android-arm-release/darwin-x64.zip'],
+    <String>['android-arm64-profile/darwin-x64', 'android-arm64-profile/darwin-x64.zip'],
+    <String>['android-arm64-release/darwin-x64', 'android-arm64-release/darwin-x64.zip'],
+    <String>['android-arm-dynamic-profile/darwin-x64', 'android-arm-dynamic-profile/darwin-x64.zip'],
+    <String>['android-arm-dynamic-release/darwin-x64', 'android-arm-dynamic-release/darwin-x64.zip'],
+    <String>['android-arm64-dynamic-profile/darwin-x64', 'android-arm64-dynamic-profile/darwin-x64.zip'],
+    <String>['android-arm64-dynamic-release/darwin-x64', 'android-arm64-dynamic-release/darwin-x64.zip'],
   ];
 
-  /// This lives separately since we only download it when includeAllPlatforms is true.
-  List<BinaryArtifact> get _dartSdks => const <BinaryArtifact>[
-    BinaryArtifact(
-      name: 'darwin-x64',
-      fileName: 'dart-sdk-darwin-x64.zip',
-    ),
-    BinaryArtifact(
-      name: 'linux-x64',
-      fileName: 'dart-sdk-linux-x64.zip',
-    ),
-    BinaryArtifact(
-      name: 'windows-x64',
-      fileName: 'dart-sdk-windows-x64.zip',
-    ),
+  List<List<String>> get _linuxBinaryDirs => <List<String>>[
+    <String>['linux-x64', 'linux-x64/artifacts.zip'],
+    <String>['android-arm-profile/linux-x64', 'android-arm-profile/linux-x64.zip'],
+    <String>['android-arm-release/linux-x64', 'android-arm-release/linux-x64.zip'],
+    <String>['android-arm64-profile/linux-x64', 'android-arm64-profile/linux-x64.zip'],
+    <String>['android-arm64-release/linux-x64', 'android-arm64-release/linux-x64.zip'],
+    <String>['android-arm-dynamic-profile/linux-x64', 'android-arm-dynamic-profile/linux-x64.zip'],
+    <String>['android-arm-dynamic-release/linux-x64', 'android-arm-dynamic-release/linux-x64.zip'],
+    <String>['android-arm64-dynamic-profile/linux-x64', 'android-arm64-dynamic-profile/linux-x64.zip'],
+    <String>['android-arm64-dynamic-release/linux-x64', 'android-arm64-dynamic-release/linux-x64.zip'],
   ];
 
-  /// A set of all possible artifacts to download.
-  ///
-  /// Adding a new artifact:
-  ///
-  /// To ensure that we do not waste a user's time/data/storage, the flutter
-  /// tool should only binaries when they are required. These can be requested
-  /// in [FlutterCommand.updateCache].
-  ///
-  /// An artifact should have the following features to prevent unecessary download:
-  ///
-  ///   * `hostPlatform` should be one of `TargetPlatform.linux_x64`,
-  ///   `TargetPlatform.darwin_x64`, or `TargetPlatfrom.windows_x64`. In the
-  ///   case where there is no restriction it can be left as null.
-  ///   * `buildMode` should be one of `BuildMode.debug`, `BuildMode.profile`,
-  ///   `BuildMode.release`, `BuildMode.dynamicRelease`, or
-  ///   `BuildMode.dynamicProfile`. In the case where it is required regardless
-  ///   of buildMode, it can be left null.
-  ///   * `targetPlatform` should be one of the supported target platforms.
-  ///   * If, despite the restrictions above, the artifact should still be
-  ///   downloaded, `skipChecks` can be set to true.
-  List<BinaryArtifact> get _binaries => const <BinaryArtifact>[
-    BinaryArtifact(
-      name: 'common',
-      fileName: 'flutter_patched_sdk.zip',
-    ),
-    BinaryArtifact(
-      name: 'linux-x64',
-      fileName: 'linux-x64/artifacts.zip',
-      hostPlatform: TargetPlatform.linux_x64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm-profile/linux-x64',
-      fileName: 'android-arm-profile/linux-x64.zip',
-      targetPlatform: TargetPlatform.android_arm,
-      buildMode: BuildMode.profile,
-      hostPlatform: TargetPlatform.linux_x64,
-      skipChecks: true,
-    ),
-    BinaryArtifact(
-      name: 'android-arm-release/linux-x64',
-      fileName: 'android-arm-release/linux-x64.zip',
-      targetPlatform: TargetPlatform.android_arm,
-      buildMode: BuildMode.release,
-      hostPlatform: TargetPlatform.linux_x64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64-profile/linux-x64',
-      fileName: 'android-arm64-profile/linux-x64.zip',
-      targetPlatform: TargetPlatform.android_arm64,
-      buildMode: BuildMode.profile,
-      hostPlatform: TargetPlatform.linux_x64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64-release/linux-x64',
-      fileName: 'android-arm64-release/linux-x64.zip',
-      targetPlatform: TargetPlatform.android_arm64,
-      buildMode: BuildMode.release,
-      hostPlatform: TargetPlatform.linux_x64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm-dynamic-profile/linux-x64',
-      fileName: 'android-arm-dynamic-profile/linux-x64.zip',
-      targetPlatform: TargetPlatform.android_arm,
-      buildMode: BuildMode.dynamicProfile,
-      hostPlatform: TargetPlatform.linux_x64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm-dynamic-release/linux-x64',
-      fileName:  'android-arm-dynamic-release/linux-x64.zip',
-      targetPlatform: TargetPlatform.android_arm,
-      buildMode: BuildMode.dynamicRelease,
-      hostPlatform: TargetPlatform.linux_x64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64-dynamic-profile/linux-x64',
-      fileName: 'android-arm64-dynamic-profile/linux-x64.zip',
-      targetPlatform: TargetPlatform.android_arm64,
-      buildMode: BuildMode.dynamicProfile,
-      hostPlatform: TargetPlatform.linux_x64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64-dynamic-release/linux-x64',
-      fileName: 'android-arm64-dynamic-release/linux-x64.zip',
-      targetPlatform: TargetPlatform.android_arm64,
-      buildMode: BuildMode.dynamicRelease,
-      hostPlatform: TargetPlatform.linux_x64,
-    ),
-    BinaryArtifact(
-      name: 'windows-x64',
-      fileName: 'windows-x64/artifacts.zip',
-      hostPlatform: TargetPlatform.windows_x64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm-profile/windows-x64',
-      fileName: 'android-arm-profile/windows-x64.zip',
-      hostPlatform: TargetPlatform.windows_x64,
-      targetPlatform: TargetPlatform.android_arm,
-      buildMode: BuildMode.profile,
-      skipChecks: true
-    ),
-    BinaryArtifact(
-      name: 'android-arm-release/windows-x64',
-      fileName: 'android-arm-release/windows-x64.zip',
-      hostPlatform: TargetPlatform.windows_x64,
-      targetPlatform: TargetPlatform.android_arm,
-      buildMode: BuildMode.release,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64-profile/windows-x64',
-      fileName: 'android-arm64-profile/windows-x64.zip',
-      hostPlatform: TargetPlatform.windows_x64,
-      targetPlatform: TargetPlatform.android_arm64,
-      buildMode: BuildMode.profile,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64-release/windows-x64',
-      fileName: 'android-arm64-release/windows-x64.zip',
-      hostPlatform: TargetPlatform.windows_x64,
-      targetPlatform: TargetPlatform.android_arm64,
-      buildMode: BuildMode.release,
-    ),
-    BinaryArtifact(
-      name: 'android-arm-dynamic-profile/windows-x64',
-      fileName: 'android-arm-dynamic-profile/windows-x64.zip',
-      hostPlatform: TargetPlatform.windows_x64,
-      targetPlatform: TargetPlatform.android_arm,
-      buildMode: BuildMode.dynamicProfile,
-    ),
-    BinaryArtifact(
-      name: 'android-arm-dynamic-release/windows-x64',
-      fileName: 'android-arm-dynamic-release/windows-x64.zip',
-      hostPlatform: TargetPlatform.windows_x64,
-      targetPlatform: TargetPlatform.android_arm,
-      buildMode: BuildMode.dynamicRelease,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64-dynamic-profile/windows-x64',
-      fileName: 'android-arm64-dynamic-profile/windows-x64.zip',
-      hostPlatform: TargetPlatform.windows_x64,
-      targetPlatform: TargetPlatform.android_arm64,
-      buildMode: BuildMode.dynamicProfile,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64-dynamic-release/windows-x64',
-      fileName: 'android-arm64-dynamic-release/windows-x64.zip',
-      hostPlatform: TargetPlatform.windows_x64,
-      targetPlatform: TargetPlatform.android_arm64,
-      buildMode: BuildMode.dynamicRelease,
-    ),
-    BinaryArtifact(
-      name: 'android-x86',
-      fileName: 'android-x86/artifacts.zip',
-      buildMode: BuildMode.debug,
-      targetPlatform: TargetPlatform.android_x86,
-    ),
-    BinaryArtifact(
-      name: 'android-x64',
-      fileName: 'android-x64/artifacts.zip',
-      buildMode: BuildMode.debug,
-      targetPlatform: TargetPlatform.android_x64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm',
-      fileName: 'android-arm/artifacts.zip',
-      buildMode: BuildMode.debug,
-      targetPlatform: TargetPlatform.android_arm,
-    ),
-    BinaryArtifact(
-      name: 'android-arm-profile',
-      fileName: 'android-arm-profile/artifacts.zip',
-      buildMode: BuildMode.profile,
-      targetPlatform: TargetPlatform.android_arm,
-    ),
-    BinaryArtifact(
-      name: 'android-arm-release',
-      fileName: 'android-arm-release/artifacts.zip',
-      buildMode: BuildMode.release,
-      targetPlatform: TargetPlatform.android_arm,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64',
-      fileName: 'android-arm64/artifacts.zip',
-      buildMode: BuildMode.debug,
-      targetPlatform: TargetPlatform.android_arm64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64-profile',
-      fileName: 'android-arm64-profile/artifacts.zip',
-      buildMode: BuildMode.profile,
-      targetPlatform: TargetPlatform.android_arm64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64-release',
-      fileName: 'android-arm64-release/artifacts.zip',
-      buildMode: BuildMode.release,
-      targetPlatform: TargetPlatform.android_arm64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm-dynamic-profile',
-      fileName: 'android-arm-dynamic-profile/artifacts.zip',
-      buildMode: BuildMode.dynamicProfile,
-      targetPlatform: TargetPlatform.android_arm,
-    ),
-    BinaryArtifact(
-      name: 'android-arm-dynamic-release',
-      fileName: 'android-arm-dynamic-release/artifacts.zip',
-      buildMode: BuildMode.dynamicRelease,
-      targetPlatform: TargetPlatform.android_arm,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64-dynamic-profile',
-      fileName: 'android-arm64-dynamic-profile/artifacts.zip',
-      buildMode: BuildMode.dynamicProfile,
-      targetPlatform: TargetPlatform.android_arm64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64-dynamic-release',
-      fileName: 'android-arm64-dynamic-release/artifacts.zip',
-      buildMode: BuildMode.dynamicRelease,
-      targetPlatform: TargetPlatform.android_arm64,
-    ),
-    BinaryArtifact(
-      name: 'ios', fileName: 'ios/artifacts.zip',
-      buildMode: BuildMode.debug,
-      hostPlatform: TargetPlatform.darwin_x64,
-      targetPlatform: TargetPlatform.ios,
-    ),
-    BinaryArtifact(
-      name: 'ios-profile',
-      fileName: 'ios-profile/artifacts.zip',
-      buildMode: BuildMode.profile,
-      hostPlatform: TargetPlatform.darwin_x64,
-      targetPlatform: TargetPlatform.ios,
-    ),
-    BinaryArtifact(
-      name: 'ios-release',
-      fileName: 'ios-release/artifacts.zip',
-      buildMode: BuildMode.release,
-      hostPlatform: TargetPlatform.darwin_x64,
-      targetPlatform: TargetPlatform.ios,
-    ),
-    BinaryArtifact(
-      name: 'darwin-x64',
-      fileName: 'darwin-x64/artifacts.zip',
-      hostPlatform: TargetPlatform.darwin_x64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm-profile/darwin-x64',
-      fileName: 'android-arm-profile/darwin-x64.zip',
-      hostPlatform: TargetPlatform.darwin_x64,
-      buildMode: BuildMode.profile,
-      targetPlatform: TargetPlatform.android_arm,
-      skipChecks: true,
-    ),
-    BinaryArtifact(
-      name: 'android-arm-release/darwin-x64',
-      fileName: 'android-arm-release/darwin-x64.zip',
-      hostPlatform: TargetPlatform.darwin_x64,
-      buildMode: BuildMode.release,
-      targetPlatform: TargetPlatform.android_arm,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64-profile/darwin-x64',
-      fileName: 'android-arm64-profile/darwin-x64.zip',
-      hostPlatform: TargetPlatform.darwin_x64,
-      buildMode: BuildMode.profile,
-      targetPlatform: TargetPlatform.android_arm64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64-release/darwin-x64',
-      fileName: 'android-arm64-release/darwin-x64.zip',
-      hostPlatform: TargetPlatform.darwin_x64,
-      buildMode: BuildMode.release,
-      targetPlatform: TargetPlatform.android_arm64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm-dynamic-profile/darwin-x64',
-      fileName: 'android-arm-dynamic-profile/darwin-x64.zip',
-      hostPlatform: TargetPlatform.darwin_x64,
-      buildMode: BuildMode.dynamicProfile,
-      targetPlatform: TargetPlatform.android_arm,
-    ),
-    BinaryArtifact(
-      name: 'android-arm-dynamic-release/darwin-x64',
-      fileName: 'android-arm-dynamic-release/darwin-x64.zip',
-      hostPlatform: TargetPlatform.darwin_x64,
-      buildMode: BuildMode.dynamicRelease,
-      targetPlatform: TargetPlatform.android_arm,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64-dynamic-profile/darwin-x64',
-      fileName: 'android-arm64-dynamic-profile/darwin-x64.zip',
-      hostPlatform: TargetPlatform.darwin_x64,
-      buildMode: BuildMode.dynamicProfile,
-      targetPlatform: TargetPlatform.android_arm64,
-    ),
-    BinaryArtifact(
-      name: 'android-arm64-dynamic-release/darwin-x64',
-      fileName: 'android-arm64-dynamic-release/darwin-x64.zip',
-      hostPlatform: TargetPlatform.darwin_x64,
-      buildMode: BuildMode.dynamicRelease,
-      targetPlatform: TargetPlatform.android_arm64,
-    ),
+  List<List<String>> get _windowsBinaryDirs => <List<String>>[
+    <String>['windows-x64', 'windows-x64/artifacts.zip'],
+    <String>['android-arm-profile/windows-x64', 'android-arm-profile/windows-x64.zip'],
+    <String>['android-arm-release/windows-x64', 'android-arm-release/windows-x64.zip'],
+    <String>['android-arm64-profile/windows-x64', 'android-arm64-profile/windows-x64.zip'],
+    <String>['android-arm64-release/windows-x64', 'android-arm64-release/windows-x64.zip'],
+    <String>['android-arm-dynamic-profile/windows-x64', 'android-arm-dynamic-profile/windows-x64.zip'],
+    <String>['android-arm-dynamic-release/windows-x64', 'android-arm-dynamic-release/windows-x64.zip'],
+    <String>['android-arm64-dynamic-profile/windows-x64', 'android-arm64-dynamic-profile/windows-x64.zip'],
+    <String>['android-arm64-dynamic-release/windows-x64', 'android-arm64-dynamic-release/windows-x64.zip'],
+  ];
+
+  List<List<String>> get _androidBinaryDirs => <List<String>>[
+    <String>['android-x86', 'android-x86/artifacts.zip'],
+    <String>['android-x64', 'android-x64/artifacts.zip'],
+    <String>['android-arm', 'android-arm/artifacts.zip'],
+    <String>['android-arm-profile', 'android-arm-profile/artifacts.zip'],
+    <String>['android-arm-release', 'android-arm-release/artifacts.zip'],
+    <String>['android-arm64', 'android-arm64/artifacts.zip'],
+    <String>['android-arm64-profile', 'android-arm64-profile/artifacts.zip'],
+    <String>['android-arm64-release', 'android-arm64-release/artifacts.zip'],
+    <String>['android-arm-dynamic-profile', 'android-arm-dynamic-profile/artifacts.zip'],
+    <String>['android-arm-dynamic-release', 'android-arm-dynamic-release/artifacts.zip'],
+    <String>['android-arm64-dynamic-profile', 'android-arm64-dynamic-profile/artifacts.zip'],
+    <String>['android-arm64-dynamic-release', 'android-arm64-dynamic-release/artifacts.zip'],
+  ];
+
+  List<List<String>> get _iosBinaryDirs => <List<String>>[
+    <String>['ios', 'ios/artifacts.zip'],
+    <String>['ios-profile', 'ios-profile/artifacts.zip'],
+    <String>['ios-release', 'ios-release/artifacts.zip'],
+  ];
+
+  List<List<String>> get _dartSdks => <List<String>> [
+    <String>['darwin-x64', 'dart-sdk-darwin-x64.zip'],
+    <String>['linux-x64', 'dart-sdk-linux-x64.zip'],
+    <String>['windows-x64', 'dart-sdk-windows-x64.zip'],
   ];
 
   // A list of cache directory paths to which the LICENSE file should be copied.
@@ -839,71 +466,52 @@
   }
 
   @override
-  UpdateResult isUpToDate({
-    List<BuildMode> buildModes = const <BuildMode>[],
-    List<TargetPlatform> targetPlatforms = const <TargetPlatform>[],
-    bool skipUnknown = true,
-  }) {
-    final UpdateResult parentResult = super.isUpToDate(
-      buildModes: buildModes,
-      targetPlatforms: targetPlatforms,
-      skipUnknown: skipUnknown
-    );
-    if (!parentResult.isUpToDate || parentResult.clobber) {
-      return parentResult;
-    }
+  bool isUpToDateInner() {
     final Directory pkgDir = cache.getCacheDir('pkg');
-    for (BinaryArtifact packageArtifact in _packages) {
-      final Directory packageDirectory = packageArtifact.artifactLocation(pkgDir);
-      if (!packageDirectory.existsSync()) {
-        return const UpdateResult(isUpToDate: false);
-      }
+    for (String pkgName in _getPackageDirs()) {
+      final String pkgPath = fs.path.join(pkgDir.path, pkgName);
+      if (!fs.directory(pkgPath).existsSync())
+        return false;
     }
-    for (BinaryArtifact toolsArtifact in getBinaryDirs(buildModes: buildModes, targetPlatforms: targetPlatforms, skipUnknown: skipUnknown)) {
-      final Directory dir = toolsArtifact.artifactLocation(location);
-      if (!dir.existsSync()) {
-        return const UpdateResult(isUpToDate: false);
-      }
+
+    for (List<String> toolsDir in _getBinaryDirs()) {
+      final Directory dir = fs.directory(fs.path.join(location.path, toolsDir[0]));
+      if (!dir.existsSync())
+        return false;
     }
-    return const UpdateResult(isUpToDate: true);
+
+    for (String licenseDir in _getLicenseDirs()) {
+      final File file = fs.file(fs.path.join(location.path, licenseDir, 'LICENSE'));
+      if (!file.existsSync())
+        return false;
+    }
+    return true;
   }
 
   @override
-  Future<void> updateInner({
-    @required List<BuildMode> buildModes,
-    @required List<TargetPlatform> targetPlatforms,
-    @required bool skipUnknown,
-    @required bool clobber,
-  }) async {
+  Future<void> updateInner() async {
     final String url = '$_storageBaseUrl/flutter_infra/flutter/$version/';
-    final Directory packageDirectory = cache.getCacheDir('pkg');
-    for (BinaryArtifact rawArtifact in _packages) {
-      final String pkgPath = fs.path.join(packageDirectory.path, rawArtifact.name);
+
+    final Directory pkgDir = cache.getCacheDir('pkg');
+    for (String pkgName in _getPackageDirs()) {
+      final String pkgPath = fs.path.join(pkgDir.path, pkgName);
       final Directory dir = fs.directory(pkgPath);
-      final bool exists = dir.existsSync();
-      if (exists) {
-        if (!clobber) {
-          continue;
-        }
+      if (dir.existsSync())
         dir.deleteSync(recursive: true);
-      }
-      final Uri uri = Uri.parse('$url${rawArtifact.name}.zip');
-      await _downloadZipArchive('Downloading package ${rawArtifact.name}...', uri, packageDirectory);
+      await _downloadZipArchive('Downloading package $pkgName...', Uri.parse(url + pkgName + '.zip'), pkgDir);
     }
 
-    final List<BinaryArtifact> rawArtifacts = getBinaryDirs(buildModes: buildModes, targetPlatforms: targetPlatforms, skipUnknown: skipUnknown);
-    for (BinaryArtifact rawArtifact in rawArtifacts) {
-      final Directory artifactDirectory = rawArtifact.artifactLocation(location);
-      if (artifactDirectory.existsSync() && !clobber) {
-        continue;
-      }
-      final Uri uri = rawArtifact.artifactRemoteLocation(url);
-      await _downloadZipArchive('Downloading ${rawArtifact.name} tools...', uri, artifactDirectory);
-      _makeFilesExecutable(artifactDirectory);
+    for (List<String> toolsDir in _getBinaryDirs()) {
+      final String cacheDir = toolsDir[0];
+      final String urlPath = toolsDir[1];
+      final Directory dir = fs.directory(fs.path.join(location.path, cacheDir));
+      await _downloadZipArchive('Downloading $cacheDir tools...', Uri.parse(url + urlPath), dir);
 
-      final File frameworkZip = fs.file(fs.path.join(artifactDirectory.path, 'Flutter.framework.zip'));
+      _makeFilesExecutable(dir);
+
+      final File frameworkZip = fs.file(fs.path.join(dir.path, 'Flutter.framework.zip'));
       if (frameworkZip.existsSync()) {
-        final Directory framework = fs.directory(fs.path.join(artifactDirectory.path, 'Flutter.framework'));
+        final Directory framework = fs.directory(fs.path.join(dir.path, 'Flutter.framework'));
         framework.createSync();
         os.unzip(frameworkZip, framework);
       }
@@ -912,43 +520,45 @@
     final File licenseSource = fs.file(fs.path.join(Cache.flutterRoot, 'LICENSE'));
     for (String licenseDir in _getLicenseDirs()) {
       final String licenseDestinationPath = fs.path.join(location.path, licenseDir, 'LICENSE');
-      // If the destination does not exist, we did not download the artifact to
-      // perform this operation.
-      if (!fs.directory(fs.path.join(location.path, licenseDir)).existsSync()) {
-        continue;
-      }
       await licenseSource.copy(licenseDestinationPath);
     }
   }
 
-  // Checks whether the remote artifacts for `engineVersion` are availible in storage.
   Future<bool> areRemoteArtifactsAvailable({
     String engineVersion,
     bool includeAllPlatforms = true,
   }) async {
-    final bool includeAllPlatforms = cache.includeAllPlatforms;
+    final bool includeAllPlatformsState = cache.includeAllPlatforms;
     cache.includeAllPlatforms = includeAllPlatforms;
-    engineVersion ??= version;
-    final String url = '$_storageBaseUrl/flutter_infra/flutter/$engineVersion/';
-    final bool result = await () async {
-      for (BinaryArtifact packageArtifact in _packages) {
-        final Uri uri = Uri.parse('$url${packageArtifact.name}.zip');
-        final bool exists = await _doesRemoteExist('Checking package ${packageArtifact.name} is available...', uri);
+
+    Future<bool> checkForArtifacts(String engineVersion) async {
+      engineVersion ??= version;
+      final String url = '$_storageBaseUrl/flutter_infra/flutter/$engineVersion/';
+
+      bool exists = false;
+      for (String pkgName in _getPackageDirs()) {
+        exists = await _doesRemoteExist('Checking package $pkgName is available...',
+            Uri.parse(url + pkgName + '.zip'));
         if (!exists) {
           return false;
         }
       }
-      final List<BinaryArtifact> rawArtifacts = getBinaryDirs(buildModes: <BuildMode>[], targetPlatforms: <TargetPlatform>[], skipUnknown: false);
-      for (BinaryArtifact rawArtifact in rawArtifacts) {
-        final Uri uri = Uri.parse('$url${rawArtifact.fileName}');
-        final bool exists = await _doesRemoteExist('Checking ${rawArtifact.name} tools are available...', uri);
+
+      for (List<String> toolsDir in _getBinaryDirs()) {
+        final String cacheDir = toolsDir[0];
+        final String urlPath = toolsDir[1];
+        exists = await _doesRemoteExist('Checking $cacheDir tools are available...',
+            Uri.parse(url + urlPath));
         if (!exists) {
           return false;
         }
       }
+
       return true;
-    }();
-    cache.includeAllPlatforms = includeAllPlatforms;
+    }
+
+    final bool result = await checkForArtifacts(engineVersion);
+    cache.includeAllPlatforms = includeAllPlatformsState;
     return result;
   }
 
@@ -957,9 +567,8 @@
     for (FileSystemEntity entity in dir.listSync()) {
       if (entity is File) {
         final String name = fs.path.basename(entity.path);
-        if (name == 'flutter_tester') {
+        if (name == 'flutter_tester')
           os.makeExecutable(entity);
-        }
       }
     }
   }
@@ -974,44 +583,30 @@
   String get _gradleWrapper => fs.path.join('gradle', 'wrapper', 'gradle-wrapper.jar');
 
   @override
-  Future<void> updateInner({List<BuildMode> buildModes, List<TargetPlatform> targetPlatforms, bool skipUnknown, bool clobber}) async {
+  Future<void> updateInner() {
     final Uri archiveUri = _toStorageUri(version);
-    if (fs.directory(location).listSync().isEmpty || clobber) {
-      await _downloadZippedTarball('Downloading Gradle Wrapper...', archiveUri, location).then<void>((_) {
-        // Delete property file, allowing templates to provide it.
-        fs.file(fs.path.join(location.path, 'gradle', 'wrapper', 'gradle-wrapper.properties')).deleteSync();
-        // Remove NOTICE file. Should not be part of the template.
-        fs.file(fs.path.join(location.path, 'NOTICE')).deleteSync();
-      });
-    }
+    return _downloadZippedTarball('Downloading Gradle Wrapper...', archiveUri, location).then<void>((_) {
+      // Delete property file, allowing templates to provide it.
+      fs.file(fs.path.join(location.path, 'gradle', 'wrapper', 'gradle-wrapper.properties')).deleteSync();
+      // Remove NOTICE file. Should not be part of the template.
+      fs.file(fs.path.join(location.path, 'NOTICE')).deleteSync();
+    });
   }
 
   @override
-  UpdateResult isUpToDate({
-    List<BuildMode> buildModes = const <BuildMode>[],
-    List<TargetPlatform> targetPlatforms = const <TargetPlatform>[],
-    bool skipUnknown = true,
-  }) {
-    final UpdateResult parentResult = super.isUpToDate(
-      buildModes: buildModes,
-      targetPlatforms: targetPlatforms,
-      skipUnknown: skipUnknown,
-    );
-    if (!parentResult.isUpToDate || parentResult.clobber) {
-      return parentResult;
-    }
+  bool isUpToDateInner() {
     final Directory wrapperDir = cache.getCacheDir(fs.path.join('artifacts', 'gradle_wrapper'));
     if (!fs.directory(wrapperDir).existsSync())
-      return const UpdateResult(isUpToDate: false);
+      return false;
     for (String scriptName in _gradleScripts) {
       final File scriptFile = fs.file(fs.path.join(wrapperDir.path, scriptName));
       if (!scriptFile.existsSync())
-        return const UpdateResult(isUpToDate: false);
+        return false;
     }
     final File gradleWrapperJar = fs.file(fs.path.join(wrapperDir.path, _gradleWrapper));
     if (!gradleWrapperJar.existsSync())
-      return const UpdateResult(isUpToDate: false);
-    return const UpdateResult(isUpToDate: true);
+      return false;
+    return true;
   }
 }
 
@@ -1066,34 +661,3 @@
   if (!directory.existsSync())
     directory.createSync(recursive: true);
 }
-
-class BinaryArtifact {
-  const BinaryArtifact({
-    this.targetPlatform,
-    this.buildMode,
-    @required this.name,
-    @required this.fileName,
-    this.hostPlatform,
-    this.skipChecks = false,
-  });
-
-  final TargetPlatform targetPlatform;
-  final TargetPlatform hostPlatform;
-  final BuildMode buildMode;
-  final String name;
-  final String fileName;
-  final bool skipChecks;
-
-  /// The location where this artifact will be cached.
-  Directory artifactLocation(Directory location) {
-    return fs.directory(fs.path.join(location.path, name));
-  }
-
-  /// The remote location where this artifact can be downloaded.
-  Uri artifactRemoteLocation(String baseUrl) {
-    return Uri.parse('$baseUrl$fileName');
-  }
-
-  @override
-  String toString() => '$name/$fileName';
-}
diff --git a/packages/flutter_tools/lib/src/commands/build_ios.dart b/packages/flutter_tools/lib/src/commands/build_ios.dart
index 8205c72..b90e332 100644
--- a/packages/flutter_tools/lib/src/commands/build_ios.dart
+++ b/packages/flutter_tools/lib/src/commands/build_ios.dart
@@ -49,15 +49,9 @@
   final String description = 'Build an iOS application bundle (Mac OS X host only).';
 
   @override
-  Future<void> validateCommand() async {
-    defaultBuildMode = forSimulator ? BuildMode.debug : BuildMode.release;
-    return super.validateCommand();
-  }
-
-  bool get forSimulator => argResults['simulator'];
-
-  @override
   Future<FlutterCommandResult> runCommand() async {
+    final bool forSimulator = argResults['simulator'];
+    defaultBuildMode = forSimulator ? BuildMode.debug : BuildMode.release;
 
     if (getCurrentHostPlatform() != HostPlatform.darwin_x64)
       throwToolExit('Building for iOS is only supported on the Mac.');
diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart
index b786415..e3d1d0e 100644
--- a/packages/flutter_tools/lib/src/commands/create.dart
+++ b/packages/flutter_tools/lib/src/commands/create.dart
@@ -212,6 +212,8 @@
       throwToolExit('Neither the --flutter-root command line flag nor the FLUTTER_ROOT environment '
         'variable was specified. Unable to find package:flutter.', exitCode: 2);
 
+    await Cache.instance.updateAll();
+
     final String flutterRoot = fs.path.absolute(Cache.flutterRoot);
 
     final String flutterPackagesDirectory = fs.path.join(flutterRoot, 'packages');
diff --git a/packages/flutter_tools/lib/src/commands/ide_config.dart b/packages/flutter_tools/lib/src/commands/ide_config.dart
index eaa4dd9..2e14108 100644
--- a/packages/flutter_tools/lib/src/commands/ide_config.dart
+++ b/packages/flutter_tools/lib/src/commands/ide_config.dart
@@ -223,6 +223,8 @@
       throwToolExit('Currently, the only supported IDE is IntelliJ\n$usage', exitCode: 2);
     }
 
+    await Cache.instance.updateAll();
+
     if (argResults['update-templates']) {
       _handleTemplateUpdate();
       return null;
diff --git a/packages/flutter_tools/lib/src/commands/precache.dart b/packages/flutter_tools/lib/src/commands/precache.dart
index 7137937..b1fc4dc 100644
--- a/packages/flutter_tools/lib/src/commands/precache.dart
+++ b/packages/flutter_tools/lib/src/commands/precache.dart
@@ -4,7 +4,6 @@
 
 import 'dart:async';
 
-import '../cache.dart';
 import '../globals.dart';
 import '../runner/flutter_command.dart';
 
@@ -12,8 +11,6 @@
   PrecacheCommand() {
     argParser.addFlag('all-platforms', abbr: 'a', negatable: false,
         help: 'Precache artifacts for all platforms.');
-    argParser.addFlag('force', abbr: 'f', negatable: false,
-        help: 'Force download of new cached artifacts');
   }
 
   @override
@@ -27,18 +24,14 @@
 
   @override
   Future<FlutterCommandResult> runCommand() async {
-    if (argResults['all-platforms']) {
+    if (argResults['all-platforms'])
       cache.includeAllPlatforms = true;
-    }
-    final UpdateResult result = cache.isUpToDate(skipUnknown: false);
-    if (result.isUpToDate && !result.clobber && !argResults['force']) {
+
+    if (cache.isUpToDate())
       printStatus('Already up-to-date.');
-    } else {
-      await cache.updateAll(
-        skipUnknown: false,
-        clobber: argResults['force'] || result.clobber,
-      );
-    }
-    return const FlutterCommandResult(ExitStatus.success);
+    else
+      await cache.updateAll();
+
+    return null;
   }
 }
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index b90cdac..2d93bfb 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -327,43 +327,30 @@
   }
 
   BuildMode getBuildMode() {
-    bool debug;
-    bool profile;
-    bool release;
-    if (argParser.options.containsKey('debug')) {
-      debug = argResults['debug'];
-    } else {
-      debug = _defaultBuildMode == BuildMode.debug;
-    }
-    if (argParser.options.containsKey('profile')) {
-      profile = argResults['profile'];
-    } else {
-      profile = _defaultBuildMode == BuildMode.profile;
-    }
-    if (argParser.options.containsKey('release')) {
-      release = argResults['release'];
-    } else {
-      release = _defaultBuildMode == BuildMode.release;
-    }
-    if (debug && profile || debug && release || release && profile) {
+    final List<bool> modeFlags = <bool>[argResults['debug'], argResults['profile'], argResults['release']];
+    if (modeFlags.where((bool flag) => flag).length > 1)
       throw UsageException('Only one of --debug, --profile, or --release can be specified.', null);
-    }
     final bool dynamicFlag = argParser.options.containsKey('dynamic')
         ? argResults['dynamic']
         : false;
 
-    if (debug) {
-      if (dynamicFlag) {
+    if (argResults['debug']) {
+      if (dynamicFlag)
         throw ToolExit('Error: --dynamic requires --release or --profile.');
-      }
       return BuildMode.debug;
     }
-    if (profile) {
+    if (argResults['profile'])
       return dynamicFlag ? BuildMode.dynamicProfile : BuildMode.profile;
-    }
-    if (release) {
+    if (argResults['release'])
       return dynamicFlag ? BuildMode.dynamicRelease : BuildMode.release;
-    }
+
+    if (_defaultBuildMode == BuildMode.debug && dynamicFlag)
+      throw ToolExit('Error: --dynamic requires --release or --profile.');
+    if (_defaultBuildMode == BuildMode.release && dynamicFlag)
+      return BuildMode.dynamicRelease;
+    if (_defaultBuildMode == BuildMode.profile && dynamicFlag)
+      return BuildMode.dynamicProfile;
+
     return _defaultBuildMode;
   }
 
@@ -401,7 +388,7 @@
           '--patch-number (${argResults['patch-number']}) must be an int.', null);
     }
 
-    List<String> extraFrontEndOptions =
+    String extraFrontEndOptions =
         argParser.options.containsKey(FlutterOptions.kExtraFrontEndOptions)
             ? argResults[FlutterOptions.kExtraFrontEndOptions]
             : null;
@@ -410,9 +397,9 @@
       for (String expFlag in argResults[FlutterOptions.kEnableExperiment]) {
         final String flag = '--enable-experiment=' + expFlag;
         if (extraFrontEndOptions != null) {
-          extraFrontEndOptions.add(flag);
+          extraFrontEndOptions += ',' + flag;
         } else {
-          extraFrontEndOptions = <String>[flag];
+          extraFrontEndOptions = flag;
         }
       }
     }
@@ -438,9 +425,9 @@
       baselineDir: argParser.options.containsKey('baseline-dir')
           ? argResults['baseline-dir']
           : null,
-      extraFrontEndOptions: extraFrontEndOptions?.join(', '),
+      extraFrontEndOptions: extraFrontEndOptions,
       extraGenSnapshotOptions: argParser.options.containsKey(FlutterOptions.kExtraGenSnapshotOptions)
-          ? argResults[FlutterOptions.kExtraGenSnapshotOptions]?.join(', ')
+          ? argResults[FlutterOptions.kExtraGenSnapshotOptions]
           : null,
       buildSharedLibrary: argParser.options.containsKey('build-shared-library')
         ? argResults['build-shared-library']
@@ -530,33 +517,6 @@
     );
   }
 
-  /// A hook called to populate the cache with a particular target platform
-  /// or build mode.
-  ///
-  /// If a command requires specific artifacts, it is it's responsibility to
-  /// request them here.
-  Future<void> updateCache() async {
-    // Download all artifacts unless told otherwise.
-    await cache.updateAll(
-      buildModes: <BuildMode>[
-        BuildMode.debug,
-        BuildMode.release,
-        BuildMode.profile,
-        BuildMode.dynamicProfile,
-        BuildMode.dynamicRelease,
-      ],
-      targetPlatforms: <TargetPlatform>[
-        TargetPlatform.android_arm,
-        TargetPlatform.android_arm64,
-        TargetPlatform.android_x64,
-        TargetPlatform.android_x86,
-        TargetPlatform.ios,
-      ],
-      clobber: false,
-      skipUnknown: true,
-    );
-  }
-
   /// Perform validation then call [runCommand] to execute the command.
   /// Return a [Future] that completes with an exit code
   /// indicating whether execution was successful.
@@ -567,11 +527,11 @@
   @mustCallSuper
   Future<FlutterCommandResult> verifyThenRunCommand(String commandPath) async {
     await validateCommand();
+
     // Populate the cache. We call this before pub get below so that the sky_engine
     // package is available in the flutter cache for pub to find.
-    if (shouldUpdateCache) {
-      await updateCache();
-    }
+    if (shouldUpdateCache)
+      await cache.updateAll();
 
     if (shouldRunPub) {
       await pubGet(context: PubContext.getVerifyContext(name));
diff --git a/packages/flutter_tools/test/cache_test.dart b/packages/flutter_tools/test/cache_test.dart
index 8b25990..1e7916f 100644
--- a/packages/flutter_tools/test/cache_test.dart
+++ b/packages/flutter_tools/test/cache_test.dart
@@ -6,7 +6,6 @@
 
 import 'package:file/file.dart';
 import 'package:file/memory.dart';
-import 'package:flutter_tools/src/build_info.dart';
 import 'package:mockito/mockito.dart';
 import 'package:platform/platform.dart';
 
@@ -61,8 +60,7 @@
       directory.createSync(recursive: true);
       fs.file(fs.path.join(directory.path, 'artifacts', 'gradle_wrapper', 'gradle', 'wrapper', 'gradle-wrapper.jar')).createSync(recursive: true);
       when(mockCache.getCacheDir(fs.path.join('artifacts', 'gradle_wrapper'))).thenReturn(fs.directory(fs.path.join(directory.path, 'artifacts', 'gradle_wrapper')));
-      when(mockCache.getArtifactDirectory('gradle_wrapper')).thenReturn(fs.directory(fs.path.join(directory.path, 'artifacts', 'gradle_wrapper')));
-      expect(gradleWrapper.isUpToDate().isUpToDate, const UpdateResult(isUpToDate: false).isUpToDate);
+      expect(gradleWrapper.isUpToDateInner(), false);
     }, overrides: <Type, Generator>{
       Cache: ()=> mockCache,
       FileSystem: () => fs,
@@ -77,8 +75,7 @@
       fs.file(fs.path.join(directory.path, 'artifacts', 'gradle_wrapper', 'gradlew.bat')).createSync(recursive: true);
 
       when(mockCache.getCacheDir(fs.path.join('artifacts', 'gradle_wrapper'))).thenReturn(fs.directory(fs.path.join(directory.path, 'artifacts', 'gradle_wrapper')));
-      when(mockCache.getArtifactDirectory('gradle_wrapper')).thenReturn(fs.directory(fs.path.join(directory.path, 'artifacts', 'gradle_wrapper')));
-      expect(gradleWrapper.isUpToDate().isUpToDate, const UpdateResult(isUpToDate: true).isUpToDate);
+      expect(gradleWrapper.isUpToDateInner(), true);
     }, overrides: <Type, Generator>{
       Cache: ()=> mockCache,
       FileSystem: () => fs,
@@ -87,37 +84,37 @@
     test('should not be up to date, if some cached artifact is not', () {
       final CachedArtifact artifact1 = MockCachedArtifact();
       final CachedArtifact artifact2 = MockCachedArtifact();
-      when(artifact1.isUpToDate(buildModes: anyNamed('buildModes'), targetPlatforms: anyNamed('targetPlatforms'), skipUnknown: anyNamed('skipUnknown'))).thenReturn(const UpdateResult(isUpToDate: true, clobber: false));
-      when(artifact2.isUpToDate(buildModes: anyNamed('buildModes'), targetPlatforms: anyNamed('targetPlatforms'), skipUnknown: anyNamed('skipUnknown'))).thenReturn(const UpdateResult(isUpToDate: false, clobber: false));
+      when(artifact1.isUpToDate()).thenReturn(true);
+      when(artifact2.isUpToDate()).thenReturn(false);
       final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]);
-      expect(cache.isUpToDate().isUpToDate, isFalse);
+      expect(cache.isUpToDate(), isFalse);
     });
     test('should be up to date, if all cached artifacts are', () {
       final CachedArtifact artifact1 = MockCachedArtifact();
       final CachedArtifact artifact2 = MockCachedArtifact();
-      when(artifact1.isUpToDate(buildModes: anyNamed('buildModes'), targetPlatforms: anyNamed('targetPlatforms'), skipUnknown: anyNamed('skipUnknown'))).thenReturn(const UpdateResult(isUpToDate: true, clobber: false));
-      when(artifact2.isUpToDate(buildModes: anyNamed('buildModes'), targetPlatforms: anyNamed('targetPlatforms'), skipUnknown: anyNamed('skipUnknown'))).thenReturn(const UpdateResult(isUpToDate: true, clobber: false));
+      when(artifact1.isUpToDate()).thenReturn(true);
+      when(artifact2.isUpToDate()).thenReturn(true);
       final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]);
-      expect(cache.isUpToDate().isUpToDate, isTrue);
+      expect(cache.isUpToDate(), isTrue);
     });
     test('should update cached artifacts which are not up to date', () async {
       final CachedArtifact artifact1 = MockCachedArtifact();
       final CachedArtifact artifact2 = MockCachedArtifact();
-      when(artifact1.isUpToDate(buildModes: anyNamed('buildModes'), targetPlatforms: anyNamed('targetPlatforms'), skipUnknown: anyNamed('skipUnknown'))).thenReturn(const UpdateResult(isUpToDate: true, clobber: false));
-      when(artifact2.isUpToDate(buildModes: anyNamed('buildModes'), targetPlatforms: anyNamed('targetPlatforms'), skipUnknown: anyNamed('skipUnknown'))).thenReturn(const UpdateResult(isUpToDate: false, clobber: false));
+      when(artifact1.isUpToDate()).thenReturn(true);
+      when(artifact2.isUpToDate()).thenReturn(false);
       final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]);
       await cache.updateAll();
-      verifyNever(artifact1.update(buildModes: anyNamed('buildModes'), targetPlatforms: anyNamed('targetPlatforms'), skipUnknown: anyNamed('skipUnknown')));
-      verify(artifact2.update(buildModes: anyNamed('buildModes'), targetPlatforms: anyNamed('targetPlatforms'), skipUnknown: anyNamed('skipUnknown'), clobber: anyNamed('clobber')));
+      verifyNever(artifact1.update());
+      verify(artifact2.update());
     });
     testUsingContext('failed storage.googleapis.com download shows China warning', () async {
       final CachedArtifact artifact1 = MockCachedArtifact();
       final CachedArtifact artifact2 = MockCachedArtifact();
-      when(artifact1.isUpToDate(buildModes: anyNamed('buildModes'), targetPlatforms: anyNamed('targetPlatforms'), skipUnknown: anyNamed('skipUnknown'))).thenReturn(const UpdateResult(isUpToDate: false, clobber: false));
-      when(artifact2.isUpToDate(buildModes: anyNamed('buildModes'), targetPlatforms: anyNamed('targetPlatforms'), skipUnknown: anyNamed('skipUnknown'))).thenReturn(const UpdateResult(isUpToDate: false, clobber: false));
+      when(artifact1.isUpToDate()).thenReturn(false);
+      when(artifact2.isUpToDate()).thenReturn(false);
       final MockInternetAddress address = MockInternetAddress();
       when(address.host).thenReturn('storage.googleapis.com');
-      when(artifact1.update(buildModes: anyNamed('buildModes'), targetPlatforms: anyNamed('targetPlatforms'), skipUnknown: anyNamed('skipUnknown'), clobber: anyNamed('clobber'))).thenThrow(SocketException(
+      when(artifact1.update()).thenThrow(SocketException(
         'Connection reset by peer',
         address: address,
       ));
@@ -126,203 +123,15 @@
         await cache.updateAll();
         fail('Mock thrown exception expected');
       } catch (e) {
-        verify(artifact1.update(buildModes: anyNamed('buildModes'), targetPlatforms: anyNamed('targetPlatforms'), skipUnknown: anyNamed('skipUnknown'), clobber: anyNamed('clobber')));
+        verify(artifact1.update());
         // Don't continue when retrieval fails.
-        verifyNever(artifact2.update(buildModes: anyNamed('buildModes'), targetPlatforms: anyNamed('targetPlatforms'), skipUnknown: anyNamed('skipUnknown'), clobber: anyNamed('clobber')));
+        verifyNever(artifact2.update());
         expect(
           testLogger.errorText,
           contains('https://flutter.io/community/china'),
         );
       }
     });
-
-    final MockPlatform macos = MockPlatform();
-    final MockPlatform windows = MockPlatform();
-    final MockPlatform linux = MockPlatform();
-    when(macos.isMacOS).thenReturn(true);
-    when(macos.isLinux).thenReturn(false);
-    when(macos.isWindows).thenReturn(false);
-    when(windows.isMacOS).thenReturn(false);
-    when(windows.isLinux).thenReturn(false);
-    when(windows.isWindows).thenReturn(true);
-    when(linux.isMacOS).thenReturn(false);
-    when(linux.isLinux).thenReturn(true);
-    when(linux.isWindows).thenReturn(false);
-
-    testUsingContext('Engine cache filtering - macOS', () {
-      final FlutterEngine flutterEngine = FlutterEngine(MockCache());
-      expect(flutterEngine.getBinaryDirs(
-        buildModes: <BuildMode>[BuildMode.release],
-        targetPlatforms: <TargetPlatform>[TargetPlatform.android_arm],
-        skipUnknown: true,
-      ), unorderedEquals(const <BinaryArtifact>[
-        BinaryArtifact(
-          name: 'common',
-          fileName: 'flutter_patched_sdk.zip',
-        ),
-        BinaryArtifact(
-          name: 'android-arm-release',
-          fileName: 'android-arm-release/artifacts.zip',
-          buildMode: BuildMode.release,
-          targetPlatform: TargetPlatform.android_arm,
-        ),
-        BinaryArtifact(
-          name: 'android-arm-profile/darwin-x64',
-          fileName: 'android-arm-profile/darwin-x64.zip',
-          hostPlatform: TargetPlatform.darwin_x64,
-          buildMode: BuildMode.profile,
-          targetPlatform: TargetPlatform.android_arm,
-          skipChecks: true,
-        ),
-        BinaryArtifact(
-          name: 'android-arm-release/darwin-x64',
-          fileName: 'android-arm-release/darwin-x64.zip',
-          hostPlatform: TargetPlatform.darwin_x64,
-          buildMode: BuildMode.release,
-          targetPlatform: TargetPlatform.android_arm,
-        ),
-        BinaryArtifact(
-          name: 'darwin-x64',
-          fileName: 'darwin-x64/artifacts.zip',
-          hostPlatform: TargetPlatform.darwin_x64,
-        ),
-      ]));
-    }, overrides: <Type, Generator>{
-      Platform: () => macos,
-    });
-
-    testUsingContext('Engine cache filtering - unknown mode - macOS', () {
-      final FlutterEngine flutterEngine = FlutterEngine(MockCache());
-      expect(flutterEngine.getBinaryDirs(
-        buildModes: <BuildMode>[],
-        targetPlatforms: <TargetPlatform>[TargetPlatform.ios],
-        skipUnknown: true,
-      ), unorderedEquals(const <BinaryArtifact>[
-        BinaryArtifact(
-          name: 'common',
-          fileName: 'flutter_patched_sdk.zip',
-        ),
-        BinaryArtifact(
-          name: 'android-arm-profile/darwin-x64',
-          fileName: 'android-arm-profile/darwin-x64.zip',
-          hostPlatform: TargetPlatform.darwin_x64,
-          buildMode: BuildMode.profile,
-          targetPlatform: TargetPlatform.android_arm,
-          skipChecks: true,
-        ),
-        BinaryArtifact(
-          name: 'ios', fileName: 'ios/artifacts.zip',
-          buildMode: BuildMode.debug,
-          hostPlatform: TargetPlatform.darwin_x64,
-          targetPlatform: TargetPlatform.ios,
-        ),
-        BinaryArtifact(
-          name: 'ios-profile',
-          fileName: 'ios-profile/artifacts.zip',
-          buildMode: BuildMode.profile,
-          hostPlatform: TargetPlatform.darwin_x64,
-          targetPlatform: TargetPlatform.ios,
-        ),
-        BinaryArtifact(
-          name: 'ios-release',
-          fileName: 'ios-release/artifacts.zip',
-          buildMode: BuildMode.release,
-          hostPlatform: TargetPlatform.darwin_x64,
-          targetPlatform: TargetPlatform.ios,
-        ),
-        BinaryArtifact(
-          name: 'darwin-x64',
-          fileName: 'darwin-x64/artifacts.zip',
-          hostPlatform: TargetPlatform.darwin_x64,
-        ),
-      ]));
-    }, overrides: <Type, Generator>{
-      Platform: () => macos,
-    });
-
-    testUsingContext('Engine cache filtering - Windows', () {
-      final FlutterEngine flutterEngine = FlutterEngine(MockCache());
-      expect(flutterEngine.getBinaryDirs(
-        buildModes: <BuildMode>[BuildMode.release],
-        targetPlatforms: <TargetPlatform>[TargetPlatform.android_arm],
-        skipUnknown: true,
-      ), unorderedEquals(const <BinaryArtifact>[
-          BinaryArtifact(
-          name: 'common',
-          fileName: 'flutter_patched_sdk.zip',
-        ),
-        BinaryArtifact(
-          name: 'android-arm-release',
-          fileName: 'android-arm-release/artifacts.zip',
-          buildMode: BuildMode.release,
-          targetPlatform: TargetPlatform.android_arm,
-        ),
-        BinaryArtifact(
-          name: 'android-arm-profile/windows-x64',
-          fileName: 'android-arm-profile/windows-x64.zip',
-          hostPlatform: TargetPlatform.windows_x64,
-          buildMode: BuildMode.profile,
-          targetPlatform: TargetPlatform.android_arm,
-          skipChecks: true,
-        ),
-        BinaryArtifact(
-          name: 'android-arm-release/windows-x64',
-          fileName: 'android-arm-release/windows-x64.zip',
-          hostPlatform: TargetPlatform.windows_x64,
-          buildMode: BuildMode.release,
-          targetPlatform: TargetPlatform.android_arm,
-        ),
-        BinaryArtifact(
-          name: 'windows-x64',
-          fileName: 'windows-x64/artifacts.zip',
-          hostPlatform: TargetPlatform.windows_x64,
-        ),
-      ]));
-    }, overrides: <Type, Generator>{
-      Platform: () => windows,
-    });
-
-    testUsingContext('Engine cache filtering - linux', () {
-      final FlutterEngine flutterEngine = FlutterEngine(MockCache());
-      expect(flutterEngine.getBinaryDirs(
-        buildModes: <BuildMode>[BuildMode.release],
-        targetPlatforms: <TargetPlatform>[TargetPlatform.android_arm],
-        skipUnknown: true,
-      ), unorderedEquals(const <BinaryArtifact>[
-          BinaryArtifact(
-          name: 'common',
-          fileName: 'flutter_patched_sdk.zip',
-        ),
-        BinaryArtifact(
-          name: 'android-arm-release',
-          fileName: 'android-arm-release/artifacts.zip',
-          buildMode: BuildMode.release,
-          targetPlatform: TargetPlatform.android_arm,
-        ),
-        BinaryArtifact(
-          name: 'android-arm-profile/linux-x64',
-          fileName: 'android-arm-profile/linux-x64.zip',
-          hostPlatform: TargetPlatform.linux_x64,
-          buildMode: BuildMode.profile,
-          targetPlatform: TargetPlatform.android_arm,
-          skipChecks: true,
-        ),
-        BinaryArtifact(
-          name: 'android-arm-release/linux-x64',
-          fileName: 'android-arm-release/linux-x64.zip',
-          hostPlatform: TargetPlatform.linux_x64,
-          buildMode: BuildMode.release,
-          targetPlatform: TargetPlatform.android_arm,
-        ),
-        BinaryArtifact(
-          name: 'linux-x64',
-          fileName: 'linux-x64/artifacts.zip',
-          hostPlatform: TargetPlatform.linux_x64,
-        ),
-      ]));
-    }, overrides: <Type, Generator>{
-      Platform: () => linux,
-    });
   });
 
   testUsingContext('flattenNameSubdirs', () {
@@ -354,4 +163,3 @@
 class MockCachedArtifact extends Mock implements CachedArtifact {}
 class MockInternetAddress extends Mock implements InternetAddress {}
 class MockCache extends Mock implements Cache {}
-class MockPlatform extends Mock implements Platform {}
diff --git a/packages/flutter_tools/test/runner/flutter_command_test.dart b/packages/flutter_tools/test/runner/flutter_command_test.dart
index ea5bfa8..f98371a 100644
--- a/packages/flutter_tools/test/runner/flutter_command_test.dart
+++ b/packages/flutter_tools/test/runner/flutter_command_test.dart
@@ -42,12 +42,7 @@
     testUsingContext('honors shouldUpdateCache true', () async {
       final DummyFlutterCommand flutterCommand = DummyFlutterCommand(shouldUpdateCache: true);
       await flutterCommand.run();
-      verify(cache.updateAll(
-        buildModes: anyNamed('buildModes'),
-        clobber: anyNamed('clobber'),
-        skipUnknown: anyNamed('skipUnknown'),
-        targetPlatforms: anyNamed('targetPlatforms')
-      )).called(1);
+      verify(cache.updateAll()).called(1);
     },
     overrides: <Type, Generator>{
       Cache: () => cache,