Fix osx_sdk module.

This change fixes several issues with manipulating paths and symlinks.

Bug: https://github.com/flutter/flutter/issues/99039
Reviewed-on: https://flutter-review.googlesource.com/c/recipes/+/28684
Reviewed-by: Jenn Magder <magder@google.com>
Reviewed-by: Keyong Han <keyonghan@google.com>
Commit-Queue: Godofredo Contreras <godofredoc@google.com>
Change-Id: I770d18d726e0eda1f45f46817a650dc57228c93f
Reviewed-on: https://flutter-review.googlesource.com/c/recipes/+/29485
Reviewed-by: Casey Hillers <chillers@google.com>
diff --git a/recipe_modules/adhoc_validation/examples/full.expected/mac.json b/recipe_modules/adhoc_validation/examples/full.expected/mac.json
index d3ac166..8ea1cd5 100644
--- a/recipe_modules/adhoc_validation/examples/full.expected/mac.json
+++ b/recipe_modules/adhoc_validation/examples/full.expected/mac.json
@@ -90,7 +90,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "env": {
       "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
@@ -117,6 +118,35 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "env": {
+      "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "GIT_BRANCH": "",
+      "LUCI_BRANCH": "",
+      "LUCI_CI": "True",
+      "LUCI_PR": "",
+      "OS": "darwin",
+      "PUB_CACHE": "[START_DIR]/.pub-cache",
+      "REVISION": "",
+      "SDK_CHECKOUT_PATH": "[START_DIR]/flutter sdk"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[START_DIR]/flutter sdk/bin",
+        "[START_DIR]/flutter sdk/bin/cache/dart-sdk/bin"
+      ]
+    },
+    "infra_step": true,
+    "name": "Docs.kill dart",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipe_modules/os_utils/api.py b/recipe_modules/os_utils/api.py
index d297c3d..f5daac7 100644
--- a/recipe_modules/os_utils/api.py
+++ b/recipe_modules/os_utils/api.py
@@ -2,15 +2,21 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import os
 from contextlib import contextmanager
 from recipe_engine import recipe_api
 
 from PB.go.chromium.org.luci.buildbucket.proto import common as common_pb2
 
 
-class FlutterDepsApi(recipe_api.RecipeApi):
+class OsUtilsApi(recipe_api.RecipeApi):
   """Operating system utilities."""
 
+  def initialize(self):
+    self._mock_is_symlink = None
+    if self._test_data.enabled:
+      self._mock_is_symlink = self._test_data.get('is_symlink', True)
+
   def _kill_win(self, name, exe_name):
     """Kills all the windows processes with a given name.
 
@@ -38,6 +44,23 @@
           infra_step=True,
       )
 
+  def is_symlink(self, path):
+    """Returns if a path points to a symlink or not."""
+    is_symlink = os.path.islink(self.m.path.abspath(path))
+    return is_symlink if self._mock_is_symlink is None else self._mock_is_symlink
+
+  def symlink(self, source, dest):
+    """Creates a symbolic link.
+
+    Creates a symbolic link in mac platforms.
+    """
+    if self.m.platform.is_mac:
+      self.m.step(
+          'Link %s to %s' % (dest, source),
+          ['ln', '-s', source, dest],
+          infra_step=True,
+      )
+
   def clean_derived_data(self):
     """Cleans the derived data folder in mac builders.
 
@@ -84,6 +107,19 @@
           infra_step=True,
       )
 
+
+  def kill_simulators(self):
+    """Kills any open simulators.
+
+    This is to ensure builds use xcode from a clean state.
+    """
+    if self.m.platform.is_mac:
+      self.m.step(
+          'kill dart', ['killall', '-9', 'com.apple.CoreSimulator.CoreSimulatorDevice'],
+          ok_ret='any',
+          infra_step=True
+      )
+
   def kill_processes(self):
     """Kills processes.
 
@@ -170,8 +206,8 @@
 
   def shutdown_simulators(self):
     """It stops simulators if task is running on a devicelab bot."""
-    if str(self.m.swarming.bot_id
-          ).startswith('flutter-devicelab') and self.m.platform.is_mac:
+    if (str(self.m.swarming.bot_id).startswith('flutter-devicelab')
+        and self.m.platform.is_mac):
       with self.m.step.nest('Shutdown simulators'):
         self.m.step(
             'Shutdown simulators',
diff --git a/recipe_modules/os_utils/examples/full.expected/clean_derived_data.json b/recipe_modules/os_utils/examples/full.expected/clean_derived_data.json
index 5e46265..004b51d 100644
--- a/recipe_modules/os_utils/examples/full.expected/clean_derived_data.json
+++ b/recipe_modules/os_utils/examples/full.expected/clean_derived_data.json
@@ -309,6 +309,25 @@
     ]
   },
   {
+    "cmd": [
+      "ln",
+      "-s",
+      "/a/file",
+      "/a/b/c/simlink"
+    ],
+    "infra_step": true,
+    "name": "Link /a/b/c/simlink to /a/file"
+  },
+  {
+    "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "infra_step": true,
+    "name": "kill dart"
+  },
+  {
     "name": "$result"
   }
 ]
\ No newline at end of file
diff --git a/recipe_modules/os_utils/examples/full.expected/mac_linux.json b/recipe_modules/os_utils/examples/full.expected/mac_linux.json
index 1b6d5e0..0b51fbb 100644
--- a/recipe_modules/os_utils/examples/full.expected/mac_linux.json
+++ b/recipe_modules/os_utils/examples/full.expected/mac_linux.json
@@ -125,6 +125,25 @@
     "name": "Delete mac deriveddata"
   },
   {
+    "cmd": [
+      "ln",
+      "-s",
+      "/a/file",
+      "/a/b/c/simlink"
+    ],
+    "infra_step": true,
+    "name": "Link /a/b/c/simlink to /a/file"
+  },
+  {
+    "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "infra_step": true,
+    "name": "kill dart"
+  },
+  {
     "name": "$result"
   }
 ]
\ No newline at end of file
diff --git a/recipe_modules/os_utils/examples/full.py b/recipe_modules/os_utils/examples/full.py
index 664664d..0d44ad5 100644
--- a/recipe_modules/os_utils/examples/full.py
+++ b/recipe_modules/os_utils/examples/full.py
@@ -25,9 +25,15 @@
   api.os_utils.enable_long_paths()
   api.os_utils.dismiss_dialogs()
   api.os_utils.print_pub_certs()
+  api.os_utils.is_symlink('/a/b/c/simlink')
+  api.os_utils.symlink('/a/file', '/a/b/c/simlink')
+  api.os_utils.kill_simulators()
 
 
 def GenTests(api):
+  # For coverage.
+  api.os_utils.is_symlink(True)
+
   yield api.test(
       'basic',
       api.platform('win', 64),
diff --git a/recipe_modules/os_utils/test_api.py b/recipe_modules/os_utils/test_api.py
new file mode 100644
index 0000000..a347e84
--- /dev/null
+++ b/recipe_modules/os_utils/test_api.py
@@ -0,0 +1,12 @@
+# Copyright 2022 The LUCI Authors. All rights reserved.
+# Use of this source code is governed under the Apache License, Version 2.0
+# that can be found in the LICENSE file.
+
+from recipe_engine import recipe_test_api
+
+class OsUtilsTestApi(recipe_test_api.RecipeTestApi):
+
+  @recipe_test_api.mod_test_data
+  @staticmethod
+  def is_symlink(value):
+    return value
diff --git a/recipe_modules/osx_sdk/__init__.py b/recipe_modules/osx_sdk/__init__.py
index ea42f29..27d77bd 100644
--- a/recipe_modules/osx_sdk/__init__.py
+++ b/recipe_modules/osx_sdk/__init__.py
@@ -5,6 +5,7 @@
 PYTHON_VERSION_COMPATIBILITY = 'PY3'
 
 DEPS = [
+    'flutter/os_utils',
     'recipe_engine/cipd',
     'recipe_engine/context',
     'recipe_engine/file',
diff --git a/recipe_modules/osx_sdk/api.py b/recipe_modules/osx_sdk/api.py
index 5117145..2f0f18d 100644
--- a/recipe_modules/osx_sdk/api.py
+++ b/recipe_modules/osx_sdk/api.py
@@ -158,6 +158,7 @@
     try:
       with self.m.context(infra_steps=True):
         app = self._ensure_sdk(kind)
+        self.m.os_utils.kill_simulators()
         self.m.step('select XCode', ['sudo', 'xcode-select', '--switch', app])
         self.m.step('list simulators', ['xcrun', 'simctl', 'list'])
       yield
@@ -189,9 +190,18 @@
             sdk_app,
             '-cipd-package-prefix',
             'flutter_internal/ios/xcode',
+            '-with-runtime=%s' % (not bool(self._runtime_versions))
         ],
     )
     if self._runtime_versions:
+      # Remove default runtime
+      self.remove_runtime(sdk_app.join(*_RUNTIMESPATH).join('iOS.simruntime'))
+      for version in self._runtime_versions:
+        runtime_name = 'iOS %s.simruntime' % version.lower().replace('ios-', '').replace('-', '.')
+        dest = sdk_app.join(*_RUNTIMESPATH).join(runtime_name)
+        self.remove_runtime(dest)
+
+      self.m.file.ensure_directory('Ensuring runtimes directory', sdk_app.join(*_RUNTIMESPATH))
       for version in self._runtime_versions:
         runtime_cache_dir = self.m.path['cache'].join('xcode_runtime_%s' % version.lower())
         self.m.step(
@@ -209,8 +219,15 @@
         )
         # Move the runtimes
         runtime_name = 'iOS %s.simruntime' % version.lower().replace('ios-', '').replace('-', '.')
-        source = runtime_cache_dir.join(runtime_name)
+        path_with_version = runtime_cache_dir.join(runtime_name)
+        # If the runtime was the default for xcode the cipd bundle contains a directory called iOS.simruntime otherwise
+        # it contains a folder called "iOS <version>.simruntime".
+        source = path_with_version if self.m.path.exists(path_with_version) else runtime_cache_dir.join('iOS.simruntime')
         dest = sdk_app.join(*_RUNTIMESPATH).join(runtime_name)
-        self.m.file.rmglob('Removing stale %s' % runtime_name, sdk_app.join(*_RUNTIMESPATH), runtime_name)
-        self.m.file.symlink('Moving %s to final dest' % version.lower(), source, dest)
+        self.m.file.copytree('Copy runtime to %s' % dest, source, dest, symlinks=True)
     return sdk_app
+
+  def remove_runtime(self, dest):
+    is_symlink = self.m.os_utils.is_symlink(dest)
+    msg = 'Removing %s' % dest
+    self.m.file.remove(msg, dest) if is_symlink else self.m.file.rmtree(msg, dest)
diff --git a/recipe_modules/osx_sdk/examples/full.expected/ancient_version.json b/recipe_modules/osx_sdk/examples/full.expected/ancient_version.json
index 0c34add..33a4e1c 100644
--- a/recipe_modules/osx_sdk/examples/full.expected/ancient_version.json
+++ b/recipe_modules/osx_sdk/examples/full.expected/ancient_version.json
@@ -39,13 +39,23 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "infra_step": true,
     "name": "install xcode"
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "infra_step": true,
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipe_modules/osx_sdk/examples/full.expected/automatic_version.json b/recipe_modules/osx_sdk/examples/full.expected/automatic_version.json
index f9a5754..455c07c 100644
--- a/recipe_modules/osx_sdk/examples/full.expected/automatic_version.json
+++ b/recipe_modules/osx_sdk/examples/full.expected/automatic_version.json
@@ -39,13 +39,23 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "infra_step": true,
     "name": "install xcode"
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "infra_step": true,
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipe_modules/osx_sdk/examples/full.expected/explicit_runtime_version.json b/recipe_modules/osx_sdk/examples/full.expected/explicit_runtime_version.json
index 94812f3..c42813d 100644
--- a/recipe_modules/osx_sdk/examples/full.expected/explicit_runtime_version.json
+++ b/recipe_modules/osx_sdk/examples/full.expected/explicit_runtime_version.json
@@ -39,13 +39,68 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=False"
     ],
     "infra_step": true,
     "name": "install xcode"
   },
   {
     "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "rmtree",
+      "[CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime"
+    ],
+    "infra_step": true,
+    "name": "Removing [CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "rmtree",
+      "[CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 13.0.simruntime"
+    ],
+    "infra_step": true,
+    "name": "Removing [CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 13.0.simruntime"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "rmtree",
+      "[CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 14.0.simruntime"
+    ],
+    "infra_step": true,
+    "name": "Removing [CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 14.0.simruntime"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes"
+    ],
+    "infra_step": true,
+    "name": "Ensuring runtimes directory"
+  },
+  {
+    "cmd": [
       "[CACHE]/osx_sdk/mac_toolchain",
       "install-runtime",
       "-cipd-package-prefix",
@@ -65,27 +120,13 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmglob",
-      "[CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes",
-      "**/iOS 13.0.simruntime",
-      "--hidden"
-    ],
-    "infra_step": true,
-    "name": "Removing stale iOS 13.0.simruntime"
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "symlink",
-      "[CACHE]/xcode_runtime_ios-13-0/iOS 13.0.simruntime",
+      "copytree",
+      "--symlinks",
+      "[CACHE]/xcode_runtime_ios-13-0/iOS.simruntime",
       "[CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 13.0.simruntime"
     ],
     "infra_step": true,
-    "name": "Moving ios-13-0 to final dest"
+    "name": "Copy runtime to [CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 13.0.simruntime"
   },
   {
     "cmd": [
@@ -108,27 +149,22 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "rmglob",
-      "[CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes",
-      "**/iOS 14.0.simruntime",
-      "--hidden"
-    ],
-    "infra_step": true,
-    "name": "Removing stale iOS 14.0.simruntime"
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "symlink",
-      "[CACHE]/xcode_runtime_ios-14-0/iOS 14.0.simruntime",
+      "copytree",
+      "--symlinks",
+      "[CACHE]/xcode_runtime_ios-14-0/iOS.simruntime",
       "[CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 14.0.simruntime"
     ],
     "infra_step": true,
-    "name": "Moving ios-14-0 to final dest"
+    "name": "Copy runtime to [CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 14.0.simruntime"
+  },
+  {
+    "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "infra_step": true,
+    "name": "kill dart"
   },
   {
     "cmd": [
diff --git a/recipe_modules/osx_sdk/examples/full.expected/explicit_runtime_version_nosymlink.json b/recipe_modules/osx_sdk/examples/full.expected/explicit_runtime_version_nosymlink.json
new file mode 100644
index 0000000..27dea8c
--- /dev/null
+++ b/recipe_modules/osx_sdk/examples/full.expected/explicit_runtime_version_nosymlink.json
@@ -0,0 +1,216 @@
+[
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CACHE]/osx_sdk",
+      "-ensure-file",
+      "infra/tools/mac_toolchain/${platform} 123abc",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-123abc----------\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/mac_toolchain/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[CACHE]/osx_sdk/mac_toolchain",
+      "install",
+      "-kind",
+      "mac",
+      "-xcode-version",
+      "deadbeef",
+      "-output-dir",
+      "[CACHE]/osx_sdk/XCode.app",
+      "-cipd-package-prefix",
+      "flutter_internal/ios/xcode",
+      "-with-runtime=False"
+    ],
+    "infra_step": true,
+    "name": "install xcode"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "remove",
+      "[CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime"
+    ],
+    "infra_step": true,
+    "name": "Removing [CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "remove",
+      "[CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 13.0.simruntime"
+    ],
+    "infra_step": true,
+    "name": "Removing [CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 13.0.simruntime"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "remove",
+      "[CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 14.0.simruntime"
+    ],
+    "infra_step": true,
+    "name": "Removing [CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 14.0.simruntime"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes"
+    ],
+    "infra_step": true,
+    "name": "Ensuring runtimes directory"
+  },
+  {
+    "cmd": [
+      "[CACHE]/osx_sdk/mac_toolchain",
+      "install-runtime",
+      "-cipd-package-prefix",
+      "flutter_internal/ios/xcode",
+      "-runtime-version",
+      "ios-13-0",
+      "-output-dir",
+      "[CACHE]/xcode_runtime_ios-13-0"
+    ],
+    "infra_step": true,
+    "name": "install xcode runtime ios-13-0"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copytree",
+      "--symlinks",
+      "[CACHE]/xcode_runtime_ios-13-0/iOS.simruntime",
+      "[CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 13.0.simruntime"
+    ],
+    "infra_step": true,
+    "name": "Copy runtime to [CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 13.0.simruntime"
+  },
+  {
+    "cmd": [
+      "[CACHE]/osx_sdk/mac_toolchain",
+      "install-runtime",
+      "-cipd-package-prefix",
+      "flutter_internal/ios/xcode",
+      "-runtime-version",
+      "ios-14-0",
+      "-output-dir",
+      "[CACHE]/xcode_runtime_ios-14-0"
+    ],
+    "infra_step": true,
+    "name": "install xcode runtime ios-14-0"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copytree",
+      "--symlinks",
+      "[CACHE]/xcode_runtime_ios-14-0/iOS.simruntime",
+      "[CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 14.0.simruntime"
+    ],
+    "infra_step": true,
+    "name": "Copy runtime to [CACHE]/osx_sdk/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 14.0.simruntime"
+  },
+  {
+    "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "infra_step": true,
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
+      "sudo",
+      "xcode-select",
+      "--switch",
+      "[CACHE]/osx_sdk/XCode.app"
+    ],
+    "infra_step": true,
+    "name": "select XCode"
+  },
+  {
+    "cmd": [
+      "xcrun",
+      "simctl",
+      "list"
+    ],
+    "infra_step": true,
+    "name": "list simulators"
+  },
+  {
+    "cmd": [
+      "gn",
+      "gen",
+      "out/Release"
+    ],
+    "name": "gn"
+  },
+  {
+    "cmd": [
+      "ninja",
+      "-C",
+      "out/Release"
+    ],
+    "name": "ninja"
+  },
+  {
+    "cmd": [
+      "sudo",
+      "xcode-select",
+      "--reset"
+    ],
+    "infra_step": true,
+    "name": "reset XCode"
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipe_modules/osx_sdk/examples/full.expected/explicit_version.json b/recipe_modules/osx_sdk/examples/full.expected/explicit_version.json
index b2ffdd5..585b62f 100644
--- a/recipe_modules/osx_sdk/examples/full.expected/explicit_version.json
+++ b/recipe_modules/osx_sdk/examples/full.expected/explicit_version.json
@@ -39,13 +39,23 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "infra_step": true,
     "name": "install xcode"
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "infra_step": true,
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipe_modules/osx_sdk/examples/full.expected/mac.json b/recipe_modules/osx_sdk/examples/full.expected/mac.json
index 39fc198..e64aeca 100644
--- a/recipe_modules/osx_sdk/examples/full.expected/mac.json
+++ b/recipe_modules/osx_sdk/examples/full.expected/mac.json
@@ -39,13 +39,23 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "infra_step": true,
     "name": "install xcode"
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "infra_step": true,
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipe_modules/osx_sdk/examples/full.py b/recipe_modules/osx_sdk/examples/full.py
index 9ecf362..975a9a9 100644
--- a/recipe_modules/osx_sdk/examples/full.py
+++ b/recipe_modules/osx_sdk/examples/full.py
@@ -5,7 +5,10 @@
 PYTHON_VERSION_COMPATIBILITY = 'PY3'
 
 DEPS = [
+  'flutter/os_utils',
   'flutter/osx_sdk',
+  'recipe_engine/file',
+  'recipe_engine/path',
   'recipe_engine/platform',
   'recipe_engine/properties',
   'recipe_engine/step',
@@ -31,13 +34,31 @@
       }})
   )
 
+  p = api.path['cache'].join(
+      'osx_sdk', 'XCode.app', 'Contents', 'Developer', 'Platforms',
+      'iPhoneOS.platform', 'Library', 'Developer', 'CoreSimulator',
+      'Profiles', 'Runtimes', 'iOS 13.0.simruntime')
+
+  yield api.test(
+      'explicit_runtime_version_nosymlink',
+      api.platform.name('mac'),
+      api.properties(**{'$flutter/osx_sdk': {
+          'sdk_version': 'deadbeef', 'toolchain_ver': '123abc',
+          'runtime_versions': ['ios-13-0', 'ios-14-0']
+      }}),
+      api.os_utils.is_symlink(True),
+      api.path.exists(p),
+  )
+
   yield api.test(
       'explicit_runtime_version',
       api.platform.name('mac'),
       api.properties(**{'$flutter/osx_sdk': {
           'sdk_version': 'deadbeef', 'toolchain_ver': '123abc',
           'runtime_versions': ['ios-13-0', 'ios-14-0']
-      }})
+      }}),
+      api.os_utils.is_symlink(False),
+      api.path.exists(p),
   )
 
   yield api.test(
diff --git a/recipes/devicelab/devicelab_drone.expected/upload-metrics-mac.json b/recipes/devicelab/devicelab_drone.expected/upload-metrics-mac.json
index 0d7ca21..2b870c8 100644
--- a/recipes/devicelab/devicelab_drone.expected/upload-metrics-mac.json
+++ b/recipes/devicelab/devicelab_drone.expected/upload-metrics-mac.json
@@ -605,7 +605,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CLEANUP]/tmp_tmp_1/flutter sdk/dev/devicelab",
     "env": {
@@ -645,6 +646,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CLEANUP]/tmp_tmp_1/flutter sdk/dev/devicelab",
+    "env": {
+      "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GIT_BRANCH": "master",
+      "LUCI_BRANCH": "",
+      "LUCI_CI": "True",
+      "LUCI_PR": "",
+      "OS": "darwin",
+      "PUB_CACHE": "[START_DIR]/.pub-cache",
+      "REVISION": "2d72510e447ab60a9728aeea2362d8be2cbd7789",
+      "SDK_CHECKOUT_PATH": "[CLEANUP]/tmp_tmp_1/flutter sdk"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CLEANUP]/tmp_tmp_1/flutter sdk/bin",
+        "[CLEANUP]/tmp_tmp_1/flutter sdk/bin/cache/dart-sdk/bin",
+        "[CLEANUP]/tmp_tmp_2/vpython"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/devicelab/devicelab_drone.expected/xcode-chromium-mac.json b/recipes/devicelab/devicelab_drone.expected/xcode-chromium-mac.json
index ebf5f4c..e41b7c5 100644
--- a/recipes/devicelab/devicelab_drone.expected/xcode-chromium-mac.json
+++ b/recipes/devicelab/devicelab_drone.expected/xcode-chromium-mac.json
@@ -605,7 +605,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CLEANUP]/tmp_tmp_1/flutter sdk/dev/devicelab",
     "env": {
@@ -645,6 +646,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CLEANUP]/tmp_tmp_1/flutter sdk/dev/devicelab",
+    "env": {
+      "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GIT_BRANCH": "master",
+      "LUCI_BRANCH": "",
+      "LUCI_CI": "True",
+      "LUCI_PR": "",
+      "OS": "darwin",
+      "PUB_CACHE": "[START_DIR]/.pub-cache",
+      "REVISION": "2d72510e447ab60a9728aeea2362d8be2cbd7789",
+      "SDK_CHECKOUT_PATH": "[CLEANUP]/tmp_tmp_1/flutter sdk"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CLEANUP]/tmp_tmp_1/flutter sdk/bin",
+        "[CLEANUP]/tmp_tmp_1/flutter sdk/bin/cache/dart-sdk/bin",
+        "[CLEANUP]/tmp_tmp_2/vpython"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine.expected/mac.json b/recipes/engine/engine.expected/mac.json
index ad593f9..16e45de 100644
--- a/recipes/engine/engine.expected/mac.json
+++ b/recipes/engine/engine.expected/mac.json
@@ -511,7 +511,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -551,6 +552,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine.expected/mac_font_subset.json b/recipes/engine/engine.expected/mac_font_subset.json
index ad593f9..16e45de 100644
--- a/recipes/engine/engine.expected/mac_font_subset.json
+++ b/recipes/engine/engine.expected/mac_font_subset.json
@@ -511,7 +511,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -551,6 +552,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine.expected/mac_no_lto.json b/recipes/engine/engine.expected/mac_no_lto.json
index 969e3aa..7492adc 100644
--- a/recipes/engine/engine.expected/mac_no_lto.json
+++ b/recipes/engine/engine.expected/mac_no_lto.json
@@ -511,7 +511,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -551,6 +552,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine.expected/mac_no_lto_font_subset.json b/recipes/engine/engine.expected/mac_no_lto_font_subset.json
index 969e3aa..7492adc 100644
--- a/recipes/engine/engine.expected/mac_no_lto_font_subset.json
+++ b/recipes/engine/engine.expected/mac_no_lto_font_subset.json
@@ -511,7 +511,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -551,6 +552,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine.expected/mac_publish_cipd.json b/recipes/engine/engine.expected/mac_publish_cipd.json
index ad593f9..16e45de 100644
--- a/recipes/engine/engine.expected/mac_publish_cipd.json
+++ b/recipes/engine/engine.expected/mac_publish_cipd.json
@@ -511,7 +511,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -551,6 +552,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine.expected/mac_publish_cipd_font_subset.json b/recipes/engine/engine.expected/mac_publish_cipd_font_subset.json
index ad593f9..16e45de 100644
--- a/recipes/engine/engine.expected/mac_publish_cipd_font_subset.json
+++ b/recipes/engine/engine.expected/mac_publish_cipd_font_subset.json
@@ -511,7 +511,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -551,6 +552,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine.expected/mac_publish_cipd_no_lto.json b/recipes/engine/engine.expected/mac_publish_cipd_no_lto.json
index 969e3aa..7492adc 100644
--- a/recipes/engine/engine.expected/mac_publish_cipd_no_lto.json
+++ b/recipes/engine/engine.expected/mac_publish_cipd_no_lto.json
@@ -511,7 +511,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -551,6 +552,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine.expected/mac_publish_cipd_no_lto_font_subset.json b/recipes/engine/engine.expected/mac_publish_cipd_no_lto_font_subset.json
index 969e3aa..7492adc 100644
--- a/recipes/engine/engine.expected/mac_publish_cipd_no_lto_font_subset.json
+++ b/recipes/engine/engine.expected/mac_publish_cipd_no_lto_font_subset.json
@@ -511,7 +511,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -551,6 +552,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine.expected/mac_upload.json b/recipes/engine/engine.expected/mac_upload.json
index bca1117..c872def 100644
--- a/recipes/engine/engine.expected/mac_upload.json
+++ b/recipes/engine/engine.expected/mac_upload.json
@@ -511,7 +511,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -551,6 +552,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine.expected/mac_upload_font_subset.json b/recipes/engine/engine.expected/mac_upload_font_subset.json
index 722974c..17783e4 100644
--- a/recipes/engine/engine.expected/mac_upload_font_subset.json
+++ b/recipes/engine/engine.expected/mac_upload_font_subset.json
@@ -511,7 +511,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -551,6 +552,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine.expected/mac_upload_no_lto.json b/recipes/engine/engine.expected/mac_upload_no_lto.json
index 6494266..5a0ccd9 100644
--- a/recipes/engine/engine.expected/mac_upload_no_lto.json
+++ b/recipes/engine/engine.expected/mac_upload_no_lto.json
@@ -511,7 +511,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -551,6 +552,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine.expected/mac_upload_no_lto_font_subset.json b/recipes/engine/engine.expected/mac_upload_no_lto_font_subset.json
index b121807..fbda875 100644
--- a/recipes/engine/engine.expected/mac_upload_no_lto_font_subset.json
+++ b/recipes/engine/engine.expected/mac_upload_no_lto_font_subset.json
@@ -511,7 +511,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -551,6 +552,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine.expected/mac_upload_publish_cipd.json b/recipes/engine/engine.expected/mac_upload_publish_cipd.json
index bca1117..c872def 100644
--- a/recipes/engine/engine.expected/mac_upload_publish_cipd.json
+++ b/recipes/engine/engine.expected/mac_upload_publish_cipd.json
@@ -511,7 +511,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -551,6 +552,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine.expected/mac_upload_publish_cipd_font_subset.json b/recipes/engine/engine.expected/mac_upload_publish_cipd_font_subset.json
index 722974c..17783e4 100644
--- a/recipes/engine/engine.expected/mac_upload_publish_cipd_font_subset.json
+++ b/recipes/engine/engine.expected/mac_upload_publish_cipd_font_subset.json
@@ -511,7 +511,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -551,6 +552,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine.expected/mac_upload_publish_cipd_no_lto.json b/recipes/engine/engine.expected/mac_upload_publish_cipd_no_lto.json
index 6494266..5a0ccd9 100644
--- a/recipes/engine/engine.expected/mac_upload_publish_cipd_no_lto.json
+++ b/recipes/engine/engine.expected/mac_upload_publish_cipd_no_lto.json
@@ -511,7 +511,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -551,6 +552,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine.expected/mac_upload_publish_cipd_no_lto_font_subset.json b/recipes/engine/engine.expected/mac_upload_publish_cipd_no_lto_font_subset.json
index b121807..fbda875 100644
--- a/recipes/engine/engine.expected/mac_upload_publish_cipd_no_lto_font_subset.json
+++ b/recipes/engine/engine.expected/mac_upload_publish_cipd_no_lto_font_subset.json
@@ -511,7 +511,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -551,6 +552,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine_lint.expected/mac.json b/recipes/engine/engine_lint.expected/mac.json
index 7fd215d..4a5704e 100644
--- a/recipes/engine/engine_lint.expected/mac.json
+++ b/recipes/engine/engine_lint.expected/mac.json
@@ -572,7 +572,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -612,6 +613,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine_unopt.expected/mac.json b/recipes/engine/engine_unopt.expected/mac.json
index 2f5f114..95ec3c4 100644
--- a/recipes/engine/engine_unopt.expected/mac.json
+++ b/recipes/engine/engine_unopt.expected/mac.json
@@ -597,7 +597,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -637,6 +638,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/engine_unopt.expected/mac_lto.json b/recipes/engine/engine_unopt.expected/mac_lto.json
index 2f5f114..95ec3c4 100644
--- a/recipes/engine/engine_unopt.expected/mac_lto.json
+++ b/recipes/engine/engine_unopt.expected/mac_lto.json
@@ -597,7 +597,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -637,6 +638,48 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "FLUTTER_LOGS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "FLUTTER_TEST_OUTPUTS_DIR": "[CLEANUP]/flutter_logs_dir",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/web_engine.expected/mac-post-submit.json b/recipes/engine/web_engine.expected/mac-post-submit.json
index 8315fc4..1093a71 100644
--- a/recipes/engine/web_engine.expected/mac-post-submit.json
+++ b/recipes/engine/web_engine.expected/mac-post-submit.json
@@ -353,7 +353,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder",
     "env": {
@@ -381,6 +382,36 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "CHROME_NO_SANDBOX": "true",
+      "ENGINE_PATH": "[CACHE]/builder",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
@@ -1195,7 +1226,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CACHE]/builder/src/flutter/lib/web_ui",
     "env": {
@@ -1223,6 +1255,36 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CACHE]/builder/src/flutter/lib/web_ui",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/builder/src/third_party/android_tools/sdk",
+      "CHROME_NO_SANDBOX": "true",
+      "ENGINE_PATH": "[CACHE]/builder",
+      "FLUTTER_PREBUILT_DART_SDK": "True",
+      "GOMA_DIR": "[CACHE]/goma/client"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "name": "kill dart (2)"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine/web_engine_drone.expected/mac-post-submit.json b/recipes/engine/web_engine_drone.expected/mac-post-submit.json
index 25c9c0a..2498ae3 100644
--- a/recipes/engine/web_engine_drone.expected/mac-post-submit.json
+++ b/recipes/engine/web_engine_drone.expected/mac-post-submit.json
@@ -462,7 +462,8 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "cwd": "[CLEANUP]/builder/src/flutter/lib/web_ui",
     "env": {
@@ -493,6 +494,39 @@
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "cwd": "[CLEANUP]/builder/src/flutter/lib/web_ui",
+    "env": {
+      "ANDROID_HOME": "[CLEANUP]/builder/src/third_party/android_tools/sdk",
+      "CHROME_NO_SANDBOX": "true",
+      "ENGINE_PATH": "[CLEANUP]/builder",
+      "GOMA_DIR": "[CACHE]/goma/client",
+      "LOCAL_ENGINE": "[CLEANUP]/builder/src/out/host_debug_unopt"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CLEANUP]/builder/src/third_party/dart/tools/sdks/dart-sdk/bin",
+        "[CLEANUP]/builder/src/out/host_debug_unopt/dart-sdk/bin"
+      ]
+    },
+    "env_suffixes": {
+      "DEPOT_TOOLS_UPDATE": [
+        "0",
+        "0"
+      ],
+      "PATH": [
+        "RECIPE_REPO[depot_tools]",
+        "RECIPE_REPO[depot_tools]"
+      ]
+    },
+    "infra_step": true,
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/engine_v2/builder.expected/mac.json b/recipes/engine_v2/builder.expected/mac.json
index 75964c7..feeed87 100644
--- a/recipes/engine_v2/builder.expected/mac.json
+++ b/recipes/engine_v2/builder.expected/mac.json
@@ -252,13 +252,23 @@
       "-output-dir",
       "[CACHE]/osx_sdk/XCode.app",
       "-cipd-package-prefix",
-      "flutter_internal/ios/xcode"
+      "flutter_internal/ios/xcode",
+      "-with-runtime=True"
     ],
     "infra_step": true,
     "name": "install xcode"
   },
   {
     "cmd": [
+      "killall",
+      "-9",
+      "com.apple.CoreSimulator.CoreSimulatorDevice"
+    ],
+    "infra_step": true,
+    "name": "kill dart"
+  },
+  {
+    "cmd": [
       "sudo",
       "xcode-select",
       "--switch",
diff --git a/recipes/flutter/flutter.pyback b/recipes/flutter/flutter.pyback
deleted file mode 100644
index 758aa07..0000000
--- a/recipes/flutter/flutter.pyback
+++ /dev/null
@@ -1,132 +0,0 @@
-# Copyright 2020 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-from contextlib import contextmanager
-import re
-
-from PB.go.chromium.org.luci.buildbucket.proto import build as build_pb2
-from PB.go.chromium.org.luci.buildbucket.proto import common as common_pb2
-from PB.go.chromium.org.luci.buildbucket.proto \
-  import builds_service as builds_service_pb2
-from google.protobuf import struct_pb2
-
-DEPS = [
-    'flutter/android_sdk',
-    'flutter/adhoc_validation',
-    'flutter/json_util',
-    'flutter/os_utils',
-    'flutter/repo_util',
-    'flutter/shard_util',
-    'flutter/flutter_deps',
-    'flutter/display_util',
-    'recipe_engine/buildbucket',
-    'recipe_engine/context',
-    'recipe_engine/path',
-    'recipe_engine/platform',
-    'recipe_engine/properties',
-    'recipe_engine/step',
-]
-
-
-def RunSteps(api):
-  """Recipe to run flutter sdk tests."""
-  # Trigger sharded tests.
-  if not api.properties.get('validation'):
-    builds = api.shard_util.schedule_builds()
-    builds = api.shard_util.collect_builds(builds)
-    api.display_util.display_builds(
-        step_name='display builds',
-        builds=builds,
-        raise_on_failure=True,
-    )
-    return
-
-  # Collect memory/cpu/process before task execution.
-  api.os_utils.collect_os_info()
-
-  # Trigger validation tests. This is to optimize resources usage
-  # when don't need to run in shards.
-  checkout_path = api.path['start_dir'].join('flutter sdk')
-  with api.step.nest('checkout source code'):
-    api.repo_util.checkout(
-        'flutter',
-        checkout_path=checkout_path,
-        url=api.properties.get('git_url'),
-        ref=api.properties.get('git_ref')
-    )
-
-  if api.platform.is_linux:
-    # Validates flutter builders json format.
-    api.json_util.validate_json(checkout_path)
-
-  env, env_prefixes = api.repo_util.flutter_environment(checkout_path)
-  api.flutter_deps.required_deps(
-      env, env_prefixes, api.properties.get('dependencies', [])
-  )
-  with api.context(env=env, env_prefixes=env_prefixes, cwd=checkout_path):
-    with api.step.nest('prepare environment'), api.step.defer_results():
-      #api.step(
-      #    'flutter doctor',
-      #    ['flutter', 'doctor'],
-      #)
-      #api.step(
-      #    'download dependencies',
-      #    ['flutter', 'update-packages'],
-      #    infra_step=True,
-      #)
-      api.adhoc_validation.run(
-          api.properties.get('validation_name'),
-          api.properties.get('validation'), env, env_prefixes,
-          api.properties.get('secrets', {})
-      )
-
-      # This is to clean up leaked processes.
-      api.os_utils.kill_processes()
-      # Collect memory/cpu/process after task execution.
-      api.os_utils.collect_os_info()
-
-
-def GenTests(api):
-  yield api.test(
-      'validators',
-      api.properties(
-          validation='analyze',
-          validation_name='dart analyze',
-          android_sdk_license='android_license',
-          android_sdk_preview_license='android_preview_license'
-      ), api.repo_util.flutter_environment_data()
-  )
-  props = struct_pb2.Struct()
-  props['task_name'] = 'abc'
-  build = build_pb2.Build(input=build_pb2.Build.Input(properties=props))
-  passed_batch_res = builds_service_pb2.BatchResponse(
-      responses=[
-          dict(
-              schedule_build=dict(
-                  id=build.id, builder=build.builder, input=build.input
-              )
-          )
-      ]
-  )
-  yield api.test(
-      'shards',
-      api.properties(shard='framework_tests', subshards=['0', '1_last']),
-      api.repo_util.flutter_environment_data(),
-      api.buildbucket.simulated_schedule_output(passed_batch_res)
-  )
-
-  err_batch_res = builds_service_pb2.BatchResponse(
-      responses=[
-          dict(error=dict(
-              code=1,
-              message='bad',
-          ),),
-      ],
-  )
-  yield api.test(
-      'shards_fail',
-      api.properties(shard='framework_tests', subshards=['0', '1_last']),
-      api.repo_util.flutter_environment_data(),
-      api.buildbucket.simulated_schedule_output(err_batch_res)
-  )