Merge branch 'main' into zanderso-patch-4
diff --git a/.ci.yaml b/.ci.yaml
index 44feda6..424f41e 100644
--- a/.ci.yaml
+++ b/.ci.yaml
@@ -183,6 +183,7 @@
         {"download_emsdk": true}
       add_recipes_cq: "true"
       build_host: "true"
+      cores: "32"
     timeout: 60
 
   - name: Linux Unopt
@@ -304,6 +305,7 @@
           {"dependency": "firefox", "version": "version:106.0"},
           {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}
         ]
+      no_goma: "true"
     timeout: 60
     runIf:
       - DEPS
@@ -321,6 +323,7 @@
       - master
     properties:
       add_recipes_cq: "true"
+      cores: "32"
       gclient_variables: >-
         {"download_emsdk": true}
       dependencies: >-
@@ -329,6 +332,7 @@
           {"dependency": "curl", "version": "version:7.64.0"}
         ]
       framework: "true"
+      no_goma: "true"
       shard: web_tests
       subshards: >-
               ["0", "1", "2", "3", "4", "5", "6", "7_last"]
@@ -448,6 +452,7 @@
         [
           {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}
         ]
+      no_goma: "true"
     timeout: 60
     runIf:
       - DEPS
@@ -525,6 +530,7 @@
         [
           {"dependency": "chrome_and_driver", "version": "version:111.0"}
         ]
+      no_goma: "true"
     timeout: 60
     runIf:
       - DEPS
diff --git a/DEPS b/DEPS
index 6dcbfcc..70ca325 100644
--- a/DEPS
+++ b/DEPS
@@ -18,7 +18,7 @@
   'llvm_git': 'https://llvm.googlesource.com',
   # OCMock is for testing only so there is no google clone
   'ocmock_git': 'https://github.com/erikdoe/ocmock.git',
-  'skia_revision': '529fb1efd882ab11e05bb97b81eaeb97f74e9d26',
+  'skia_revision': '1c36c5c38ef4742a4e359484ab15a670c06902d9',
 
   # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY
   # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version.
@@ -48,7 +48,7 @@
   # Dart is: https://github.com/dart-lang/sdk/blob/main/DEPS
   # You can use //tools/dart/create_updated_flutter_deps.py to produce
   # updated revision list of existing dependencies.
-  'dart_revision': '7240b35cc401ad8cf3107e83c04b055ef3cc895d',
+  'dart_revision': '689440e4d16326ed59fe8d7185a81ce1402a4430',
 
   # WARNING: DO NOT EDIT MANUALLY
   # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py
@@ -61,14 +61,14 @@
   'dart_devtools_rev': 'bf15e7348d53dc83531d503be94e0c035b604984',
   'dart_libprotobuf_rev': '24487dd1045c7f3d64a21f38a3f0c06cc4cf2edb',
   'dart_perfetto_rev': 'b8da07095979310818f0efde2ef3c69ea70d62c5',
-  'dart_protobuf_gn_rev': '5f87ef9990fc4f4ffd76b3f5b0138562178db8bc',
+  'dart_protobuf_gn_rev': 'f872f05cb0378eef9a7a2609076929f0f35b4141',
   'dart_protobuf_rev': '75bc380a6e9601565606a13dee16c5ab2bf5019c',
-  'dart_pub_rev': '048e3ad2b5e1b4ebe6883addbc95722be6904a7b',
+  'dart_pub_rev': 'd69493e5163553bde53c0889b7479dee02f550bf',
   'dart_root_certificates_rev': '692f6d6488af68e0121317a9c2c9eb393eb0ee50',
   'dart_watcher_rev': '5968409e1d73e21e75fc22a6481d5efaef7f3558',
-  'dart_webdev_rev': 'c007560346a53728920362e5ccaa7eaae85301a7',
+  'dart_webdev_rev': 'cfe97534b33d37c7e0bbac2a3576085f74f2eaa3',
   'dart_webkit_inspection_protocol_rev': '8401098ace995e4dcd9855a2741c2dacccaa780b',
-  'dart_yaml_edit_rev': '998eea2e4fc474a5e95cfea117e4233d35c3069b',
+  'dart_yaml_edit_rev': '6abc42a74b76700ad02fa1c1ebd94951b62626b9',
   'dart_zlib_rev': '27c2f474b71d0d20764f86f60ef8b00da1a16cda',
 
   'ocmock_rev': 'c4ec0e3a7a9f56cfdbd0aa01f4f97bb4b75c5ef8', # v3.7.1
@@ -239,7 +239,7 @@
 ]
 
 deps = {
-  'src': 'https://github.com/flutter/buildroot.git' + '@' + '93f7f85422a8604bdc44ef76c3f105ead65e8c1c',
+  'src': 'https://github.com/flutter/buildroot.git' + '@' + 'a357fb6285af70772dbca8b164cd61af16cc8af1',
 
    # Fuchsia compatibility
    #
@@ -449,13 +449,13 @@
    Var('dart_git') + '/term_glyph.git@d275a8f7482b6a5e4f15d0da6feb66c24f52eb94',
 
   'src/third_party/dart/third_party/pkg/test':
-   Var('dart_git') + '/test.git@92da93a83615f2bc0483aa00e6a85c4f89d616e4',
+   Var('dart_git') + '/test.git@3ba78f15538399073d0b5aba4ec19b1378af1625',
 
   'src/third_party/dart/third_party/pkg/test_reflective_loader':
    Var('dart_git') + '/test_reflective_loader.git@c4c2d5c3f94a96f3fc79e9e28944fba391bc544c',
 
   'src/third_party/dart/third_party/pkg/tools':
-   Var('dart_git') + '/tools.git@a1c35060d920122ecbecb8c5a389b58ccbceb125',
+   Var('dart_git') + '/tools.git@bed358ea8ca10551c710282be96cf6e95620fb24',
 
   'src/third_party/dart/third_party/pkg/typed_data':
    Var('dart_git') + '/typed_data.git@f858046fb420cf644e7d8cb86b7893f2830d8a6c',
@@ -476,7 +476,7 @@
    Var('dart_git') + '/external/github.com/google/webkit_inspection_protocol.dart.git' + '@' + Var('dart_webkit_inspection_protocol_rev'),
 
   'src/third_party/dart/third_party/pkg/yaml':
-   Var('dart_git') + '/yaml.git@a6d8781744d34c391368664b4c1e174f0433bbb6',
+   Var('dart_git') + '/yaml.git@0f80b12978f066b3547632dec4a273649138fae4',
 
   'src/third_party/dart/third_party/pkg/yaml_edit':
    Var('dart_git') + '/yaml_edit.git' + '@' + Var('dart_yaml_edit_rev'),
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 40329d6..1eeb5c8 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -95,6 +95,7 @@
     - flutter_style_todos
     - hash_and_equals
     - implementation_imports
+    - invalid_case_patterns
     - iterable_contains_unrelated_type
     # - join_return_with_assignment # not required by flutter style
     - leading_newlines_in_multiline_strings
diff --git a/ci/builders/linux_android_aot_engine.json b/ci/builders/linux_android_aot_engine.json
index d28dfc1..6523c0b 100644
--- a/ci/builders/linux_android_aot_engine.json
+++ b/ci/builders/linux_android_aot_engine.json
@@ -90,6 +90,7 @@
                         "out/android_release_arm64/zip_archives/android-arm64-release/artifacts.zip",
                         "out/android_release_arm64/zip_archives/android-arm64-release/linux-x64.zip",
                         "out/android_release_arm64/zip_archives/android-arm64-release/symbols.zip",
+                        "out/android_release_arm64/zip_archives/android-arm64-release/analyze-snapshot-linux-x64.zip",
                         "out/android_release_arm64/zip_archives/download.flutter.io"
                     ]
                 }
@@ -114,7 +115,8 @@
                 "targets": [
                     "default",
                     "clang_x64/gen_snapshot",
-                    "flutter/shell/platform/android:abi_jars"
+                    "flutter/shell/platform/android:abi_jars",
+                    "flutter/shell/platform/android:analyze_snapshot"
                 ]
             },
             "tests": []
@@ -128,6 +130,7 @@
                     "include_paths": [
                         "out/android_profile_arm64/zip_archives/android-arm64-profile/artifacts.zip",
                         "out/android_profile_arm64/zip_archives/android-arm64-profile/linux-x64.zip",
+                        "out/android_profile_arm64/zip_archives/android-arm64-profile/analyze-snapshot-linux-x64.zip",
                         "out/android_profile_arm64/zip_archives/download.flutter.io"
                     ]
                 }
@@ -152,7 +155,8 @@
                 "targets": [
                     "default",
                     "clang_x64/gen_snapshot",
-                    "flutter/shell/platform/android:abi_jars"
+                    "flutter/shell/platform/android:abi_jars",
+                    "flutter/shell/platform/android:analyze_snapshot"
                 ]
             },
             "tests": []
@@ -167,6 +171,7 @@
                         "out/android_profile_x64/zip_archives/android-x64-profile/artifacts.zip",
                         "out/android_profile_x64/zip_archives/android-x64-profile/linux-x64.zip",
                         "out/android_profile_x64/zip_archives/android-x64-profile/symbols.zip",
+                        "out/android_profile_x64/zip_archives/android-x64-profile/analyze-snapshot-linux-x64.zip",
                         "out/android_profile_x64/zip_archives/download.flutter.io"
                     ]
                 }
@@ -191,7 +196,8 @@
                 "targets": [
                     "default",
                     "clang_x64/gen_snapshot",
-                    "flutter/shell/platform/android:abi_jars"
+                    "flutter/shell/platform/android:abi_jars",
+                    "flutter/shell/platform/android:analyze_snapshot"
                 ]
             },
             "tests": []
@@ -206,6 +212,7 @@
                         "out/android_release_x64/zip_archives/android-x64-release/artifacts.zip",
                         "out/android_release_x64/zip_archives/android-x64-release/linux-x64.zip",
                         "out/android_release_x64/zip_archives/android-x64-release/symbols.zip",
+                        "out/android_release_x64/zip_archives/android-x64-release/analyze-snapshot-linux-x64.zip",
                         "out/android_release_x64/zip_archives/download.flutter.io"
                     ]
                 }
@@ -230,7 +237,8 @@
                 "targets": [
                     "default",
                     "clang_x64/gen_snapshot",
-                    "flutter/shell/platform/android:abi_jars"
+                    "flutter/shell/platform/android:abi_jars",
+                    "flutter/shell/platform/android:analyze_snapshot"
                 ]
             },
             "tests": []
diff --git a/ci/builders/linux_web_engine.json b/ci/builders/linux_web_engine.json
index e1b1c13..af80baa 100644
--- a/ci/builders/linux_web_engine.json
+++ b/ci/builders/linux_web_engine.json
@@ -8,7 +8,8 @@
                     "type": "gcs",
                     "include_paths": [
                         "out/wasm_release/zip_archives/flutter-web-sdk.zip"
-                    ]
+                    ],
+                    "realm": "production"
                 }
             ],
             "drone_dimensions": [
diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files
index 11d1a1a..2d0dbbe 100644
--- a/ci/licenses_golden/excluded_files
+++ b/ci/licenses_golden/excluded_files
@@ -275,7 +275,6 @@
 ../../../flutter/shell/platform/fuchsia/flutter/accessibility_bridge_unittest.cc
 ../../../flutter/shell/platform/fuchsia/flutter/build/asset_package.py
 ../../../flutter/shell/platform/fuchsia/flutter/build/gen_debug_wrapper_main.py
-../../../flutter/shell/platform/fuchsia/flutter/component_v1_unittest.cc
 ../../../flutter/shell/platform/fuchsia/flutter/component_v2_unittest.cc
 ../../../flutter/shell/platform/fuchsia/flutter/focus_delegate_unittests.cc
 ../../../flutter/shell/platform/fuchsia/flutter/fuchsia_intl_unittest.cc
diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter
index 5ab7c54..e0abd2e 100644
--- a/ci/licenses_golden/licenses_flutter
+++ b/ci/licenses_golden/licenses_flutter
@@ -2744,8 +2744,6 @@
 ORIGIN: ../../../flutter/shell/platform/fuchsia/dart_runner/vmservice/empty.dart + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/shell/platform/fuchsia/flutter/accessibility_bridge.cc + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/shell/platform/fuchsia/flutter/accessibility_bridge.h + ../../../flutter/LICENSE
-ORIGIN: ../../../flutter/shell/platform/fuchsia/flutter/component_v1.cc + ../../../flutter/LICENSE
-ORIGIN: ../../../flutter/shell/platform/fuchsia/flutter/component_v1.h + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/shell/platform/fuchsia/flutter/component_v2.cc + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/shell/platform/fuchsia/flutter/component_v2.h + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/shell/platform/fuchsia/flutter/engine.cc + ../../../flutter/LICENSE
@@ -5295,8 +5293,6 @@
 FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/vmservice/empty.dart
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/accessibility_bridge.cc
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/accessibility_bridge.h
-FILE: ../../../flutter/shell/platform/fuchsia/flutter/component_v1.cc
-FILE: ../../../flutter/shell/platform/fuchsia/flutter/component_v1.h
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/component_v2.cc
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/component_v2.h
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/engine.cc
@@ -5329,19 +5325,11 @@
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/keyboard.h
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/logging.h
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/main.cc
-FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/aot_product_runtime
-FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/aot_runtime
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/common.shard.cml
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/flutter_aot_product_runner.cml
-FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/flutter_aot_product_runner.cmx
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/flutter_aot_runner.cml
-FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/flutter_aot_runner.cmx
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/flutter_jit_product_runner.cml
-FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/flutter_jit_product_runner.cmx
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/flutter_jit_runner.cml
-FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/flutter_jit_runner.cmx
-FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/jit_product_runtime
-FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/jit_runtime
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/platform_view.cc
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/platform_view.h
 FILE: ../../../flutter/shell/platform/fuchsia/flutter/pointer_delegate.cc
diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia
index e7c7512..35bdd6b 100644
--- a/ci/licenses_golden/licenses_skia
+++ b/ci/licenses_golden/licenses_skia
@@ -1,4 +1,4 @@
-Signature: 31a48d3b6608c2afe988dde9b6ed3d7a
+Signature: 0bb6840486c80db920cb2ed91500f705
 
 ====================================================================================================
 LIBRARY: etc1
@@ -8416,6 +8416,8 @@
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/dawn/DawnCommandBuffer.h + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/dawn/DawnGraphicsPipeline.cpp + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/dawn/DawnGraphicsPipeline.h + ../../../third_party/skia/LICENSE
+ORIGIN: ../../../third_party/skia/src/gpu/graphite/dawn/DawnGraphiteUtils.cpp + ../../../third_party/skia/LICENSE
+ORIGIN: ../../../third_party/skia/src/gpu/graphite/dawn/DawnGraphiteUtilsPriv.h + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/dawn/DawnQueueManager.cpp + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/dawn/DawnQueueManager.h + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/dawn/DawnResourceProvider.cpp + ../../../third_party/skia/LICENSE
@@ -8427,8 +8429,6 @@
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/dawn/DawnTexture.cpp + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/dawn/DawnTexture.h + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/dawn/DawnTypesPriv.cpp + ../../../third_party/skia/LICENSE
-ORIGIN: ../../../third_party/skia/src/gpu/graphite/dawn/DawnUtils.cpp + ../../../third_party/skia/LICENSE
-ORIGIN: ../../../third_party/skia/src/gpu/graphite/dawn/DawnUtilsPriv.h + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/geom/Geometry.h + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/geom/SubRunData.h + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/mtl/MtlComputePipeline.h + ../../../third_party/skia/LICENSE
@@ -8641,6 +8641,8 @@
 FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnCommandBuffer.h
 FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnGraphicsPipeline.cpp
 FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnGraphicsPipeline.h
+FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnGraphiteUtils.cpp
+FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnGraphiteUtilsPriv.h
 FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnQueueManager.cpp
 FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnQueueManager.h
 FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnResourceProvider.cpp
@@ -8652,8 +8654,6 @@
 FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnTexture.cpp
 FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnTexture.h
 FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnTypesPriv.cpp
-FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnUtils.cpp
-FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnUtilsPriv.h
 FILE: ../../../third_party/skia/src/gpu/graphite/geom/Geometry.h
 FILE: ../../../third_party/skia/src/gpu/graphite/geom/SubRunData.h
 FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlComputePipeline.h
@@ -8957,6 +8957,7 @@
 ORIGIN: ../../../third_party/skia/fuzz/FuzzCubicQuadRoots.cpp + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/fuzz/oss_fuzz/FuzzCubicQuadRoots.cpp + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/gm/graphite_replay.cpp + ../../../third_party/skia/LICENSE
+ORIGIN: ../../../third_party/skia/include/gpu/graphite/YUVABackendTextures.h + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/include/private/base/SkCPUTypes.h + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/base/SkBezierCurves.h + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/base/SkCubics.cpp + ../../../third_party/skia/LICENSE
@@ -8976,6 +8977,7 @@
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/Image_YUVA_Graphite.cpp + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/Image_YUVA_Graphite.h + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/ReadWriteSwizzle.h + ../../../third_party/skia/LICENSE
+ORIGIN: ../../../third_party/skia/src/gpu/graphite/YUVABackendTextures.cpp + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/YUVATextureProxies.cpp + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/YUVATextureProxies.h + ../../../third_party/skia/LICENSE
 ORIGIN: ../../../third_party/skia/src/gpu/graphite/compute/ComputeStep.cpp + ../../../third_party/skia/LICENSE
@@ -8992,6 +8994,7 @@
 FILE: ../../../third_party/skia/fuzz/FuzzCubicQuadRoots.cpp
 FILE: ../../../third_party/skia/fuzz/oss_fuzz/FuzzCubicQuadRoots.cpp
 FILE: ../../../third_party/skia/gm/graphite_replay.cpp
+FILE: ../../../third_party/skia/include/gpu/graphite/YUVABackendTextures.h
 FILE: ../../../third_party/skia/include/private/base/SkCPUTypes.h
 FILE: ../../../third_party/skia/src/base/SkBezierCurves.h
 FILE: ../../../third_party/skia/src/base/SkCubics.cpp
@@ -9011,6 +9014,7 @@
 FILE: ../../../third_party/skia/src/gpu/graphite/Image_YUVA_Graphite.cpp
 FILE: ../../../third_party/skia/src/gpu/graphite/Image_YUVA_Graphite.h
 FILE: ../../../third_party/skia/src/gpu/graphite/ReadWriteSwizzle.h
+FILE: ../../../third_party/skia/src/gpu/graphite/YUVABackendTextures.cpp
 FILE: ../../../third_party/skia/src/gpu/graphite/YUVATextureProxies.cpp
 FILE: ../../../third_party/skia/src/gpu/graphite/YUVATextureProxies.h
 FILE: ../../../third_party/skia/src/gpu/graphite/compute/ComputeStep.cpp
@@ -9057,6 +9061,45 @@
 
 ====================================================================================================
 LIBRARY: skia
+ORIGIN: ../../../third_party/skia/src/core/SkFontMetricsPriv.cpp + ../../../third_party/skia/LICENSE
+ORIGIN: ../../../third_party/skia/src/core/SkFontMetricsPriv.h + ../../../third_party/skia/LICENSE
+TYPE: LicenseType.bsd
+FILE: ../../../third_party/skia/src/core/SkFontMetricsPriv.cpp
+FILE: ../../../third_party/skia/src/core/SkFontMetricsPriv.h
+----------------------------------------------------------------------------------------------------
+Copyright 2023 Google LLC.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+  * Neither the name of the copyright holder nor the names of its
+    contributors may be used to endorse or promote products derived
+    from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+====================================================================================================
+
+====================================================================================================
+LIBRARY: skia
 ORIGIN: ../../../third_party/skia/src/shaders/SkCoordClampShader.cpp + ../../../third_party/skia/LICENSE
 TYPE: LicenseType.bsd
 FILE: ../../../third_party/skia/src/shaders/SkCoordClampShader.cpp
@@ -9092,4 +9135,4 @@
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ====================================================================================================
 
-Total license count: 66
+Total license count: 67
diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party
index 8b25e72..a6e5009 100644
--- a/ci/licenses_golden/licenses_third_party
+++ b/ci/licenses_golden/licenses_third_party
@@ -1,4 +1,4 @@
-Signature: 479841c56f2e6285f5971d095ed2306c
+Signature: 692acb95337a57802d84427dbd848abf
 
 ====================================================================================================
 LIBRARY: angle
diff --git a/display_list/display_list_builder.h b/display_list/display_list_builder.h
index 4226d6a..58e20f1 100644
--- a/display_list/display_list_builder.h
+++ b/display_list/display_list_builder.h
@@ -446,7 +446,7 @@
 
     bool has_layer() const { return has_layer_; }
     bool cannot_inherit_opacity() const { return cannot_inherit_opacity_; }
-    bool has_compatible_op() const { return cannot_inherit_opacity_; }
+    bool has_compatible_op() const { return has_compatible_op_; }
 
     bool is_group_opacity_compatible() const {
       return !cannot_inherit_opacity_;
diff --git a/display_list/display_list_unittests.cc b/display_list/display_list_unittests.cc
index c7b2311..9b942bb 100644
--- a/display_list/display_list_unittests.cc
+++ b/display_list/display_list_unittests.cc
@@ -2403,5 +2403,17 @@
   }
 }
 
+TEST(DisplayListTest, DrawSaveDrawCannotInheritOpacity) {
+  DisplayListBuilder builder;
+  builder.DrawCircle({10, 10}, 5, DlPaint());
+  builder.Save();
+  builder.ClipRect({0, 0, 20, 20}, DlCanvas::ClipOp::kIntersect, false);
+  builder.DrawRect({5, 5, 15, 15}, DlPaint());
+  builder.Restore();
+  auto display_list = builder.Build();
+
+  ASSERT_FALSE(display_list->can_apply_group_opacity());
+}
+
 }  // namespace testing
 }  // namespace flutter
diff --git a/fml/concurrent_message_loop.cc b/fml/concurrent_message_loop.cc
index 681b983..f553654 100644
--- a/fml/concurrent_message_loop.cc
+++ b/fml/concurrent_message_loop.cc
@@ -170,4 +170,14 @@
   task();
 }
 
+bool ConcurrentMessageLoop::RunsTasksOnCurrentThread() {
+  std::scoped_lock lock(tasks_mutex_);
+  for (const auto& worker_thread_id : worker_thread_ids_) {
+    if (worker_thread_id == std::this_thread::get_id()) {
+      return true;
+    }
+  }
+  return false;
+}
+
 }  // namespace fml
diff --git a/fml/concurrent_message_loop.h b/fml/concurrent_message_loop.h
index c043705..ab8534b 100644
--- a/fml/concurrent_message_loop.h
+++ b/fml/concurrent_message_loop.h
@@ -34,6 +34,8 @@
 
   void PostTaskToAllWorkers(const fml::closure& task);
 
+  bool RunsTasksOnCurrentThread();
+
  private:
   friend ConcurrentTaskRunner;
 
diff --git a/impeller/entity/shaders/linear_gradient_ssbo_fill.frag b/impeller/entity/shaders/linear_gradient_ssbo_fill.frag
index 718e319..45e4f9c 100644
--- a/impeller/entity/shaders/linear_gradient_ssbo_fill.frag
+++ b/impeller/entity/shaders/linear_gradient_ssbo_fill.frag
@@ -21,7 +21,7 @@
   vec2 end_point;
   float alpha;
   float tile_mode;
-  float colors_length;
+  int colors_length;
 }
 frag_info;
 
diff --git a/impeller/entity/shaders/radial_gradient_ssbo_fill.frag b/impeller/entity/shaders/radial_gradient_ssbo_fill.frag
index e870d27..6a05b4b 100644
--- a/impeller/entity/shaders/radial_gradient_ssbo_fill.frag
+++ b/impeller/entity/shaders/radial_gradient_ssbo_fill.frag
@@ -21,7 +21,7 @@
   float radius;
   float tile_mode;
   float alpha;
-  float colors_length;
+  int colors_length;
 }
 frag_info;
 
diff --git a/impeller/entity/shaders/sweep_gradient_ssbo_fill.frag b/impeller/entity/shaders/sweep_gradient_ssbo_fill.frag
index 8370b3c..34bcb74 100644
--- a/impeller/entity/shaders/sweep_gradient_ssbo_fill.frag
+++ b/impeller/entity/shaders/sweep_gradient_ssbo_fill.frag
@@ -23,7 +23,7 @@
   float scale;
   float tile_mode;
   float alpha;
-  float colors_length;
+  int colors_length;
 }
 frag_info;
 
diff --git a/impeller/fixtures/stroke.comp b/impeller/fixtures/stroke.comp
index 57d9555..5a48a29 100644
--- a/impeller/fixtures/stroke.comp
+++ b/impeller/fixtures/stroke.comp
@@ -17,11 +17,15 @@
 polyline;
 
 layout(binding = 1) buffer VertexBuffer {
-  uint count;
   vec2 position[];
 }
 vertex_buffer;
 
+layout(binding = 2) buffer VertexBufferCount {
+  uint count;
+}
+vertex_buffer_count;
+
 uniform Config {
   float width;
   uint cap;
@@ -41,7 +45,7 @@
     return;
   }
 
-  atomicAdd(vertex_buffer.count, 4);
+  atomicAdd(vertex_buffer_count.count, 4);
 
   vec2 offset = compute_offset(ident);
   uint index = ident - 1;
diff --git a/impeller/playground/compute_playground_test.cc b/impeller/playground/compute_playground_test.cc
index 165a6f9..eda0b2c 100644
--- a/impeller/playground/compute_playground_test.cc
+++ b/impeller/playground/compute_playground_test.cc
@@ -24,6 +24,7 @@
   }
 
   SetupContext(GetParam());
+  SetupWindow();
 
   start_time_ = fml::TimePoint::Now().ToEpochDelta();
 }
diff --git a/impeller/playground/compute_playground_test.h b/impeller/playground/compute_playground_test.h
index 06c480b..af9edf7 100644
--- a/impeller/playground/compute_playground_test.h
+++ b/impeller/playground/compute_playground_test.h
@@ -11,6 +11,7 @@
 #include "flutter/testing/testing.h"
 #include "impeller/geometry/scalar.h"
 #include "impeller/playground/playground.h"
+#include "impeller/renderer/device_buffer.h"
 
 namespace impeller {
 
@@ -36,6 +37,18 @@
   // |Playground|
   std::string GetWindowTitle() const override;
 
+  template <typename T>
+  std::shared_ptr<DeviceBuffer> CreateHostVisibleDeviceBuffer(
+      std::shared_ptr<Context> context,
+      const std::string& label) {
+    DeviceBufferDescriptor desc;
+    desc.storage_mode = StorageMode::kHostVisible;
+    desc.size = sizeof(T);
+    auto buffer = context->GetResourceAllocator()->CreateBuffer(desc);
+    buffer->SetLabel(label);
+    return buffer;
+  }
+
  private:
   fml::TimeDelta start_time_;
 
diff --git a/impeller/renderer/BUILD.gn b/impeller/renderer/BUILD.gn
index 2ac5e90..792fc8e 100644
--- a/impeller/renderer/BUILD.gn
+++ b/impeller/renderer/BUILD.gn
@@ -121,6 +121,7 @@
 
   deps = [
     ":renderer",
+    "../entity",
     "../fixtures",
     "../playground:playground_test",
     "//flutter/testing:testing_lib",
diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc
index 220eca3..f1c1e21 100644
--- a/impeller/renderer/backend/vulkan/allocator_vk.cc
+++ b/impeller/renderer/backend/vulkan/allocator_vk.cc
@@ -252,7 +252,7 @@
                                               &allocation_info      //
                                               )};
       if (result != vk::Result::eSuccess) {
-        VALIDATION_LOG << "Unable to allocation Vulkan Image: "
+        VALIDATION_LOG << "Unable to allocate Vulkan Image: "
                        << vk::to_string(result);
         return;
       }
diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc
index c1ac785..a797491 100644
--- a/impeller/renderer/backend/vulkan/context_vk.cc
+++ b/impeller/renderer/backend/vulkan/context_vk.cc
@@ -51,7 +51,7 @@
   }
 
   const auto prefix = impeller::vk::to_string(
-      impeller::vk::DebugUtilsMessageSeverityFlagBitsEXT{severity});
+      impeller::vk::DebugUtilsMessageSeverityFlagBitsEXT(severity));
   // Just so that the log doesn't say FML_DCHECK(false).
   constexpr bool kVulkanValidationFailure = false;
   FML_DCHECK(kVulkanValidationFailure)
diff --git a/impeller/renderer/compute_subgroup_unittests.cc b/impeller/renderer/compute_subgroup_unittests.cc
index 5ebcb33..1b93ae6 100644
--- a/impeller/renderer/compute_subgroup_unittests.cc
+++ b/impeller/renderer/compute_subgroup_unittests.cc
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <numeric>
+
 #include "flutter/fml/synchronization/waitable_event.h"
 #include "flutter/fml/time/time_point.h"
 #include "flutter/testing/testing.h"
 #include "gmock/gmock.h"
 #include "impeller/base/strings.h"
+#include "impeller/entity/contents/content_context.h"
 #include "impeller/fixtures/cubic_to_quads.comp.h"
 #include "impeller/fixtures/golden_heart.h"
 #include "impeller/fixtures/quad_polyline.comp.h"
@@ -22,6 +25,7 @@
 #include "impeller/renderer/compute_pipeline_builder.h"
 #include "impeller/renderer/formats.h"
 #include "impeller/renderer/pipeline_library.h"
+#include "impeller/renderer/render_pass.h"
 
 namespace impeller {
 namespace testing {
@@ -44,27 +48,21 @@
   static constexpr size_t kCubicCount = 6;
   static constexpr Scalar kAccuracy = .1;
 
-  DeviceBufferDescriptor quad_buffer_desc;
-  quad_buffer_desc.storage_mode = StorageMode::kHostVisible;
-  quad_buffer_desc.size = sizeof(CS::Quads<kCubicCount * 10>);
-  auto quads = context->GetResourceAllocator()->CreateBuffer(quad_buffer_desc);
-  quads->SetLabel("Quads");
+  auto quads = CreateHostVisibleDeviceBuffer<CS::Quads<kCubicCount * 10>>(
+      context, "Quads");
 
-  DeviceBufferDescriptor point_buffer_desc;
-  point_buffer_desc.storage_mode = StorageMode::kHostVisible;
   // TODO(dnfield): Size this buffer more accurately.
-  point_buffer_desc.size = sizeof(QS::Polyline<kCubicCount * 10 * 10>);
   auto polyline =
-      context->GetResourceAllocator()->CreateBuffer(point_buffer_desc);
-  polyline->SetLabel("polyline");
+      CreateHostVisibleDeviceBuffer<QS::Polyline<kCubicCount * 10 * 10>>(
+          context, "polyline");
 
-  DeviceBufferDescriptor vertex_buffer_desc;
-  vertex_buffer_desc.storage_mode = StorageMode::kHostVisible;
+  auto vertex_buffer_count =
+      CreateHostVisibleDeviceBuffer<SS::VertexBufferCount>(context,
+                                                           "VertexBufferCount");
+
   // TODO(dnfield): Size this buffer more accurately.
-  vertex_buffer_desc.size = sizeof(SS::VertexBuffer<kCubicCount * 10 * 10 * 4>);
-  auto vertex_buffer =
-      context->GetResourceAllocator()->CreateBuffer(vertex_buffer_desc);
-  vertex_buffer->SetLabel("VertexBuffer");
+  auto vertex_buffer = CreateHostVisibleDeviceBuffer<
+      SS::VertexBuffer<kCubicCount * 10 * 10 * 4>>(context, "VertexBuffer");
 
   {
     using CubicPipelineBuilder = ComputePipelineBuilder<CS>;
@@ -138,13 +136,14 @@
     pass->SetThreadGroupSize(ISize(1024, 1));
 
     ComputeCommand cmd;
-    cmd.label = "Stroke";
+    cmd.label = "Draw Stroke";
     cmd.pipeline = compute_pipeline;
 
     SS::Config config{.width = 1.0f, .cap = 1, .join = 1, .miter_limit = 4.0f};
     SS::BindConfig(cmd, pass->GetTransientsBuffer().EmplaceUniform(config));
 
     SS::BindPolyline(cmd, polyline->AsBufferView());
+    SS::BindVertexBufferCount(cmd, vertex_buffer_count->AsBufferView());
     SS::BindVertexBuffer(cmd, vertex_buffer->AsBufferView());
 
     ASSERT_TRUE(pass->AddCommand(std::move(cmd)));
@@ -154,7 +153,7 @@
 
   fml::AutoResetWaitableEvent latch;
   ASSERT_TRUE(cmd_buffer->SubmitCommands([&latch, quads, polyline,
-                                          vertex_buffer](
+                                          vertex_buffer_count, vertex_buffer](
                                              CommandBuffer::Status status) {
     EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
 
@@ -183,7 +182,9 @@
 
     auto* v = reinterpret_cast<SS::VertexBuffer<kCubicCount * 10 * 10 * 4>*>(
         vertex_buffer->AsBufferView().contents);
-    EXPECT_EQ(v->count, golden_heart_vertices.size());
+    auto* v_count = reinterpret_cast<SS::VertexBufferCount*>(
+        vertex_buffer_count->AsBufferView().contents);
+    EXPECT_EQ(v_count->count, golden_heart_vertices.size());
     for (size_t i = 0; i < golden_heart_vertices.size(); i += 1) {
       EXPECT_LT(std::abs(golden_heart_vertices[i].x - v->position[i].x), 1e-3);
       EXPECT_LT(std::abs(golden_heart_vertices[i].y - v->position[i].y), 1e-3);
@@ -193,6 +194,64 @@
   }));
 
   latch.Wait();
+
+  auto callback = [&](RenderPass& pass) -> bool {
+    ContentContext renderer(context);
+    if (!renderer.IsValid()) {
+      return false;
+    }
+
+    using VS = SolidFillPipeline::VertexShader;
+    using FS = SolidFillPipeline::FragmentShader;
+
+    Command cmd;
+    cmd.label = "Draw Stroke";
+    cmd.stencil_reference = 0;  // entity.GetStencilDepth();
+
+    ContentContextOptions options;
+    options.sample_count = pass.GetRenderTarget().GetSampleCount();
+    options.color_attachment_pixel_format =
+        pass.GetRenderTarget().GetRenderTargetPixelFormat();
+    options.has_stencil_attachment =
+        pass.GetRenderTarget().GetStencilAttachment().has_value();
+    options.blend_mode = BlendMode::kSourceIn;  // entity.GetBlendMode();
+    options.primitive_type = PrimitiveType::kTriangleStrip;
+    options.stencil_compare = CompareFunction::kEqual;
+    options.stencil_operation = StencilOperation::kIncrementClamp;
+
+    cmd.pipeline = renderer.GetSolidFillPipeline(options);
+
+    auto count = golden_heart_vertices.size();
+    auto& host_buffer = pass.GetTransientsBuffer();
+    std::vector<uint16_t> indices(count);
+    std::iota(std::begin(indices), std::end(indices), 0);
+
+    VertexBuffer render_vertex_buffer{
+        .vertex_buffer = vertex_buffer->AsBufferView(),
+        .index_buffer = host_buffer.Emplace(
+            indices.data(), count * sizeof(uint16_t), alignof(uint16_t)),
+        .index_count = count,
+        .index_type = IndexType::k16bit};
+    cmd.BindVertices(render_vertex_buffer);
+
+    VS::FrameInfo frame_info;
+    auto world_matrix = Matrix::MakeScale(GetContentScale());
+    frame_info.mvp =
+        Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * world_matrix;
+    VS::BindFrameInfo(cmd,
+                      pass.GetTransientsBuffer().EmplaceUniform(frame_info));
+
+    FS::FragInfo frag_info;
+    frag_info.color = Color::Red().Premultiply();
+    FS::BindFragInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frag_info));
+
+    if (!pass.AddCommand(std::move(cmd))) {
+      return false;
+    }
+
+    return true;
+  };
+  ASSERT_TRUE(OpenPlaygroundHere(callback));
 }
 
 TEST_P(ComputeTest, QuadsToPolyline) {
@@ -215,12 +274,8 @@
                      golden_heart_quads[i].p2};
   }
 
-  DeviceBufferDescriptor point_buffer_desc;
-  point_buffer_desc.storage_mode = StorageMode::kHostVisible;
-  point_buffer_desc.size = sizeof(QS::Polyline<kPolylineCount>);
-  auto polyline =
-      context->GetResourceAllocator()->CreateBuffer(point_buffer_desc);
-  polyline->SetLabel("polyline");
+  auto polyline = CreateHostVisibleDeviceBuffer<QS::Polyline<kPolylineCount>>(
+      context, "polyline");
 
   {
     using QuadPipelineBuilder = ComputePipelineBuilder<QS>;
diff --git a/impeller/renderer/compute_unittests.cc b/impeller/renderer/compute_unittests.cc
index cfa50e0..ffed4bd 100644
--- a/impeller/renderer/compute_unittests.cc
+++ b/impeller/renderer/compute_unittests.cc
@@ -54,7 +54,7 @@
   CS::Info info{.count = kCount};
   CS::Input0<kCount> input_0;
   CS::Input1<kCount> input_1;
-  for (uint i = 0; i < kCount; i++) {
+  for (size_t i = 0; i < kCount; i++) {
     input_0.elements[i] = Vector4(2.0 + i, 3.0 + i, 4.0 + i, 5.0 * i);
     input_1.elements[i] = Vector4(6.0, 7.0, 8.0, 9.0);
   }
@@ -64,13 +64,8 @@
   input_0.some_int = 5;
   input_1.some_struct = CS::SomeStruct{.vf = Point(3, 4), .i = 42};
 
-  DeviceBufferDescriptor buffer_desc;
-  buffer_desc.storage_mode = StorageMode::kHostVisible;
-  buffer_desc.size = sizeof(CS::Output<kCount>);
-
-  auto output_buffer =
-      context->GetResourceAllocator()->CreateBuffer(buffer_desc);
-  output_buffer->SetLabel("Output Buffer");
+  auto output_buffer = CreateHostVisibleDeviceBuffer<CS::Output<kCount>>(
+      context, "Output Buffer");
 
   CS::BindInfo(cmd, pass->GetTransientsBuffer().EmplaceUniform(info));
   CS::BindInput0(cmd,
@@ -144,31 +139,20 @@
 
   CS1::Input<kCount1> input_1;
   input_1.count = kCount1;
-  for (uint i = 0; i < kCount1; i++) {
+  for (size_t i = 0; i < kCount1; i++) {
     input_1.elements[i] = i;
   }
 
   CS2::Input<kCount2> input_2;
   input_2.count = kCount2;
-  for (uint i = 0; i < kCount2; i++) {
+  for (size_t i = 0; i < kCount2; i++) {
     input_2.elements[i] = i;
   }
 
-  DeviceBufferDescriptor output_desc_1;
-  output_desc_1.storage_mode = StorageMode::kHostVisible;
-  output_desc_1.size = sizeof(CS1::Output<kCount2>);
-
-  auto output_buffer_1 =
-      context->GetResourceAllocator()->CreateBuffer(output_desc_1);
-  output_buffer_1->SetLabel("Output Buffer Stage 1");
-
-  DeviceBufferDescriptor output_desc_2;
-  output_desc_2.storage_mode = StorageMode::kHostVisible;
-  output_desc_2.size = sizeof(CS2::Output<kCount2>);
-
-  auto output_buffer_2 =
-      context->GetResourceAllocator()->CreateBuffer(output_desc_2);
-  output_buffer_2->SetLabel("Output Buffer Stage 2");
+  auto output_buffer_1 = CreateHostVisibleDeviceBuffer<CS1::Output<kCount2>>(
+      context, "Output Buffer Stage 1");
+  auto output_buffer_2 = CreateHostVisibleDeviceBuffer<CS2::Output<kCount2>>(
+      context, "Output Buffer Stage 2");
 
   {
     ComputeCommand cmd;
diff --git a/impeller/tools/impeller.gni b/impeller/tools/impeller.gni
index 4f864b4..14bbbc9 100644
--- a/impeller/tools/impeller.gni
+++ b/impeller/tools/impeller.gni
@@ -18,7 +18,7 @@
   impeller_enable_opengles = is_mac || is_linux || is_win || is_android
 
   # Whether the Vulkan backend is enabled.
-  impeller_enable_vulkan = is_mac || is_linux || is_android
+  impeller_enable_vulkan = is_mac || is_linux || is_win || is_android
 
   # Whether to use a prebuilt impellerc.
   # If this is the empty string, impellerc will be built.
diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart
index 30cc3d3..ee2d173 100644
--- a/lib/ui/painting.dart
+++ b/lib/ui/painting.dart
@@ -6294,7 +6294,12 @@
     final ImmutableBuffer instance = ImmutableBuffer._(0);
     return _futurize((_Callback<int> callback) {
       return instance._initFromAsset(encodedKey, callback);
-    }).then((int length) => instance.._length = length);
+    }).then((int length) {
+      if (length == -1) {
+        throw Exception('Asset not found');
+      }
+      return instance.._length = length;
+    });
   }
 
   /// Create a buffer from the file with [path].
diff --git a/lib/ui/painting/image_decoder_impeller.cc b/lib/ui/painting/image_decoder_impeller.cc
index bd94028..04c4cd8 100644
--- a/lib/ui/painting/image_decoder_impeller.cc
+++ b/lib/ui/painting/image_decoder_impeller.cc
@@ -54,9 +54,12 @@
 
 // Source:
 // https://source.chromium.org/chromium/_/skia/skia.git/+/393fb1ec80f41d8ad7d104921b6920e69749fda1:src/codec/SkAndroidCodec.cpp;l=67;drc=46572b4d445f41943059d0e377afc6d6748cd5ca;bpv=1;bpt=0
-bool IsWideGamut(const SkColorSpace& color_space) {
+bool IsWideGamut(const SkColorSpace* color_space) {
+  if (!color_space) {
+    return false;
+  }
   skcms_Matrix3x3 xyzd50;
-  color_space.toXYZD50(&xyzd50);
+  color_space->toXYZD50(&xyzd50);
   SkPoint rgb[3];
   LoadGamut(rgb, xyzd50);
   float area = CalculateArea(rgb);
@@ -134,7 +137,7 @@
 
   const auto base_image_info = descriptor->image_info();
   const bool is_wide_gamut =
-      supports_wide_gamut ? IsWideGamut(*base_image_info.colorSpace()) : false;
+      supports_wide_gamut ? IsWideGamut(base_image_info.colorSpace()) : false;
   SkAlphaType alpha_type =
       ChooseCompatibleAlphaType(base_image_info.alphaType());
   SkImageInfo image_info;
diff --git a/lib/ui/painting/image_decoder_unittests.cc b/lib/ui/painting/image_decoder_unittests.cc
index 587ae4d..551947a 100644
--- a/lib/ui/painting/image_decoder_unittests.cc
+++ b/lib/ui/painting/image_decoder_unittests.cc
@@ -290,6 +290,31 @@
 }
 }  // namespace
 
+TEST_F(ImageDecoderFixtureTest, ImpellerNullColorspace) {
+  auto info = SkImageInfo::Make(10, 10, SkColorType::kRGBA_8888_SkColorType,
+                                SkAlphaType::kPremul_SkAlphaType);
+  SkBitmap bitmap;
+  bitmap.allocPixels(info, 10 * 4);
+  auto data = SkData::MakeWithoutCopy(bitmap.getPixels(), 10 * 10 * 4);
+  auto image = SkImage::MakeFromBitmap(bitmap);
+  ASSERT_TRUE(image != nullptr);
+  ASSERT_EQ(SkISize::Make(10, 10), image->dimensions());
+  ASSERT_EQ(nullptr, image->colorSpace());
+
+  auto descriptor = fml::MakeRefCounted<ImageDescriptor>(
+      std::move(data), image->imageInfo(), 10 * 4);
+
+#if IMPELLER_SUPPORTS_RENDERING
+  std::shared_ptr<SkBitmap> decompressed =
+      ImageDecoderImpeller::DecompressTexture(
+          descriptor.get(), SkISize::Make(100, 100), {100, 100},
+          /*supports_wide_gamut=*/true);
+  ASSERT_TRUE(decompressed);
+  ASSERT_EQ(decompressed->colorType(), kRGBA_8888_SkColorType);
+  ASSERT_EQ(decompressed->colorSpace(), nullptr);
+#endif  // IMPELLER_SUPPORTS_RENDERING
+}
+
 TEST_F(ImageDecoderFixtureTest, ImpellerWideGamutDisplayP3) {
   auto data = OpenFixtureAsSkData("DisplayP3Logo.png");
   auto image = SkImage::MakeFromEncoded(data);
diff --git a/lib/ui/painting/immutable_buffer.cc b/lib/ui/painting/immutable_buffer.cc
index 0d86b07..0f859f3 100644
--- a/lib/ui/painting/immutable_buffer.cc
+++ b/lib/ui/painting/immutable_buffer.cc
@@ -43,7 +43,7 @@
   return Dart_Null();
 }
 
-Dart_Handle ImmutableBuffer::initFromAsset(Dart_Handle buffer_handle,
+Dart_Handle ImmutableBuffer::initFromAsset(Dart_Handle raw_buffer_handle,
                                            Dart_Handle asset_name_handle,
                                            Dart_Handle callback_handle) {
   UIDartState::ThrowIfUIOperationsProhibited();
@@ -62,21 +62,60 @@
   std::string asset_name = std::string{reinterpret_cast<const char*>(chars),
                                        static_cast<size_t>(asset_length)};
 
-  std::shared_ptr<AssetManager> asset_manager = UIDartState::Current()
-                                                    ->platform_configuration()
-                                                    ->client()
-                                                    ->GetAssetManager();
-  std::unique_ptr<fml::Mapping> data = asset_manager->GetAsMapping(asset_name);
-  if (data == nullptr) {
-    return tonic::ToDart("Asset not found");
-  }
+  auto* dart_state = UIDartState::Current();
+  auto ui_task_runner = dart_state->GetTaskRunners().GetUITaskRunner();
+  auto* buffer_callback_ptr =
+      new tonic::DartPersistentValue(dart_state, callback_handle);
+  auto* buffer_handle_ptr =
+      new tonic::DartPersistentValue(dart_state, raw_buffer_handle);
+  auto asset_manager = UIDartState::Current()
+                           ->platform_configuration()
+                           ->client()
+                           ->GetAssetManager();
 
-  auto size = data->GetSize();
-  const void* bytes = static_cast<const void*>(data->GetMapping());
-  auto sk_data = MakeSkDataWithCopy(bytes, size);
-  auto buffer = fml::MakeRefCounted<ImmutableBuffer>(sk_data);
-  buffer->AssociateWithDartWrapper(buffer_handle);
-  tonic::DartInvoke(callback_handle, {tonic::ToDart(size)});
+  auto ui_task = fml::MakeCopyable(
+      [buffer_callback_ptr, buffer_handle_ptr](const sk_sp<SkData>& sk_data,
+                                               size_t buffer_size) mutable {
+        std::unique_ptr<tonic::DartPersistentValue> buffer_handle(
+            buffer_handle_ptr);
+        std::unique_ptr<tonic::DartPersistentValue> buffer_callback(
+            buffer_callback_ptr);
+
+        auto dart_state = buffer_callback->dart_state().lock();
+        if (!dart_state) {
+          return;
+        }
+        tonic::DartState::Scope scope(dart_state);
+
+        if (!sk_data) {
+          // -1 is used as a sentinel that the file could not be opened.
+          tonic::DartInvoke(buffer_callback->Get(), {tonic::ToDart(-1)});
+          return;
+        }
+        auto buffer = fml::MakeRefCounted<ImmutableBuffer>(sk_data);
+        buffer->AssociateWithDartWrapper(buffer_handle->Get());
+        tonic::DartInvoke(buffer_callback->Get(), {tonic::ToDart(buffer_size)});
+      });
+
+  dart_state->GetConcurrentTaskRunner()->PostTask(
+      [asset_name = std::move(asset_name),
+       asset_manager = std::move(asset_manager),
+       ui_task_runner = std::move(ui_task_runner), ui_task] {
+        std::unique_ptr<fml::Mapping> mapping =
+            asset_manager->GetAsMapping(asset_name);
+
+        sk_sp<SkData> sk_data;
+        size_t buffer_size = 0;
+        if (mapping != nullptr) {
+          buffer_size = mapping->GetSize();
+          const void* bytes = static_cast<const void*>(mapping->GetMapping());
+          sk_data = MakeSkDataWithCopy(bytes, buffer_size);
+        }
+        ui_task_runner->PostTask(
+            [sk_data = std::move(sk_data), ui_task = ui_task, buffer_size]() {
+              ui_task(sk_data, buffer_size);
+            });
+      });
   return Dart_Null();
 }
 
@@ -101,20 +140,24 @@
 
   auto* dart_state = UIDartState::Current();
   auto ui_task_runner = dart_state->GetTaskRunners().GetUITaskRunner();
-  auto buffer_callback =
-      std::make_unique<tonic::DartPersistentValue>(dart_state, callback_handle);
-  auto buffer_handle = std::make_unique<tonic::DartPersistentValue>(
-      dart_state, raw_buffer_handle);
+  auto* buffer_callback_ptr =
+      new tonic::DartPersistentValue(dart_state, callback_handle);
+  auto* buffer_handle_ptr =
+      new tonic::DartPersistentValue(dart_state, raw_buffer_handle);
 
   auto ui_task = fml::MakeCopyable(
-      [buffer_callback = std::move(buffer_callback),
-       buffer_handle = std::move(buffer_handle)](const sk_sp<SkData>& sk_data,
-                                                 size_t buffer_size) mutable {
+      [buffer_callback_ptr, buffer_handle_ptr](const sk_sp<SkData>& sk_data,
+                                               size_t buffer_size) mutable {
+        std::unique_ptr<tonic::DartPersistentValue> buffer_handle(
+            buffer_handle_ptr);
+        std::unique_ptr<tonic::DartPersistentValue> buffer_callback(
+            buffer_callback_ptr);
         auto dart_state = buffer_callback->dart_state().lock();
         if (!dart_state) {
           return;
         }
         tonic::DartState::Scope scope(dart_state);
+
         if (!sk_data) {
           // -1 is used as a sentinel that the file could not be opened.
           tonic::DartInvoke(buffer_callback->Get(), {tonic::ToDart(-1)});
diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
index d588da5..c5f739d 100644
--- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
+++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
@@ -1911,12 +1911,12 @@
   // into a utf16 string.
   String getText() => utf8.decode(getTextUtf8().codeUnits);
 
-  external void setWordsUtf8(Uint32List words);
-  external void setWordsUtf16(Uint32List words);
-  external void setGraphemeBreaksUtf8(Uint32List graphemes);
-  external void setGraphemeBreaksUtf16(Uint32List graphemes);
-  external void setLineBreaksUtf8(Uint32List lineBreaks);
-  external void setLineBreaksUtf16(Uint32List lineBreaks);
+  external void setWordsUtf8(SkUint32List words);
+  external void setWordsUtf16(SkUint32List words);
+  external void setGraphemeBreaksUtf8(SkUint32List graphemes);
+  external void setGraphemeBreaksUtf16(SkUint32List graphemes);
+  external void setLineBreaksUtf8(SkUint32List lineBreaks);
+  external void setLineBreaksUtf16(SkUint32List lineBreaks);
 
   external SkParagraph build();
   external void delete();
diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart
index a27aa97..596e87b 100644
--- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart
+++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart
@@ -389,8 +389,13 @@
           'If non-null, "colors" length must be one fourth the length of "rstTransforms" and "rects".');
     }
 
+    Uint32List? unsignedColors;
+    if (colors != null) {
+      unsignedColors = colors.buffer.asUint32List(colors.offsetInBytes, colors.length);
+    }
+
     _drawAtlas(paint, atlas, rstTransforms, rects,
-        colors?.buffer.asUint32List(), blendMode ?? ui.BlendMode.src);
+        unsignedColors, blendMode ?? ui.BlendMode.src);
   }
 
   // TODO(hterkelsen): Pass a cull_rect once CanvasKit supports that.
diff --git a/lib/web_ui/lib/src/engine/canvaskit/text_fragmenter.dart b/lib/web_ui/lib/src/engine/canvaskit/text_fragmenter.dart
index ef55f17..762b617 100644
--- a/lib/web_ui/lib/src/engine/canvaskit/text_fragmenter.dart
+++ b/lib/web_ui/lib/src/engine/canvaskit/text_fragmenter.dart
@@ -43,7 +43,7 @@
   IntlSegmenterGranularity.word: createIntlSegmenter(granularity: 'word'),
 };
 
-Uint32List fragmentUsingIntlSegmenter(
+SkUint32List fragmentUsingIntlSegmenter(
   String text,
   IntlSegmenterGranularity granularity,
 ) {
@@ -56,7 +56,9 @@
   }
   breaks.add(text.length);
 
-  return mallocUint32List(breaks.length).toTypedArray()..setAll(0, breaks);
+  final SkUint32List mallocedList = mallocUint32List(breaks.length);
+  mallocedList.toTypedArray().setAll(0, breaks);
+  return mallocedList;
 }
 
 // These are the soft/hard line break values expected by Skia's SkParagraph.
@@ -65,12 +67,13 @@
 
 final DomV8BreakIterator _v8LineBreaker = createV8BreakIterator();
 
-Uint32List fragmentUsingV8LineBreaker(String text) {
+SkUint32List fragmentUsingV8LineBreaker(String text) {
   final List<LineBreakFragment> fragments =
       breakLinesUsingV8BreakIterator(text, _v8LineBreaker);
 
   final int size = (fragments.length + 1) * 2;
-  final Uint32List typedArray = mallocUint32List(size).toTypedArray();
+  final SkUint32List mallocedList = mallocUint32List(size);
+  final Uint32List typedArray = mallocedList.toTypedArray();
 
   typedArray[0] = 0; // start index
   typedArray[1] = _kSoftLineBreak; // break type
@@ -84,5 +87,5 @@
         : _kSoftLineBreak;
   }
 
-  return typedArray;
+  return mallocedList;
 }
diff --git a/lib/web_ui/lib/src/engine/canvaskit/vertices.dart b/lib/web_ui/lib/src/engine/canvaskit/vertices.dart
index df2b38c..5c22556 100644
--- a/lib/web_ui/lib/src/engine/canvaskit/vertices.dart
+++ b/lib/web_ui/lib/src/engine/canvaskit/vertices.dart
@@ -62,11 +62,16 @@
           '"indices" values must be valid indices in the positions list.');
     }
 
+    Uint32List? unsignedColors;
+    if (colors != null) {
+      unsignedColors = colors.buffer.asUint32List(colors.offsetInBytes, colors.length);
+    }
+
     return CkVertices._(
       toSkVertexMode(mode),
       positions,
       textureCoordinates,
-      colors?.buffer.asUint32List(),
+      unsignedColors,
       indices,
     );
   }
diff --git a/lib/web_ui/test/canvaskit/text_fragmenter_test.dart b/lib/web_ui/test/canvaskit/text_fragmenter_test.dart
index 7d44c3b..e444321 100644
--- a/lib/web_ui/test/canvaskit/text_fragmenter_test.dart
+++ b/lib/web_ui/test/canvaskit/text_fragmenter_test.dart
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:typed_data';
-
 import 'package:test/bootstrap/browser.dart';
 import 'package:test/test.dart';
 import 'package:ui/src/engine.dart';
@@ -17,25 +15,33 @@
 void testMain() {
   setUpCanvasKitTest();
 
+  late SkUint32List breaks;
+
+  tearDown(() {
+    if (browserSupportsCanvaskitChromium) {
+      free(breaks);
+    }
+  });
+
   group('$fragmentUsingIntlSegmenter', () {
     test('fragments text into words', () {
-      final Uint32List breaks = fragmentUsingIntlSegmenter(
+      breaks = fragmentUsingIntlSegmenter(
         'Hello world 你好世界',
         IntlSegmenterGranularity.word,
       );
       expect(
-        breaks,
+        breaks.toTypedArray(),
         orderedEquals(<int>[0, 5, 6, 11, 12, 14, 16]),
       );
     });
 
     test('fragments multi-line text into words', () {
-      final Uint32List breaks = fragmentUsingIntlSegmenter(
+      breaks = fragmentUsingIntlSegmenter(
         'Lorem ipsum\ndolor 你好世界 sit\namet',
         IntlSegmenterGranularity.word,
       );
       expect(
-        breaks,
+        breaks.toTypedArray(),
         orderedEquals(<int>[
           0, 5, 6, 11, 12, // "Lorem ipsum\n"
           17, 18, 20, 22, 23, 26, 27, // "dolor 你好世界 sit\n"
@@ -47,12 +53,12 @@
     test('fragments text into grapheme clusters', () {
       // The smiley emoji has a length of 2.
       // The family emoji has a length of 11.
-      final Uint32List breaks = fragmentUsingIntlSegmenter(
+      breaks = fragmentUsingIntlSegmenter(
         'Lorem🙂ipsum👨‍👩‍👧‍👦',
         IntlSegmenterGranularity.grapheme,
       );
       expect(
-        breaks,
+        breaks.toTypedArray(),
         orderedEquals(<int>[
           0, 1, 2, 3, 4, 5, 7, // "Lorem🙂"
           8, 9, 10, 11, 12, 23, // "ipsum👨‍👩‍👧‍👦"
@@ -63,12 +69,12 @@
     test('fragments multi-line text into grapheme clusters', () {
       // The smiley emojis have a length of 2 each.
       // The family emoji has a length of 11.
-      final Uint32List breaks = fragmentUsingIntlSegmenter(
+      breaks = fragmentUsingIntlSegmenter(
         'Lorem🙂\nipsum👨‍👩‍👧‍👦dolor\n😄',
         IntlSegmenterGranularity.grapheme,
       );
       expect(
-        breaks,
+        breaks.toTypedArray(),
         orderedEquals(<int>[
           0, 1, 2, 3, 4, 5, 7, 8, // "Lorem🙂\n"
           9, 10, 11, 12, 13, 24, // "ipsum👨‍👩‍👧‍👦"
@@ -83,11 +89,11 @@
     const int kHard = 1;
 
     test('fragments text into soft and hard line breaks', () {
-      final Uint32List breaks = fragmentUsingV8LineBreaker(
+      breaks = fragmentUsingV8LineBreaker(
         'Lorem-ipsum 你好🙂\nDolor sit',
       );
       expect(
-        breaks,
+        breaks.toTypedArray(),
         orderedEquals(<int>[
           0, kSoft,
           6, kSoft, // "Lorem-"
diff --git a/shell/common/fixtures/shell_test.dart b/shell/common/fixtures/shell_test.dart
index 605e3d9..b88289a 100644
--- a/shell/common/fixtures/shell_test.dart
+++ b/shell/common/fixtures/shell_test.dart
@@ -470,3 +470,11 @@
   }
   notifyNativeBool(true);
 }
+
+@pragma('vm:entry-point')
+Future<void> testThatAssetLoadingHappensOnWorkerThread() async {
+  try {
+    await ImmutableBuffer.fromAsset('DoesNotExist');
+  } catch (err) { /* Do nothing */ }
+  notifyNative();
+}
diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc
index 449822c..36c8646 100644
--- a/shell/common/shell_unittests.cc
+++ b/shell/common/shell_unittests.cc
@@ -19,6 +19,7 @@
 #include "flutter/flow/layers/layer_raster_cache_item.h"
 #include "flutter/flow/layers/platform_view_layer.h"
 #include "flutter/flow/layers/transform_layer.h"
+#include "flutter/fml/backtrace.h"
 #include "flutter/fml/command_line.h"
 #include "flutter/fml/dart/dart_converter.h"
 #include "flutter/fml/make_copyable.h"
@@ -194,6 +195,42 @@
   AssetResolver::AssetResolverType type_;
 };
 
+class ThreadCheckingAssetResolver : public AssetResolver {
+ public:
+  explicit ThreadCheckingAssetResolver(
+      std::shared_ptr<fml::ConcurrentMessageLoop> concurrent_loop)
+      : concurrent_loop_(std::move(concurrent_loop)) {}
+
+  // |AssetResolver|
+  bool IsValid() const override { return true; }
+
+  // |AssetResolver|
+  bool IsValidAfterAssetManagerChange() const override { return true; }
+
+  // |AssetResolver|
+  AssetResolverType GetType() const {
+    return AssetResolverType::kApkAssetProvider;
+  }
+
+  // |AssetResolver|
+  std::unique_ptr<fml::Mapping> GetAsMapping(
+      const std::string& asset_name) const override {
+    if (asset_name == "FontManifest.json") {
+      // This file is loaded directly by the engine.
+      return nullptr;
+    }
+    mapping_requests.push_back(asset_name);
+    EXPECT_TRUE(concurrent_loop_->RunsTasksOnCurrentThread())
+        << fml::BacktraceHere();
+    return nullptr;
+  }
+
+  mutable std::vector<std::string> mapping_requests;
+
+ private:
+  std::shared_ptr<fml::ConcurrentMessageLoop> concurrent_loop_;
+};
+
 static bool ValidateShell(Shell* shell) {
   if (!shell) {
     return false;
@@ -3805,6 +3842,39 @@
   ASSERT_FALSE(DartVMRef::IsInstanceRunning());
 }
 
+TEST_F(ShellTest, ImmutableBufferLoadsAssetOnBackgroundThread) {
+  Settings settings = CreateSettingsForFixture();
+  auto task_runner = CreateNewThread();
+  TaskRunners task_runners("test", task_runner, task_runner, task_runner,
+                           task_runner);
+  std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
+
+  fml::CountDownLatch latch(1);
+  AddNativeCallback("NotifyNative",
+                    CREATE_NATIVE_ENTRY([&](auto args) { latch.CountDown(); }));
+
+  // Create the surface needed by rasterizer
+  PlatformViewNotifyCreated(shell.get());
+
+  auto configuration = RunConfiguration::InferFromSettings(settings);
+  configuration.SetEntrypoint("testThatAssetLoadingHappensOnWorkerThread");
+  auto asset_manager = configuration.GetAssetManager();
+  auto test_resolver = std::make_unique<ThreadCheckingAssetResolver>(
+      shell->GetDartVM()->GetConcurrentMessageLoop());
+  auto leaked_resolver = test_resolver.get();
+  asset_manager->PushBack(std::move(test_resolver));
+
+  RunEngine(shell.get(), std::move(configuration));
+  PumpOneFrame(shell.get());
+
+  latch.Wait();
+
+  EXPECT_EQ(leaked_resolver->mapping_requests[0], "DoesNotExist");
+
+  PlatformViewNotifyDestroyed(shell.get());
+  DestroyShell(std::move(shell), task_runners);
+}
+
 TEST_F(ShellTest, PictureToImageSync) {
 #if !SHELL_ENABLE_GL
   // This test uses the GL backend.
diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java
index d22118d..0dbb457 100644
--- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java
+++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java
@@ -235,9 +235,16 @@
     DartExecutor.DartEntrypoint dartEntrypoint =
         new DartExecutor.DartEntrypoint(
             appBundlePathOverride, host.getDartEntrypointFunctionName());
+    String initialRoute = host.getInitialRoute();
+    if (initialRoute == null) {
+      initialRoute = maybeGetInitialRouteFromIntent(host.getActivity().getIntent());
+      if (initialRoute == null) {
+        initialRoute = DEFAULT_INITIAL_ROUTE;
+      }
+    }
     return options
         .setDartEntrypoint(dartEntrypoint)
-        .setInitialRoute(host.getInitialRoute())
+        .setInitialRoute(initialRoute)
         .setDartEntrypointArgs(host.getDartEntrypointArgs());
   }
 
diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java
index e120d77..8c1f545 100644
--- a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java
+++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java
@@ -237,6 +237,47 @@
     // Expect IllegalStateException.
   }
 
+  // Bug: b/271100292
+  @Test
+  public void flutterEngineGroupGetsInitialRouteFromIntent() {
+    // ---- Test setup ----
+    FlutterLoader mockFlutterLoader = mock(FlutterLoader.class);
+    Activity mockActivity = mock(Activity.class);
+    Intent mockIntent = mock(Intent.class);
+    when(mockFlutterLoader.findAppBundlePath()).thenReturn("default_flutter_assets/path");
+    FlutterInjector.setInstance(
+        new FlutterInjector.Builder().setFlutterLoader(mockFlutterLoader).build());
+    FlutterEngineGroup flutterEngineGroup = mock(FlutterEngineGroup.class);
+    FlutterEngineGroupCache.getInstance().put("my_flutter_engine_group", flutterEngineGroup);
+
+    List<String> entryPointArgs = new ArrayList<>();
+    entryPointArgs.add("entrypoint-arg");
+
+    // Adjust fake host to request cached engine group.
+    when(mockHost.getInitialRoute()).thenReturn(null);
+    when(mockHost.getCachedEngineGroupId()).thenReturn("my_flutter_engine_group");
+    when(mockHost.provideFlutterEngine(any(Context.class))).thenReturn(null);
+    when(mockHost.shouldAttachEngineToActivity()).thenReturn(false);
+    when(mockHost.getDartEntrypointArgs()).thenReturn(entryPointArgs);
+    when(mockHost.shouldHandleDeeplinking()).thenReturn(true);
+    when(mockHost.getActivity()).thenReturn(mockActivity);
+    when(mockActivity.getIntent()).thenReturn(mockIntent);
+    when(mockIntent.getData()).thenReturn(Uri.parse("foo://example.com/initial_route"));
+
+    // Create the real object that we're testing.
+    FlutterActivityAndFragmentDelegate delegate = new FlutterActivityAndFragmentDelegate(mockHost);
+
+    // --- Execute the behavior under test ---
+    // The FlutterEngine is obtained in onAttach().
+    delegate.onAttach(ctx);
+
+    DartExecutor.DartEntrypoint entrypoint = new DartExecutor.DartEntrypoint("/fake/path", "main");
+    ArgumentCaptor<FlutterEngineGroup.Options> optionsCaptor =
+        ArgumentCaptor.forClass(FlutterEngineGroup.Options.class);
+    verify(flutterEngineGroup, times(1)).createAndRunEngine(optionsCaptor.capture());
+    assertEquals("/initial_route", optionsCaptor.getValue().getInitialRoute());
+  }
+
   @Test
   public void itUsesNewEngineInGroupWhenProvided() {
     // ---- Test setup ----
diff --git a/shell/platform/common/accessibility_bridge.cc b/shell/platform/common/accessibility_bridge.cc
index 8007460..765304e 100644
--- a/shell/platform/common/accessibility_bridge.cc
+++ b/shell/platform/common/accessibility_bridge.cc
@@ -37,13 +37,13 @@
 }
 
 void AccessibilityBridge::AddFlutterSemanticsNodeUpdate(
-    const FlutterSemanticsNode* node) {
-  pending_semantics_node_updates_[node->id] = FromFlutterSemanticsNode(node);
+    const FlutterSemanticsNode& node) {
+  pending_semantics_node_updates_[node.id] = FromFlutterSemanticsNode(node);
 }
 
 void AccessibilityBridge::AddFlutterSemanticsCustomActionUpdate(
-    const FlutterSemanticsCustomAction* action) {
-  pending_semantics_custom_action_updates_[action->id] =
+    const FlutterSemanticsCustomAction& action) {
+  pending_semantics_custom_action_updates_[action.id] =
       FromFlutterSemanticsCustomAction(action);
 }
 
@@ -578,66 +578,66 @@
 
 AccessibilityBridge::SemanticsNode
 AccessibilityBridge::FromFlutterSemanticsNode(
-    const FlutterSemanticsNode* flutter_node) {
+    const FlutterSemanticsNode& flutter_node) {
   SemanticsNode result;
-  result.id = flutter_node->id;
-  result.flags = flutter_node->flags;
-  result.actions = flutter_node->actions;
-  result.text_selection_base = flutter_node->text_selection_base;
-  result.text_selection_extent = flutter_node->text_selection_extent;
-  result.scroll_child_count = flutter_node->scroll_child_count;
-  result.scroll_index = flutter_node->scroll_index;
-  result.scroll_position = flutter_node->scroll_position;
-  result.scroll_extent_max = flutter_node->scroll_extent_max;
-  result.scroll_extent_min = flutter_node->scroll_extent_min;
-  result.elevation = flutter_node->elevation;
-  result.thickness = flutter_node->thickness;
-  if (flutter_node->label) {
-    result.label = std::string(flutter_node->label);
+  result.id = flutter_node.id;
+  result.flags = flutter_node.flags;
+  result.actions = flutter_node.actions;
+  result.text_selection_base = flutter_node.text_selection_base;
+  result.text_selection_extent = flutter_node.text_selection_extent;
+  result.scroll_child_count = flutter_node.scroll_child_count;
+  result.scroll_index = flutter_node.scroll_index;
+  result.scroll_position = flutter_node.scroll_position;
+  result.scroll_extent_max = flutter_node.scroll_extent_max;
+  result.scroll_extent_min = flutter_node.scroll_extent_min;
+  result.elevation = flutter_node.elevation;
+  result.thickness = flutter_node.thickness;
+  if (flutter_node.label) {
+    result.label = std::string(flutter_node.label);
   }
-  if (flutter_node->hint) {
-    result.hint = std::string(flutter_node->hint);
+  if (flutter_node.hint) {
+    result.hint = std::string(flutter_node.hint);
   }
-  if (flutter_node->value) {
-    result.value = std::string(flutter_node->value);
+  if (flutter_node.value) {
+    result.value = std::string(flutter_node.value);
   }
-  if (flutter_node->increased_value) {
-    result.increased_value = std::string(flutter_node->increased_value);
+  if (flutter_node.increased_value) {
+    result.increased_value = std::string(flutter_node.increased_value);
   }
-  if (flutter_node->decreased_value) {
-    result.decreased_value = std::string(flutter_node->decreased_value);
+  if (flutter_node.decreased_value) {
+    result.decreased_value = std::string(flutter_node.decreased_value);
   }
-  if (flutter_node->tooltip) {
-    result.tooltip = std::string(flutter_node->tooltip);
+  if (flutter_node.tooltip) {
+    result.tooltip = std::string(flutter_node.tooltip);
   }
-  result.text_direction = flutter_node->text_direction;
-  result.rect = flutter_node->rect;
-  result.transform = flutter_node->transform;
-  if (flutter_node->child_count > 0) {
+  result.text_direction = flutter_node.text_direction;
+  result.rect = flutter_node.rect;
+  result.transform = flutter_node.transform;
+  if (flutter_node.child_count > 0) {
     result.children_in_traversal_order = std::vector<int32_t>(
-        flutter_node->children_in_traversal_order,
-        flutter_node->children_in_traversal_order + flutter_node->child_count);
+        flutter_node.children_in_traversal_order,
+        flutter_node.children_in_traversal_order + flutter_node.child_count);
   }
-  if (flutter_node->custom_accessibility_actions_count > 0) {
+  if (flutter_node.custom_accessibility_actions_count > 0) {
     result.custom_accessibility_actions = std::vector<int32_t>(
-        flutter_node->custom_accessibility_actions,
-        flutter_node->custom_accessibility_actions +
-            flutter_node->custom_accessibility_actions_count);
+        flutter_node.custom_accessibility_actions,
+        flutter_node.custom_accessibility_actions +
+            flutter_node.custom_accessibility_actions_count);
   }
   return result;
 }
 
 AccessibilityBridge::SemanticsCustomAction
 AccessibilityBridge::FromFlutterSemanticsCustomAction(
-    const FlutterSemanticsCustomAction* flutter_custom_action) {
+    const FlutterSemanticsCustomAction& flutter_custom_action) {
   SemanticsCustomAction result;
-  result.id = flutter_custom_action->id;
-  result.override_action = flutter_custom_action->override_action;
-  if (flutter_custom_action->label) {
-    result.label = std::string(flutter_custom_action->label);
+  result.id = flutter_custom_action.id;
+  result.override_action = flutter_custom_action.override_action;
+  if (flutter_custom_action.label) {
+    result.label = std::string(flutter_custom_action.label);
   }
-  if (flutter_custom_action->hint) {
-    result.hint = std::string(flutter_custom_action->hint);
+  if (flutter_custom_action.hint) {
+    result.hint = std::string(flutter_custom_action.hint);
   }
   return result;
 }
diff --git a/shell/platform/common/accessibility_bridge.h b/shell/platform/common/accessibility_bridge.h
index 81a6a1a..b654dad 100644
--- a/shell/platform/common/accessibility_bridge.h
+++ b/shell/platform/common/accessibility_bridge.h
@@ -60,8 +60,8 @@
   ///             Calling this method alone will NOT update the semantics tree.
   ///             To flush the pending updates, call the CommitUpdates().
   ///
-  /// @param[in]  node           A pointer to the semantics node update.
-  void AddFlutterSemanticsNodeUpdate(const FlutterSemanticsNode* node);
+  /// @param[in]  node           A reference to the semantics node update.
+  void AddFlutterSemanticsNodeUpdate(const FlutterSemanticsNode& node);
 
   //------------------------------------------------------------------------------
   /// @brief      Adds a custom semantics action update to the pending semantics
@@ -69,10 +69,10 @@
   ///             semantics tree. To flush the pending updates, call the
   ///             CommitUpdates().
   ///
-  /// @param[in]  action           A pointer to the custom semantics action
+  /// @param[in]  action           A reference to the custom semantics action
   ///                              update.
   void AddFlutterSemanticsCustomActionUpdate(
-      const FlutterSemanticsCustomAction* action);
+      const FlutterSemanticsCustomAction& action);
 
   //------------------------------------------------------------------------------
   /// @brief      Flushes the pending updates and applies them to this
@@ -252,9 +252,9 @@
                                    const SemanticsNode& node);
   void SetTreeData(const SemanticsNode& node, ui::AXTreeUpdate& tree_update);
   SemanticsNode FromFlutterSemanticsNode(
-      const FlutterSemanticsNode* flutter_node);
+      const FlutterSemanticsNode& flutter_node);
   SemanticsCustomAction FromFlutterSemanticsCustomAction(
-      const FlutterSemanticsCustomAction* flutter_custom_action);
+      const FlutterSemanticsCustomAction& flutter_custom_action);
 
   // |AXTreeObserver|
   void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
diff --git a/shell/platform/common/accessibility_bridge_unittests.cc b/shell/platform/common/accessibility_bridge_unittests.cc
index 3b5f197..d243afc 100644
--- a/shell/platform/common/accessibility_bridge_unittests.cc
+++ b/shell/platform/common/accessibility_bridge_unittests.cc
@@ -46,9 +46,9 @@
   FlutterSemanticsNode child1 = CreateSemanticsNode(1, "child 1");
   FlutterSemanticsNode child2 = CreateSemanticsNode(2, "child 2");
 
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
-  bridge->AddFlutterSemanticsNodeUpdate(&child1);
-  bridge->AddFlutterSemanticsNodeUpdate(&child2);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
+  bridge->AddFlutterSemanticsNodeUpdate(child1);
+  bridge->AddFlutterSemanticsNodeUpdate(child2);
   bridge->CommitUpdates();
 
   auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
@@ -78,9 +78,9 @@
   FlutterSemanticsNode child1 = CreateSemanticsNode(456, "child 1");
   FlutterSemanticsNode child2 = CreateSemanticsNode(789, "child 2");
 
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
-  bridge->AddFlutterSemanticsNodeUpdate(&child1);
-  bridge->AddFlutterSemanticsNodeUpdate(&child2);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
+  bridge->AddFlutterSemanticsNodeUpdate(child1);
+  bridge->AddFlutterSemanticsNodeUpdate(child2);
   bridge->CommitUpdates();
 
   auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(123).lock();
@@ -121,11 +121,11 @@
       CreateSemanticsNode(78, "child 3", &child3_children);
   FlutterSemanticsNode child4 = CreateSemanticsNode(90, "child 4");
 
-  bridge->AddFlutterSemanticsNodeUpdate(&child3);
-  bridge->AddFlutterSemanticsNodeUpdate(&child2);
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
-  bridge->AddFlutterSemanticsNodeUpdate(&child1);
-  bridge->AddFlutterSemanticsNodeUpdate(&child4);
+  bridge->AddFlutterSemanticsNodeUpdate(child3);
+  bridge->AddFlutterSemanticsNodeUpdate(child2);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
+  bridge->AddFlutterSemanticsNodeUpdate(child1);
+  bridge->AddFlutterSemanticsNodeUpdate(child4);
   bridge->CommitUpdates();
 
   auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(12).lock();
@@ -165,8 +165,8 @@
   FlutterSemanticsNode root = CreateSemanticsNode(0, "root", &children);
   FlutterSemanticsNode child1 = CreateSemanticsNode(1, "child 1");
 
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
-  bridge->AddFlutterSemanticsNodeUpdate(&child1);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
+  bridge->AddFlutterSemanticsNodeUpdate(child1);
 
   bridge->CommitUpdates();
 
@@ -187,8 +187,8 @@
 
   FlutterSemanticsNode child2 = CreateSemanticsNode(2, "child 2");
 
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
-  bridge->AddFlutterSemanticsNodeUpdate(&child2);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
+  bridge->AddFlutterSemanticsNodeUpdate(child2);
   bridge->CommitUpdates();
 
   root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
@@ -213,8 +213,8 @@
   FlutterSemanticsNode root = CreateSemanticsNode(0, "root", &children);
   FlutterSemanticsNode child1 = CreateSemanticsNode(1, "child 1");
 
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
-  bridge->AddFlutterSemanticsNodeUpdate(&child1);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
+  bridge->AddFlutterSemanticsNodeUpdate(child1);
   bridge->CommitUpdates();
 
   auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0);
@@ -246,7 +246,7 @@
   root.flags = static_cast<FlutterSemanticsFlag>(
       FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField |
       FlutterSemanticsFlag::kFlutterSemanticsFlagIsFocused);
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
   bridge->CommitUpdates();
 
   const ui::AXTreeData& tree = bridge->GetAXTreeData();
@@ -256,7 +256,7 @@
   // Update the selection.
   root.text_selection_base = 0;
   root.text_selection_extent = 5;
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   bridge->CommitUpdates();
 
@@ -278,7 +278,7 @@
   root.flags = static_cast<FlutterSemanticsFlag>(
       FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField |
       FlutterSemanticsFlag::kFlutterSemanticsFlagIsReadOnly);
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
   bridge->CommitUpdates();
 
   auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
@@ -295,7 +295,7 @@
       FlutterSemanticsFlag::kFlutterSemanticsFlagHasToggledState |
       FlutterSemanticsFlag::kFlutterSemanticsFlagHasEnabledState |
       FlutterSemanticsFlag::kFlutterSemanticsFlagIsEnabled);
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
   bridge->CommitUpdates();
 
   auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
@@ -311,7 +311,7 @@
       FlutterSemanticsFlag::kFlutterSemanticsFlagHasEnabledState |
       FlutterSemanticsFlag::kFlutterSemanticsFlagIsEnabled |
       FlutterSemanticsFlag::kFlutterSemanticsFlagIsFocusable);
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
   bridge->CommitUpdates();
 
   auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
@@ -330,7 +330,7 @@
   root.flags = static_cast<FlutterSemanticsFlag>(
       FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState |
       FlutterSemanticsFlag::kFlutterSemanticsFlagIsChecked);
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
   bridge->CommitUpdates();
 
   auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
@@ -351,9 +351,9 @@
       CreateSemanticsNode(1, "child 1", &child1_children);
   FlutterSemanticsNode child2 = CreateSemanticsNode(2, "child 2");
 
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
-  bridge->AddFlutterSemanticsNodeUpdate(&child1);
-  bridge->AddFlutterSemanticsNodeUpdate(&child2);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
+  bridge->AddFlutterSemanticsNodeUpdate(child1);
+  bridge->AddFlutterSemanticsNodeUpdate(child2);
   bridge->CommitUpdates();
   bridge->accessibility_events.clear();
 
@@ -365,9 +365,9 @@
   root.child_count = 2;
   root.children_in_traversal_order = new_root_children;
 
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
-  bridge->AddFlutterSemanticsNodeUpdate(&child1);
-  bridge->AddFlutterSemanticsNodeUpdate(&child2);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
+  bridge->AddFlutterSemanticsNodeUpdate(child1);
+  bridge->AddFlutterSemanticsNodeUpdate(child2);
   bridge->CommitUpdates();
 
   auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
@@ -427,12 +427,12 @@
   FlutterSemanticsNode leaf2 = CreateSemanticsNode(leaf2_id, "leaf 2");
   FlutterSemanticsNode leaf3 = CreateSemanticsNode(leaf3_id, "leaf 3");
 
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
-  bridge->AddFlutterSemanticsNodeUpdate(&intermediary1);
-  bridge->AddFlutterSemanticsNodeUpdate(&intermediary2);
-  bridge->AddFlutterSemanticsNodeUpdate(&leaf1);
-  bridge->AddFlutterSemanticsNodeUpdate(&leaf2);
-  bridge->AddFlutterSemanticsNodeUpdate(&leaf3);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
+  bridge->AddFlutterSemanticsNodeUpdate(intermediary1);
+  bridge->AddFlutterSemanticsNodeUpdate(intermediary2);
+  bridge->AddFlutterSemanticsNodeUpdate(leaf1);
+  bridge->AddFlutterSemanticsNodeUpdate(leaf2);
+  bridge->AddFlutterSemanticsNodeUpdate(leaf3);
   bridge->CommitUpdates();
   bridge->accessibility_events.clear();
 
@@ -445,11 +445,11 @@
   intermediary2.child_count = 1;
   intermediary2.children_in_traversal_order = new_intermediary2_children;
 
-  bridge->AddFlutterSemanticsNodeUpdate(&intermediary1);
-  bridge->AddFlutterSemanticsNodeUpdate(&intermediary2);
-  bridge->AddFlutterSemanticsNodeUpdate(&leaf1);
-  bridge->AddFlutterSemanticsNodeUpdate(&leaf2);
-  bridge->AddFlutterSemanticsNodeUpdate(&leaf3);
+  bridge->AddFlutterSemanticsNodeUpdate(intermediary1);
+  bridge->AddFlutterSemanticsNodeUpdate(intermediary2);
+  bridge->AddFlutterSemanticsNodeUpdate(leaf1);
+  bridge->AddFlutterSemanticsNodeUpdate(leaf2);
+  bridge->AddFlutterSemanticsNodeUpdate(leaf3);
   bridge->CommitUpdates();
 
   auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(root_id).lock();
@@ -516,10 +516,10 @@
       CreateSemanticsNode(intermediary2_id, "intermediary 2");
   FlutterSemanticsNode leaf1 = CreateSemanticsNode(leaf1_id, "leaf 1");
 
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
-  bridge->AddFlutterSemanticsNodeUpdate(&intermediary1);
-  bridge->AddFlutterSemanticsNodeUpdate(&intermediary2);
-  bridge->AddFlutterSemanticsNodeUpdate(&leaf1);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
+  bridge->AddFlutterSemanticsNodeUpdate(intermediary1);
+  bridge->AddFlutterSemanticsNodeUpdate(intermediary2);
+  bridge->AddFlutterSemanticsNodeUpdate(leaf1);
   bridge->CommitUpdates();
   bridge->accessibility_events.clear();
 
@@ -532,10 +532,10 @@
   intermediary2.child_count = 1;
   intermediary2.children_in_traversal_order = new_intermediary2_children;
 
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
-  bridge->AddFlutterSemanticsNodeUpdate(&intermediary1);
-  bridge->AddFlutterSemanticsNodeUpdate(&intermediary2);
-  bridge->AddFlutterSemanticsNodeUpdate(&leaf1);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
+  bridge->AddFlutterSemanticsNodeUpdate(intermediary1);
+  bridge->AddFlutterSemanticsNodeUpdate(intermediary2);
+  bridge->AddFlutterSemanticsNodeUpdate(leaf1);
   bridge->CommitUpdates();
 
   auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(root_id).lock();
@@ -595,7 +595,7 @@
 
   FlutterSemanticsNode root = CreateSemanticsNode(root_id, "root", {});
 
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
   bridge->CommitUpdates();
 
   auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(root_id).lock();
diff --git a/shell/platform/common/flutter_platform_node_delegate_unittests.cc b/shell/platform/common/flutter_platform_node_delegate_unittests.cc
index d9fe80c..efe9e8d 100644
--- a/shell/platform/common/flutter_platform_node_delegate_unittests.cc
+++ b/shell/platform/common/flutter_platform_node_delegate_unittests.cc
@@ -28,8 +28,8 @@
   node1.label = "prefecture";
   node1.value = "Kyoto";
 
-  bridge->AddFlutterSemanticsNodeUpdate(&node0);
-  bridge->AddFlutterSemanticsNodeUpdate(&node1);
+  bridge->AddFlutterSemanticsNodeUpdate(node0);
+  bridge->AddFlutterSemanticsNodeUpdate(node1);
   bridge->CommitUpdates();
 
   auto node0_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
@@ -54,7 +54,7 @@
   root.tooltip = "";
   root.child_count = 0;
   root.custom_accessibility_actions_count = 0;
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   bridge->CommitUpdates();
 
@@ -99,7 +99,7 @@
   root.tooltip = "";
   root.child_count = 0;
   root.custom_accessibility_actions_count = 0;
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   bridge->CommitUpdates();
 
@@ -124,7 +124,7 @@
   root.custom_accessibility_actions_count = 0;
   root.rect = {0, 0, 100, 100};  // LTRB
   root.transform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   FlutterSemanticsNode child1;
   child1.id = 1;
@@ -138,7 +138,7 @@
   child1.custom_accessibility_actions_count = 0;
   child1.rect = {0, 0, 50, 50};  // LTRB
   child1.transform = {0.5, 0, 0, 0, 0.5, 0, 0, 0, 1};
-  bridge->AddFlutterSemanticsNodeUpdate(&child1);
+  bridge->AddFlutterSemanticsNodeUpdate(child1);
 
   bridge->CommitUpdates();
   auto child1_node = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
@@ -170,7 +170,7 @@
   root.custom_accessibility_actions_count = 0;
   root.rect = {0, 0, 100, 100};  // LTRB
   root.transform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   FlutterSemanticsNode child1;
   child1.id = 1;
@@ -184,7 +184,7 @@
   child1.custom_accessibility_actions_count = 0;
   child1.rect = {90, 90, 100, 100};  // LTRB
   child1.transform = {2, 0, 0, 0, 2, 0, 0, 0, 1};
-  bridge->AddFlutterSemanticsNodeUpdate(&child1);
+  bridge->AddFlutterSemanticsNodeUpdate(child1);
 
   bridge->CommitUpdates();
   auto child1_node = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
@@ -216,7 +216,7 @@
   root.custom_accessibility_actions_count = 0;
   root.rect = {0, 0, 100, 100};  // LTRB
   root.transform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   FlutterSemanticsNode child1;
   child1.id = 1;
@@ -230,7 +230,7 @@
   child1.custom_accessibility_actions_count = 0;
   child1.rect = {0, 0, 50, 50};  // LTRB
   child1.transform = {0.5, 0, 0, 0, 0.5, 0, 0, 0, 1};
-  bridge->AddFlutterSemanticsNodeUpdate(&child1);
+  bridge->AddFlutterSemanticsNodeUpdate(child1);
 
   bridge->CommitUpdates();
   auto child1_node = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
@@ -260,7 +260,7 @@
   root.child_count = 0;
   root.children_in_traversal_order = nullptr;
   root.custom_accessibility_actions_count = 0;
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   bridge->CommitUpdates();
   auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
@@ -283,7 +283,7 @@
   int32_t children[] = {1};
   root.children_in_traversal_order = children;
   root.custom_accessibility_actions_count = 0;
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   FlutterSemanticsNode child1;
   child1.id = 1;
@@ -295,7 +295,7 @@
   child1.tooltip = "";
   child1.child_count = 0;
   child1.custom_accessibility_actions_count = 0;
-  bridge->AddFlutterSemanticsNodeUpdate(&child1);
+  bridge->AddFlutterSemanticsNodeUpdate(child1);
 
   bridge->CommitUpdates();
   auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
diff --git a/shell/platform/darwin/ios/platform_message_handler_ios.h b/shell/platform/darwin/ios/platform_message_handler_ios.h
index 09ef281..3b176a1 100644
--- a/shell/platform/darwin/ios/platform_message_handler_ios.h
+++ b/shell/platform/darwin/ios/platform_message_handler_ios.h
@@ -13,7 +13,9 @@
 #include "flutter/shell/common/platform_message_handler.h"
 #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterBinaryMessenger.h"
 
-@protocol FlutterTaskQueue;
+@protocol FlutterTaskQueue
+- (void)dispatch:(dispatch_block_t)block;
+@end
 
 namespace flutter {
 
@@ -21,11 +23,11 @@
  public:
   static NSObject<FlutterTaskQueue>* MakeBackgroundTaskQueue();
 
-  PlatformMessageHandlerIos(const TaskRunners& task_runners);
+  PlatformMessageHandlerIos(fml::RefPtr<fml::TaskRunner> platform_task_runner);
 
   void HandlePlatformMessage(std::unique_ptr<PlatformMessage> message) override;
 
-  bool DoesHandlePlatformMessageOnPlatformThread() const override { return false; }
+  bool DoesHandlePlatformMessageOnPlatformThread() const override;
 
   void InvokePlatformMessageResponseCallback(int response_id,
                                              std::unique_ptr<fml::Mapping> mapping) override;
@@ -43,7 +45,7 @@
 
  private:
   std::unordered_map<std::string, HandlerInfo> message_handlers_;
-  TaskRunners task_runners_;
+  const fml::RefPtr<fml::TaskRunner> platform_task_runner_;
   std::mutex message_handlers_mutex_;
   FML_DISALLOW_COPY_AND_ASSIGN(PlatformMessageHandlerIos);
 };
diff --git a/shell/platform/darwin/ios/platform_message_handler_ios.mm b/shell/platform/darwin/ios/platform_message_handler_ios.mm
index cf510bc..df65828 100644
--- a/shell/platform/darwin/ios/platform_message_handler_ios.mm
+++ b/shell/platform/darwin/ios/platform_message_handler_ios.mm
@@ -11,10 +11,6 @@
 
 static uint64_t platform_message_counter = 1;
 
-@protocol FlutterTaskQueue
-- (void)dispatch:(dispatch_block_t)block;
-@end
-
 @interface FLTSerialTaskQueue : NSObject <FlutterTaskQueue>
 @property(nonatomic, strong) dispatch_queue_t queue;
 @end
@@ -44,8 +40,9 @@
   return [[[FLTSerialTaskQueue alloc] init] autorelease];
 }
 
-PlatformMessageHandlerIos::PlatformMessageHandlerIos(const TaskRunners& task_runners)
-    : task_runners_(task_runners) {}
+PlatformMessageHandlerIos::PlatformMessageHandlerIos(
+    fml::RefPtr<fml::TaskRunner> platform_task_runner)
+    : platform_task_runner_(std::move(platform_task_runner)) {}
 
 void PlatformMessageHandlerIos::HandlePlatformMessage(std::unique_ptr<PlatformMessage> message) {
   // This can be called from any isolate's thread.
@@ -97,6 +94,10 @@
   }
 }
 
+bool PlatformMessageHandlerIos::DoesHandlePlatformMessageOnPlatformThread() const {
+  return false;
+}
+
 void PlatformMessageHandlerIos::InvokePlatformMessageResponseCallback(
     int response_id,
     std::unique_ptr<fml::Mapping> mapping) {
@@ -114,7 +115,7 @@
 void PlatformMessageHandlerIos::SetMessageHandler(const std::string& channel,
                                                   FlutterBinaryMessageHandler handler,
                                                   NSObject<FlutterTaskQueue>* task_queue) {
-  FML_CHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
+  FML_CHECK(platform_task_runner_->RunsTasksOnCurrentThread());
   /// TODO(gaaclarke): This should be migrated to a lockfree datastructure.
   std::lock_guard lock(message_handlers_mutex_);
   message_handlers_.erase(channel);
diff --git a/shell/platform/darwin/ios/platform_message_handler_ios_test.mm b/shell/platform/darwin/ios/platform_message_handler_ios_test.mm
index 7249722..f1af3be 100644
--- a/shell/platform/darwin/ios/platform_message_handler_ios_test.mm
+++ b/shell/platform/darwin/ios/platform_message_handler_ios_test.mm
@@ -46,7 +46,7 @@
 - (void)testCreate {
   flutter::TaskRunners task_runners("test", GetCurrentTaskRunner(), CreateNewThread("raster"),
                                     CreateNewThread("ui"), CreateNewThread("io"));
-  auto handler = std::make_unique<PlatformMessageHandlerIos>(task_runners);
+  auto handler = std::make_unique<PlatformMessageHandlerIos>(task_runners.GetPlatformTaskRunner());
   XCTAssertTrue(handler);
 }
 
@@ -57,7 +57,7 @@
       "test", GetCurrentTaskRunner(), thread_host.raster_thread->GetTaskRunner(),
       thread_host.ui_thread->GetTaskRunner(), thread_host.io_thread->GetTaskRunner());
 
-  auto handler = std::make_unique<PlatformMessageHandlerIos>(task_runners);
+  auto handler = std::make_unique<PlatformMessageHandlerIos>(task_runners.GetPlatformTaskRunner());
   std::string channel = "foo";
   XCTestExpectation* didCallReply = [self expectationWithDescription:@"didCallReply"];
   handler->SetMessageHandler(
@@ -83,7 +83,7 @@
       "test", GetCurrentTaskRunner(), thread_host.raster_thread->GetTaskRunner(),
       thread_host.ui_thread->GetTaskRunner(), thread_host.io_thread->GetTaskRunner());
 
-  auto handler = std::make_unique<PlatformMessageHandlerIos>(task_runners);
+  auto handler = std::make_unique<PlatformMessageHandlerIos>(task_runners.GetPlatformTaskRunner());
   std::string channel = "foo";
   XCTestExpectation* didCallMessage = [self expectationWithDescription:@"didCallMessage"];
   handler->SetMessageHandler(
@@ -111,7 +111,7 @@
       "test", GetCurrentTaskRunner(), thread_host.raster_thread->GetTaskRunner(),
       thread_host.ui_thread->GetTaskRunner(), thread_host.io_thread->GetTaskRunner());
 
-  auto handler = std::make_unique<PlatformMessageHandlerIos>(task_runners);
+  auto handler = std::make_unique<PlatformMessageHandlerIos>(task_runners.GetPlatformTaskRunner());
   std::string channel = "foo";
   XCTestExpectation* didCallReply = [self expectationWithDescription:@"didCallReply"];
   NSObject<FlutterTaskQueue>* taskQueue = PlatformMessageHandlerIos::MakeBackgroundTaskQueue();
diff --git a/shell/platform/darwin/ios/platform_view_ios.mm b/shell/platform/darwin/ios/platform_view_ios.mm
index 7e054fc..219dab4 100644
--- a/shell/platform/darwin/ios/platform_view_ios.mm
+++ b/shell/platform/darwin/ios/platform_view_ios.mm
@@ -48,7 +48,8 @@
       ios_context_(context),
       platform_views_controller_(platform_views_controller),
       accessibility_bridge_([this](bool enabled) { PlatformView::SetSemanticsEnabled(enabled); }),
-      platform_message_handler_(new PlatformMessageHandlerIos(task_runners)) {}
+      platform_message_handler_(
+          new PlatformMessageHandlerIos(task_runners.GetPlatformTaskRunner())) {}
 
 PlatformViewIOS::PlatformViewIOS(
     PlatformView::Delegate& delegate,
diff --git a/shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMacTest.mm b/shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMacTest.mm
index 0100e0b..9ba8d25 100644
--- a/shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMacTest.mm
+++ b/shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMacTest.mm
@@ -87,7 +87,7 @@
   root.tooltip = "";
   root.child_count = 0;
   root.custom_accessibility_actions_count = 0;
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   bridge->CommitUpdates();
   auto platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
@@ -135,7 +135,7 @@
   root.tooltip = "";
   root.child_count = 0;
   root.custom_accessibility_actions_count = 0;
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   bridge->CommitUpdates();
   auto platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
@@ -182,7 +182,7 @@
   root.tooltip = "";
   root.child_count = 0;
   root.custom_accessibility_actions_count = 0;
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   bridge->CommitUpdates();
   auto platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
diff --git a/shell/platform/darwin/macos/framework/Source/FlutterPlatformNodeDelegateMacTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterPlatformNodeDelegateMacTest.mm
index 276d620..8dbc02f 100644
--- a/shell/platform/darwin/macos/framework/Source/FlutterPlatformNodeDelegateMacTest.mm
+++ b/shell/platform/darwin/macos/framework/Source/FlutterPlatformNodeDelegateMacTest.mm
@@ -50,7 +50,7 @@
   root.tooltip = "";
   root.child_count = 0;
   root.custom_accessibility_actions_count = 0;
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   bridge->CommitUpdates();
 
@@ -88,7 +88,7 @@
   root.tooltip = "";
   root.child_count = 0;
   root.custom_accessibility_actions_count = 0;
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   bridge->CommitUpdates();
 
@@ -130,7 +130,7 @@
   root.tooltip = "";
   root.child_count = 0;
   root.custom_accessibility_actions_count = 0;
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   bridge->CommitUpdates();
 
@@ -172,7 +172,7 @@
   int32_t children[] = {1};
   root.children_in_traversal_order = children;
   root.custom_accessibility_actions_count = 0;
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   FlutterSemanticsNode child1;
   child1.id = 1;
@@ -184,7 +184,7 @@
   child1.tooltip = "";
   child1.child_count = 0;
   child1.custom_accessibility_actions_count = 0;
-  bridge->AddFlutterSemanticsNodeUpdate(&child1);
+  bridge->AddFlutterSemanticsNodeUpdate(child1);
 
   bridge->CommitUpdates();
 
@@ -251,7 +251,7 @@
   root.custom_accessibility_actions_count = 0;
   root.rect = {0, 0, 100, 100};  // LTRB
   root.transform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   double rectSize = 50;
   double transformFactor = 0.5;
@@ -272,7 +272,7 @@
   child1.custom_accessibility_actions_count = 0;
   child1.rect = {0, 0, rectSize, rectSize};  // LTRB
   child1.transform = {transformFactor, 0, 0, 0, transformFactor, 0, 0, 0, 1};
-  bridge->AddFlutterSemanticsNodeUpdate(&child1);
+  bridge->AddFlutterSemanticsNodeUpdate(child1);
 
   bridge->CommitUpdates();
 
diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm
index a921738..ace1e14 100644
--- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm
+++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm
@@ -479,13 +479,11 @@
     return;
   }
   for (size_t i = 0; i < update->nodes_count; i++) {
-    const FlutterSemanticsNode* node = &update->nodes[i];
-    _bridge->AddFlutterSemanticsNodeUpdate(node);
+    _bridge->AddFlutterSemanticsNodeUpdate(update->nodes[i]);
   }
 
   for (size_t i = 0; i < update->custom_actions_count; i++) {
-    const FlutterSemanticsCustomAction* action = &update->custom_actions[i];
-    _bridge->AddFlutterSemanticsCustomActionUpdate(action);
+    _bridge->AddFlutterSemanticsCustomActionUpdate(update->custom_actions[i]);
   }
 
   _bridge->CommitUpdates();
diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h
index 60a90f4..989b9cc 100644
--- a/shell/platform/embedder/embedder.h
+++ b/shell/platform/embedder/embedder.h
@@ -25,12 +25,16 @@
 // - Function signatures (names, argument counts, argument order, and argument
 //   type) cannot change.
 // - The core behavior of existing functions cannot change.
+// - Instead of nesting structures by value within another structure, prefer
+//   nesting by pointer. This ensures that adding members to the nested struct
+//   does not break the ABI of the parent struct.
 // - Instead of array of structures, prefer array of pointers to structures.
 //   This ensures that array indexing does not break if members are added
 //   to the structure.
 //
 // These changes are allowed:
-// - Adding new struct members at the end of a structure.
+// - Adding new struct members at the end of a structure as long as the struct
+//   is not nested within another struct by value.
 // - Adding new enum members with a new value.
 // - Renaming a struct member as long as its type, size, and intent remain the
 //   same.
diff --git a/shell/platform/embedder/tests/embedder_frozen.h b/shell/platform/embedder/tests/embedder_frozen.h
index 46e00f0..60c995f 100644
--- a/shell/platform/embedder/tests/embedder_frozen.h
+++ b/shell/platform/embedder/tests/embedder_frozen.h
@@ -22,6 +22,47 @@
 namespace flutter {
 namespace testing {
 
+// New members must not be added to `FlutterTransformation`
+// as it would break the ABI of `FlutterSemanticsNode`.
+// See: https://github.com/flutter/flutter/issues/121176
+typedef struct {
+  double scaleX;
+  double skewX;
+  double transX;
+  double skewY;
+  double scaleY;
+  double transY;
+  double pers0;
+  double pers1;
+  double pers2;
+} FrozenFlutterTransformation;
+
+// New members must not be added to `FlutterRect` as it would
+// break the ABI of `FlutterSemanticsNode` and `FlutterDamage`.
+// See: https://github.com/flutter/flutter/issues/121176
+// See: https://github.com/flutter/flutter/issues/121347
+typedef struct {
+  double left;
+  double top;
+  double right;
+  double bottom;
+} FrozenFlutterRect;
+
+// New members must not be added to `FlutterPoint` as it would
+// break the ABI of `FlutterLayer`.
+typedef struct {
+  double x;
+  double y;
+} FrozenFlutterPoint;
+
+// New members must not be added to `FlutterDamage` as it would
+// break the ABI of `FlutterPresentInfo`.
+typedef struct {
+  size_t struct_size;
+  size_t num_rects;
+  FrozenFlutterRect* damage;
+} FrozenFlutterDamage;
+
 // New members must not be added to `FlutterSemanticsNode`
 // as it would break the ABI of `FlutterSemanticsUpdate`.
 // See: https://github.com/flutter/flutter/issues/121176
@@ -45,8 +86,8 @@
   const char* increased_value;
   const char* decreased_value;
   FlutterTextDirection text_direction;
-  FlutterRect rect;
-  FlutterTransformation transform;
+  FrozenFlutterRect rect;
+  FrozenFlutterTransformation transform;
   size_t child_count;
   const int32_t* children_in_traversal_order;
   const int32_t* children_in_hit_test_order;
diff --git a/shell/platform/embedder/tests/embedder_frozen_unittests.cc b/shell/platform/embedder/tests/embedder_frozen_unittests.cc
index eb173fe..4235547 100644
--- a/shell/platform/embedder/tests/embedder_frozen_unittests.cc
+++ b/shell/platform/embedder/tests/embedder_frozen_unittests.cc
@@ -14,6 +14,47 @@
 #define ASSERT_EQ_OFFSET(type1, type2, member) \
   ASSERT_EQ(offsetof(type1, member), offsetof(type2, member))
 
+// New members must not be added to `FlutterTransformation`
+// as it would break the ABI of `FlutterSemanticsNode`.
+// See: https://github.com/flutter/flutter/issues/121176
+TEST(EmbedderFrozen, FlutterTransformationIsFrozen) {
+  ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, scaleX);
+  ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, skewX);
+  ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, transX);
+  ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, skewY);
+  ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, scaleY);
+  ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, transY);
+  ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, pers0);
+  ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, pers1);
+  ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, pers2);
+}
+
+// New members must not be added to `FlutterRect` as it would
+// break the ABI of `FlutterSemanticsNode` and `FlutterDamage`.
+// See: https://github.com/flutter/flutter/issues/121176
+// See: https://github.com/flutter/flutter/issues/121347
+TEST(EmbedderFrozen, FlutterRectIsFrozen) {
+  ASSERT_EQ_OFFSET(FlutterRect, FrozenFlutterRect, left);
+  ASSERT_EQ_OFFSET(FlutterRect, FrozenFlutterRect, top);
+  ASSERT_EQ_OFFSET(FlutterRect, FrozenFlutterRect, right);
+  ASSERT_EQ_OFFSET(FlutterRect, FrozenFlutterRect, bottom);
+}
+
+// New members must not be added to `FlutterPoint` as it would
+// break the ABI of `FlutterLayer`.
+TEST(EmbedderFrozen, FlutterPointIsFrozen) {
+  ASSERT_EQ_OFFSET(FlutterPoint, FrozenFlutterPoint, x);
+  ASSERT_EQ_OFFSET(FlutterPoint, FrozenFlutterPoint, y);
+}
+
+// New members must not be added to `FlutterDamage` as it would
+// break the ABI of `FlutterPresentInfo`.
+TEST(EmbedderFrozen, FlutterDamageIsFrozen) {
+  ASSERT_EQ_OFFSET(FlutterDamage, FrozenFlutterDamage, struct_size);
+  ASSERT_EQ_OFFSET(FlutterDamage, FrozenFlutterDamage, num_rects);
+  ASSERT_EQ_OFFSET(FlutterDamage, FrozenFlutterDamage, damage);
+}
+
 // New members must not be added to `FlutterSemanticsNode`
 // as it would break the ABI of `FlutterSemanticsUpdate`.
 // See: https://github.com/flutter/flutter/issues/121176
diff --git a/shell/platform/fuchsia/flutter/BUILD.gn b/shell/platform/fuchsia/flutter/BUILD.gn
index 13e5526..cc1407f 100644
--- a/shell/platform/fuchsia/flutter/BUILD.gn
+++ b/shell/platform/fuchsia/flutter/BUILD.gn
@@ -57,8 +57,6 @@
     sources = [
       "accessibility_bridge.cc",
       "accessibility_bridge.h",
-      "component_v1.cc",
-      "component_v1.h",
       "component_v2.cc",
       "component_v2.h",
       "engine.cc",
@@ -322,7 +320,6 @@
 
     binary = "flutter_jit${product_suffix}_runner"
 
-    cmx_file = rebase_path("meta/flutter_jit${product_suffix}_runner.cmx")
     cml_file = rebase_path("meta/flutter_jit${product_suffix}_runner.cml")
 
     resources = [
@@ -402,7 +399,6 @@
       ]
     }
 
-    cmx_file = rebase_path("meta/flutter_aot${product_suffix}_runner.cmx")
     cml_file = rebase_path("meta/flutter_aot${product_suffix}_runner.cml")
 
     binary = "flutter_aot${product_suffix}_runner"
@@ -500,7 +496,6 @@
 
     sources = [
       "accessibility_bridge_unittest.cc",
-      "component_v1_unittest.cc",
       "component_v2_unittest.cc",
       "flutter_runner_fakes.h",
       "focus_delegate_unittests.cc",
diff --git a/shell/platform/fuchsia/flutter/component_v1.cc b/shell/platform/fuchsia/flutter/component_v1.cc
deleted file mode 100644
index b869edb..0000000
--- a/shell/platform/fuchsia/flutter/component_v1.cc
+++ /dev/null
@@ -1,609 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "component_v1.h"
-
-#include <dlfcn.h>
-#include <fuchsia/mem/cpp/fidl.h>
-#include <lib/async-loop/cpp/loop.h>
-#include <lib/async/cpp/task.h>
-#include <lib/async/default.h>
-#include <lib/fdio/directory.h>
-#include <lib/fdio/io.h>
-#include <lib/fdio/namespace.h>
-#include <lib/ui/scenic/cpp/view_ref_pair.h>
-#include <lib/ui/scenic/cpp/view_token_pair.h>
-#include <lib/vfs/cpp/composed_service_dir.h>
-#include <lib/vfs/cpp/remote_dir.h>
-#include <lib/vfs/cpp/service.h>
-#include <sys/stat.h>
-#include <zircon/dlfcn.h>
-#include <zircon/status.h>
-#include <zircon/types.h>
-
-#include <memory>
-#include <regex>
-#include <sstream>
-
-#include "file_in_namespace_buffer.h"
-#include "flutter/fml/mapping.h"
-#include "flutter/fml/platform/fuchsia/task_observers.h"
-#include "flutter/fml/synchronization/waitable_event.h"
-#include "flutter/fml/unique_fd.h"
-#include "flutter/runtime/dart_vm_lifecycle.h"
-#include "flutter/shell/common/switches.h"
-#include "runtime/dart/utils/files.h"
-#include "runtime/dart/utils/handle_exception.h"
-#include "runtime/dart/utils/mapped_resource.h"
-#include "runtime/dart/utils/tempfs.h"
-#include "runtime/dart/utils/vmo.h"
-
-namespace flutter_runner {
-namespace {
-
-constexpr char kDataKey[] = "data";
-constexpr char kAssetsKey[] = "assets";
-constexpr char kOldGenHeapSizeKey[] = "old_gen_heap_size";
-
-constexpr char kTmpPath[] = "/tmp";
-constexpr char kServiceRootPath[] = "/svc";
-constexpr char kRunnerConfigPath[] = "/config/data/flutter_runner_config";
-
-std::string DebugLabelForUrl(const std::string& url) {
-  auto found = url.rfind("/");
-  if (found == std::string::npos) {
-    return url;
-  } else {
-    return {url, found + 1};
-  }
-}
-
-}  // namespace
-
-ProgramMetadata ComponentV1::ParseProgramMetadata(
-    const fidl::VectorPtr<fuchsia::sys::ProgramMetadata>& program_metadata) {
-  ProgramMetadata result;
-  if (!program_metadata.has_value()) {
-    return result;
-  }
-
-  for (const auto& pg : *program_metadata) {
-    if (pg.key.compare(kDataKey) == 0) {
-      result.data_path = "pkg/" + pg.value;
-    } else if (pg.key.compare(kAssetsKey) == 0) {
-      result.assets_path = "pkg/" + pg.value;
-    } else if (pg.key.compare(kOldGenHeapSizeKey) == 0) {
-      int64_t specified_old_gen_heap_size =
-          strtol(pg.value.c_str(), nullptr /* endptr */, 10 /* base */);
-      if (specified_old_gen_heap_size != 0) {
-        result.old_gen_heap_size = specified_old_gen_heap_size;
-      } else {
-        FML_LOG(ERROR) << "Invalid old_gen_heap_size: " << pg.value;
-      }
-    }
-  }
-
-  // assets_path defaults to the same as data_path if omitted.
-  if (result.assets_path.empty()) {
-    result.assets_path = result.data_path;
-  }
-
-  return result;
-}
-
-ActiveComponentV1 ComponentV1::Create(
-    TerminationCallback termination_callback,
-    fuchsia::sys::Package package,
-    fuchsia::sys::StartupInfo startup_info,
-    std::shared_ptr<sys::ServiceDirectory> runner_incoming_services,
-    fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller) {
-  auto thread = std::make_unique<fml::Thread>();
-  std::unique_ptr<ComponentV1> component;
-
-  fml::AutoResetWaitableEvent latch;
-  thread->GetTaskRunner()->PostTask([&]() mutable {
-    component.reset(new ComponentV1(std::move(termination_callback),
-                                    std::move(package), std::move(startup_info),
-                                    runner_incoming_services,
-                                    std::move(controller)));
-    latch.Signal();
-  });
-
-  latch.Wait();
-  return {.platform_thread = std::move(thread),
-          .component = std::move(component)};
-}
-
-ComponentV1::ComponentV1(
-    TerminationCallback termination_callback,
-    fuchsia::sys::Package package,
-    fuchsia::sys::StartupInfo startup_info,
-    std::shared_ptr<sys::ServiceDirectory> runner_incoming_services,
-    fidl::InterfaceRequest<fuchsia::sys::ComponentController>
-        component_controller_request)
-    : termination_callback_(std::move(termination_callback)),
-      debug_label_(DebugLabelForUrl(startup_info.launch_info.url)),
-      component_controller_(this),
-      outgoing_dir_(new vfs::PseudoDir()),
-      runner_incoming_services_(runner_incoming_services),
-      weak_factory_(this) {
-  component_controller_.set_error_handler(
-      [this](zx_status_t status) { Kill(); });
-
-  FML_DCHECK(fdio_ns_.is_valid());
-  // LaunchInfo::url non-optional.
-  auto& launch_info = startup_info.launch_info;
-
-  // LaunchInfo::arguments optional.
-  if (auto& arguments = launch_info.arguments) {
-    dart_entrypoint_args_ = arguments.value();
-  }
-
-  const ProgramMetadata metadata =
-      ParseProgramMetadata(startup_info.program_metadata);
-
-  if (metadata.data_path.empty()) {
-    FML_LOG(ERROR) << "Could not find a /pkg/data directory for "
-                   << package.resolved_url;
-    return;
-  }
-
-  // Setup /tmp to be mapped to the process-local memfs.
-  dart_utils::RunnerTemp::SetupComponent(fdio_ns_.get());
-
-  // LaunchInfo::flat_namespace optional.
-  for (size_t i = 0; i < startup_info.flat_namespace.paths.size(); ++i) {
-    const auto& path = startup_info.flat_namespace.paths.at(i);
-    if (path == kTmpPath) {
-      continue;
-    }
-
-    fidl::InterfaceHandle<fuchsia::io::Directory> dir;
-    if (path == kServiceRootPath) {
-      svc_ = std::make_unique<sys::ServiceDirectory>(
-          std::move(startup_info.flat_namespace.directories.at(i)));
-      dir = svc_->CloneChannel();
-    } else {
-      dir = std::move(startup_info.flat_namespace.directories.at(i));
-    }
-
-    zx_handle_t dir_handle = dir.TakeChannel().release();
-    if (fdio_ns_bind(fdio_ns_.get(), path.data(), dir_handle) != ZX_OK) {
-      FML_LOG(ERROR) << "Could not bind path to namespace: " << path;
-      zx_handle_close(dir_handle);
-    }
-  }
-
-  {
-    fml::UniqueFD ns_fd(fdio_ns_opendir(fdio_ns_.get()));
-    FML_DCHECK(ns_fd.is_valid());
-
-    constexpr mode_t mode = O_RDONLY | O_DIRECTORY;
-
-    component_assets_directory_.reset(
-        openat(ns_fd.get(), metadata.assets_path.c_str(), mode));
-    FML_DCHECK(component_assets_directory_.is_valid());
-
-    component_data_directory_.reset(
-        openat(ns_fd.get(), metadata.data_path.c_str(), mode));
-    FML_DCHECK(component_data_directory_.is_valid());
-  }
-
-  // TODO: LaunchInfo::out.
-
-  // TODO: LaunchInfo::err.
-
-  // LaunchInfo::service_request optional.
-  if (launch_info.directory_request) {
-    outgoing_dir_->Serve(fuchsia::io::OpenFlags::RIGHT_READABLE |
-                             fuchsia::io::OpenFlags::RIGHT_WRITABLE |
-                             fuchsia::io::OpenFlags::DIRECTORY,
-                         launch_info.directory_request.TakeChannel());
-  }
-
-  directory_request_ = directory_ptr_.NewRequest();
-
-  fuchsia::io::DirectoryHandle flutter_public_dir;
-  // TODO(anmittal): when fixing enumeration using new c++ vfs, make sure that
-  // flutter_public_dir is only accessed once we receive OnOpen Event.
-  // That will prevent FL-175 for public directory
-  auto request = flutter_public_dir.NewRequest().TakeChannel();
-  fdio_service_connect_at(directory_ptr_.channel().get(), "svc",
-                          request.release());
-
-  auto composed_service_dir = std::make_unique<vfs::ComposedServiceDir>();
-  composed_service_dir->set_fallback(std::move(flutter_public_dir));
-
-  // Clone and check if client is servicing the directory.
-  directory_ptr_->Clone(fuchsia::io::OpenFlags::DESCRIBE |
-                            fuchsia::io::OpenFlags::CLONE_SAME_RIGHTS,
-                        cloned_directory_ptr_.NewRequest());
-
-  cloned_directory_ptr_.events().OnOpen = [this](zx_status_t status,
-                                                 auto unused) {
-    cloned_directory_ptr_.Unbind();
-    if (status != ZX_OK) {
-      FML_LOG(ERROR) << "could not bind out directory for flutter component("
-                     << debug_label_ << "): " << zx_status_get_string(status);
-      return;
-    }
-    const char* other_dirs[] = {"debug", "ctrl", "diagnostics"};
-    // add other directories as RemoteDirs.
-    for (auto& dir_str : other_dirs) {
-      fuchsia::io::DirectoryHandle dir;
-      auto request = dir.NewRequest().TakeChannel();
-      auto status = fdio_open_at(
-          directory_ptr_.channel().get(), dir_str,
-          static_cast<uint32_t>(fuchsia::io::OpenFlags::DIRECTORY |
-                                fuchsia::io::OpenFlags::RIGHT_READABLE),
-          request.release());
-      if (status == ZX_OK) {
-        outgoing_dir_->AddEntry(
-            dir_str, std::make_unique<vfs::RemoteDir>(dir.TakeChannel()));
-      } else {
-        FML_LOG(ERROR) << "could not add out directory entry(" << dir_str
-                       << ") for flutter component(" << debug_label_
-                       << "): " << zx_status_get_string(status);
-      }
-    }
-  };
-
-  cloned_directory_ptr_.set_error_handler(
-      [this](zx_status_t status) { cloned_directory_ptr_.Unbind(); });
-
-  // TODO: LaunchInfo::additional_services optional.
-
-  // All launch arguments have been read. Perform service binding and
-  // final settings configuration. The next call will be to create a view
-  // for this component.
-  composed_service_dir->AddService(
-      fuchsia::ui::app::ViewProvider::Name_,
-      std::make_unique<vfs::Service>(
-          [this](zx::channel channel, async_dispatcher_t* dispatcher) {
-            shells_bindings_.AddBinding(
-                this, fidl::InterfaceRequest<fuchsia::ui::app::ViewProvider>(
-                          std::move(channel)));
-          }));
-
-  outgoing_dir_->AddEntry("svc", std::move(composed_service_dir));
-
-  // Setup the component controller binding.
-  if (component_controller_request) {
-    component_controller_.Bind(std::move(component_controller_request));
-  }
-
-  // Load and use runner-specific configuration, if it exists.
-  std::string json_string;
-  if (dart_utils::ReadFileToString(kRunnerConfigPath, &json_string)) {
-    product_config_ = FlutterRunnerProductConfiguration(json_string);
-    FML_LOG(INFO) << "Successfully loaded runner configuration: "
-                  << json_string;
-  } else {
-    FML_LOG(WARNING) << "Failed to load runner configuration from "
-                     << kRunnerConfigPath << "; using default config values.";
-  }
-
-  // Load VM and component bytecode.
-  // For AOT, compare with flutter_aot_app in flutter_app.gni.
-  // For JIT, compare flutter_jit_runner in BUILD.gn.
-  if (flutter::DartVM::IsRunningPrecompiledCode()) {
-    std::shared_ptr<dart_utils::ElfSnapshot> snapshot =
-        std::make_shared<dart_utils::ElfSnapshot>();
-    if (snapshot->Load(component_data_directory_.get(),
-                       "app_aot_snapshot.so")) {
-      const uint8_t* isolate_data = snapshot->IsolateData();
-      const uint8_t* isolate_instructions = snapshot->IsolateInstrs();
-      const uint8_t* vm_data = snapshot->VmData();
-      const uint8_t* vm_instructions = snapshot->VmInstrs();
-      if (isolate_data == nullptr || isolate_instructions == nullptr ||
-          vm_data == nullptr || vm_instructions == nullptr) {
-        FML_LOG(FATAL) << "ELF snapshot missing AOT symbols.";
-        return;
-      }
-      auto hold_snapshot = [snapshot](const uint8_t* _, size_t __) {};
-      settings_.vm_snapshot_data = [hold_snapshot, vm_data]() {
-        return std::make_unique<fml::NonOwnedMapping>(vm_data, 0, hold_snapshot,
-                                                      true /* dontneed_safe */);
-      };
-      settings_.vm_snapshot_instr = [hold_snapshot, vm_instructions]() {
-        return std::make_unique<fml::NonOwnedMapping>(
-            vm_instructions, 0, hold_snapshot, true /* dontneed_safe */);
-      };
-      settings_.isolate_snapshot_data = [hold_snapshot, isolate_data]() {
-        return std::make_unique<fml::NonOwnedMapping>(
-            isolate_data, 0, hold_snapshot, true /* dontneed_safe */);
-      };
-      settings_.isolate_snapshot_instr = [hold_snapshot,
-                                          isolate_instructions]() {
-        return std::make_unique<fml::NonOwnedMapping>(
-            isolate_instructions, 0, hold_snapshot, true /* dontneed_safe */);
-      };
-      isolate_snapshot_ = fml::MakeRefCounted<flutter::DartSnapshot>(
-          std::make_shared<fml::NonOwnedMapping>(isolate_data, 0, hold_snapshot,
-                                                 true /* dontneed_safe */),
-          std::make_shared<fml::NonOwnedMapping>(isolate_instructions, 0,
-                                                 hold_snapshot,
-                                                 true /* dontneed_safe */));
-    } else {
-      const int namespace_fd = component_data_directory_.get();
-      settings_.vm_snapshot_data = [namespace_fd]() {
-        return LoadFile(namespace_fd, "vm_snapshot_data.bin",
-                        false /* executable */);
-      };
-      settings_.vm_snapshot_instr = [namespace_fd]() {
-        return LoadFile(namespace_fd, "vm_snapshot_instructions.bin",
-                        true /* executable */);
-      };
-      settings_.isolate_snapshot_data = [namespace_fd]() {
-        return LoadFile(namespace_fd, "isolate_snapshot_data.bin",
-                        false /* executable */);
-      };
-      settings_.isolate_snapshot_instr = [namespace_fd]() {
-        return LoadFile(namespace_fd, "isolate_snapshot_instructions.bin",
-                        true /* executable */);
-      };
-    }
-  } else {
-    settings_.vm_snapshot_data = []() {
-      return MakeFileMapping("/pkg/data/vm_snapshot_data.bin",
-                             false /* executable */);
-    };
-    settings_.vm_snapshot_instr = []() {
-      return MakeFileMapping("/pkg/data/vm_snapshot_instructions.bin",
-                             true /* executable */);
-    };
-
-    settings_.isolate_snapshot_data = []() {
-      return MakeFileMapping("/pkg/data/isolate_core_snapshot_data.bin",
-                             false /* executable */);
-    };
-    settings_.isolate_snapshot_instr = [] {
-      return MakeFileMapping("/pkg/data/isolate_core_snapshot_instructions.bin",
-                             true /* executable */);
-    };
-  }
-
-#if defined(DART_PRODUCT)
-  settings_.enable_vm_service = false;
-#else
-  settings_.enable_vm_service = true;
-
-  // TODO(cbracken): pass this in as a param to allow 0.0.0.0, ::1, etc.
-  settings_.vm_service_host = "127.0.0.1";
-#endif
-
-  // Controls whether category "skia" trace events are enabled.
-  settings_.trace_skia = true;
-
-  settings_.verbose_logging = true;
-
-  settings_.advisory_script_uri = debug_label_;
-
-  settings_.advisory_script_entrypoint = debug_label_;
-
-  settings_.icu_data_path = "";
-
-  settings_.assets_dir = component_assets_directory_.get();
-
-  // Compare flutter_jit_app in flutter_app.gni.
-  settings_.application_kernel_list_asset = "app.dilplist";
-
-  settings_.log_tag = debug_label_ + std::string{"(flutter)"};
-
-  if (metadata.old_gen_heap_size.has_value()) {
-    settings_.old_gen_heap_size = *metadata.old_gen_heap_size;
-  }
-
-  // No asserts in debug or release product.
-  // No asserts in release with flutter_profile=true (non-product)
-  // Yes asserts in non-product debug.
-#if !defined(DART_PRODUCT) && (!defined(FLUTTER_PROFILE) || !defined(NDEBUG))
-  // Debug mode
-  settings_.disable_dart_asserts = false;
-#else
-  // Release mode
-  settings_.disable_dart_asserts = true;
-#endif
-
-  // Do not leak the VM; allow it to shut down normally when the last shell
-  // terminates.
-  settings_.leak_vm = false;
-
-  settings_.task_observer_add =
-      std::bind(&fml::CurrentMessageLoopAddAfterTaskObserver,
-                std::placeholders::_1, std::placeholders::_2);
-
-  settings_.task_observer_remove = std::bind(
-      &fml::CurrentMessageLoopRemoveAfterTaskObserver, std::placeholders::_1);
-
-  settings_.log_message_callback = [](const std::string& tag,
-                                      const std::string& message) {
-    if (!tag.empty()) {
-      std::cout << tag << ": ";
-    }
-    std::cout << message << std::endl;
-  };
-
-  settings_.dart_flags = {};
-
-  // Run in unsound null safety mode as some packages used in Integration
-  // testing have not been migrated yet.
-  settings_.dart_flags.push_back("--no-sound-null-safety");
-
-  // Don't collect CPU samples from Dart VM C++ code.
-  settings_.dart_flags.push_back("--no_profile_vm");
-
-  // Scale back CPU profiler sampling period on ARM64 to avoid overloading
-  // the tracing engine.
-#if defined(__aarch64__)
-  settings_.dart_flags.push_back("--profile_period=10000");
-#endif  // defined(__aarch64__)
-
-  auto platform_task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner();
-  const std::string component_url = package.resolved_url;
-  settings_.unhandled_exception_callback = [weak = weak_factory_.GetWeakPtr(),
-                                            platform_task_runner,
-                                            runner_incoming_services,
-                                            component_url](
-                                               const std::string& error,
-                                               const std::string& stack_trace) {
-    if (weak) {
-      // TODO(cbracken): unsafe. The above check and the PostTask below are
-      // happening on the UI thread. If the Component dtor and thread
-      // termination happen (on the platform thread) between the previous
-      // line and the next line, a crash will occur since we'll be posting
-      // to a dead thread. See Runner::OnComponentV1Terminate() in
-      // runner.cc.
-      platform_task_runner->PostTask([weak, runner_incoming_services,
-                                      component_url, error, stack_trace]() {
-        if (weak) {
-          dart_utils::HandleException(runner_incoming_services, component_url,
-                                      error, stack_trace);
-        } else {
-          FML_LOG(WARNING)
-              << "Exception was thrown which was not caught in Flutter app: "
-              << error;
-        }
-      });
-    } else {
-      FML_LOG(WARNING)
-          << "Exception was thrown which was not caught in Flutter app: "
-          << error;
-    }
-    // Ideally we would return whether HandleException returned ZX_OK, but
-    // short of knowing if the exception was correctly handled, we return
-    // false to have the error and stack trace printed in the logs.
-    return false;
-  };
-}
-
-ComponentV1::~ComponentV1() = default;
-
-const std::string& ComponentV1::GetDebugLabel() const {
-  return debug_label_;
-}
-
-void ComponentV1::Kill() {
-  component_controller_.events().OnTerminated(
-      last_return_code_.second, fuchsia::sys::TerminationReason::EXITED);
-
-  termination_callback_(this);
-  // WARNING: Don't do anything past this point as this instance may have been
-  // collected.
-}
-
-void ComponentV1::Detach() {
-  component_controller_.set_error_handler(nullptr);
-}
-
-void ComponentV1::OnEngineTerminate(const Engine* shell_holder) {
-  auto found = std::find_if(shell_holders_.begin(), shell_holders_.end(),
-                            [shell_holder](const auto& holder) {
-                              return holder.get() == shell_holder;
-                            });
-
-  if (found == shell_holders_.end()) {
-    // This indicates a deeper issue with memory management and should never
-    // happen.
-    FML_LOG(ERROR) << "Tried to terminate an unregistered shell holder.";
-    FML_DCHECK(false);
-
-    return;
-  }
-
-  // We may launch multiple shell in this component. However, we will
-  // terminate when the last shell goes away. The error code return to the
-  // component controller will be the last isolate that had an error.
-  auto return_code = shell_holder->GetEngineReturnCode();
-  if (return_code.has_value()) {
-    last_return_code_ = {true, return_code.value()};
-  } else {
-    FML_LOG(ERROR) << "Failed to get return code from terminated shell holder.";
-  }
-
-  shell_holders_.erase(found);
-
-  if (shell_holders_.empty()) {
-    FML_VLOG(-1) << "Killing component because all shell holders have been "
-                    "terminated.";
-    Kill();
-    // WARNING: Don't do anything past this point because the delegate may have
-    // collected this instance via the termination callback.
-  }
-}
-
-void ComponentV1::CreateView(
-    zx::eventpair token,
-    fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> /*incoming_services*/,
-    fidl::InterfaceHandle<
-        fuchsia::sys::ServiceProvider> /*outgoing_services*/) {
-  auto view_ref_pair = scenic::ViewRefPair::New();
-  CreateViewWithViewRef(std::move(token), std::move(view_ref_pair.control_ref),
-                        std::move(view_ref_pair.view_ref));
-}
-
-void ComponentV1::CreateViewWithViewRef(
-    zx::eventpair view_token,
-    fuchsia::ui::views::ViewRefControl control_ref,
-    fuchsia::ui::views::ViewRef view_ref) {
-  if (!svc_) {
-    FML_LOG(ERROR)
-        << "Component incoming services was invalid when attempting to "
-           "create a shell for a view provider request.";
-    return;
-  }
-
-  shell_holders_.emplace(std::make_unique<Engine>(
-      *this,                      // delegate
-      debug_label_,               // thread label
-      svc_,                       // Component incoming services
-      runner_incoming_services_,  // Runner incoming services
-      settings_,                  // settings
-      scenic::ToViewToken(std::move(view_token)),  // view token
-      scenic::ViewRefPair{
-          .control_ref = std::move(control_ref),
-          .view_ref = std::move(view_ref),
-      },
-      std::move(fdio_ns_),            // FDIO namespace
-      std::move(directory_request_),  // outgoing request
-      product_config_,                // product configuration
-      dart_entrypoint_args_,          // dart entrypoint args
-      true                            // v1 component
-      ));
-}
-
-void ComponentV1::CreateView2(fuchsia::ui::app::CreateView2Args view_args) {
-  if (!svc_) {
-    FML_LOG(ERROR)
-        << "Component incoming services was invalid when attempting to "
-           "create a shell for a view provider request.";
-    return;
-  }
-
-  shell_holders_.emplace(std::make_unique<Engine>(
-      *this,                      // delegate
-      debug_label_,               // thread label
-      svc_,                       // Component incoming services
-      runner_incoming_services_,  // Runner incoming services
-      settings_,                  // settings
-      std::move(
-          *view_args.mutable_view_creation_token()),  // view creation token
-      scenic::ViewRefPair::New(),                     // view ref pair
-      std::move(fdio_ns_),                            // FDIO namespace
-      std::move(directory_request_),                  // outgoing request
-      product_config_,                                // product configuration
-      dart_entrypoint_args_,                          // dart entrypoint args
-      true                                            // v1 component
-      ));
-}
-
-#if !defined(DART_PRODUCT)
-void ComponentV1::WriteProfileToTrace() const {
-  for (const auto& engine : shell_holders_) {
-    engine->WriteProfileToTrace();
-  }
-}
-#endif  // !defined(DART_PRODUCT)
-
-}  // namespace flutter_runner
diff --git a/shell/platform/fuchsia/flutter/component_v1.h b/shell/platform/fuchsia/flutter/component_v1.h
deleted file mode 100644
index efdc2a3..0000000
--- a/shell/platform/fuchsia/flutter/component_v1.h
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_COMPONENT_V1_H_
-#define FLUTTER_SHELL_PLATFORM_FUCHSIA_COMPONENT_V1_H_
-
-#include <array>
-#include <memory>
-#include <set>
-
-#include <fuchsia/io/cpp/fidl.h>
-#include <fuchsia/sys/cpp/fidl.h>
-#include <fuchsia/ui/app/cpp/fidl.h>
-#include <lib/async-loop/cpp/loop.h>
-#include <lib/async/default.h>
-#include <lib/fidl/cpp/binding_set.h>
-#include <lib/fidl/cpp/interface_request.h>
-#include <lib/fit/function.h>
-#include <lib/sys/cpp/service_directory.h>
-#include <lib/vfs/cpp/pseudo_dir.h>
-#include <lib/zx/eventpair.h>
-
-#include "flutter/common/settings.h"
-#include "flutter/fml/macros.h"
-
-#include "engine.h"
-#include "flutter_runner_product_configuration.h"
-#include "program_metadata.h"
-#include "unique_fdio_ns.h"
-
-namespace flutter_runner {
-
-class ComponentV1;
-
-struct ActiveComponentV1 {
-  std::unique_ptr<fml::Thread> platform_thread;
-  std::unique_ptr<ComponentV1> component;
-
-  ActiveComponentV1& operator=(ActiveComponentV1&& other) noexcept {
-    if (this != &other) {
-      this->platform_thread.reset(other.platform_thread.release());
-      this->component.reset(other.component.release());
-    }
-    return *this;
-  }
-
-  ~ActiveComponentV1() = default;
-};
-
-// Represents an instance of a CF v1 Flutter component that contains one or more
-// Flutter engine instances.
-class ComponentV1 final : public Engine::Delegate,
-                          public fuchsia::sys::ComponentController,
-                          public fuchsia::ui::app::ViewProvider {
- public:
-  using TerminationCallback = fit::function<void(const ComponentV1*)>;
-
-  // Creates a dedicated thread to run the component and creates the
-  // component on it. The component can be accessed only on this thread.
-  // This is a synchronous operation.
-  static ActiveComponentV1 Create(
-      TerminationCallback termination_callback,
-      fuchsia::sys::Package package,
-      fuchsia::sys::StartupInfo startup_info,
-      std::shared_ptr<sys::ServiceDirectory> runner_incoming_services,
-      fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller);
-
-  // Must be called on the same thread returned from the create call. The thread
-  // may be collected after.
-  ~ComponentV1();
-
-  static ProgramMetadata ParseProgramMetadata(
-      const fidl::VectorPtr<fuchsia::sys::ProgramMetadata>& program_metadata);
-
-  const std::string& GetDebugLabel() const;
-
-#if !defined(DART_PRODUCT)
-  void WriteProfileToTrace() const;
-#endif  // !defined(DART_PRODUCT)
-
- private:
-  ComponentV1(
-      TerminationCallback termination_callback,
-      fuchsia::sys::Package package,
-      fuchsia::sys::StartupInfo startup_info,
-      std::shared_ptr<sys::ServiceDirectory> runner_incoming_services,
-      fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller);
-
-  // |fuchsia::sys::ComponentController|
-  void Kill() override;
-
-  // |fuchsia::sys::ComponentController|
-  void Detach() override;
-
-  // |fuchsia::ui::app::ViewProvider|
-  void CreateView(
-      zx::eventpair token,
-      fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> incoming_services,
-      fuchsia::sys::ServiceProviderHandle outgoing_services) override;
-
-  // |fuchsia::ui::app::ViewProvider|
-  void CreateViewWithViewRef(zx::eventpair view_token,
-                             fuchsia::ui::views::ViewRefControl control_ref,
-                             fuchsia::ui::views::ViewRef view_ref) override;
-
-  // |fuchsia::ui::app::ViewProvider|
-  void CreateView2(fuchsia::ui::app::CreateView2Args view_args) override;
-
-  // |flutter::Engine::Delegate|
-  void OnEngineTerminate(const Engine* holder) override;
-
-  flutter::Settings settings_;
-  FlutterRunnerProductConfiguration product_config_;
-  TerminationCallback termination_callback_;
-  const std::string debug_label_;
-  UniqueFDIONS fdio_ns_ = UniqueFDIONSCreate();
-  fml::UniqueFD component_data_directory_;
-  fml::UniqueFD component_assets_directory_;
-
-  fidl::Binding<fuchsia::sys::ComponentController> component_controller_;
-  fuchsia::io::DirectoryPtr directory_ptr_;
-  fuchsia::io::NodePtr cloned_directory_ptr_;
-  fidl::InterfaceRequest<fuchsia::io::Directory> directory_request_;
-  std::unique_ptr<vfs::PseudoDir> outgoing_dir_;
-  std::shared_ptr<sys::ServiceDirectory> svc_;
-  std::shared_ptr<sys::ServiceDirectory> runner_incoming_services_;
-  fidl::BindingSet<fuchsia::ui::app::ViewProvider> shells_bindings_;
-
-  fml::RefPtr<flutter::DartSnapshot> isolate_snapshot_;
-  std::set<std::unique_ptr<Engine>> shell_holders_;
-  std::pair<bool, uint32_t> last_return_code_;
-  std::vector<std::string> dart_entrypoint_args_;
-  fml::WeakPtrFactory<ComponentV1> weak_factory_;  // Must be the last member.
-  FML_DISALLOW_COPY_AND_ASSIGN(ComponentV1);
-};
-
-}  // namespace flutter_runner
-
-#endif  // FLUTTER_SHELL_PLATFORM_FUCHSIA_COMPONENT_V1_H_
diff --git a/shell/platform/fuchsia/flutter/component_v1_unittest.cc b/shell/platform/fuchsia/flutter/component_v1_unittest.cc
deleted file mode 100644
index c9abacc..0000000
--- a/shell/platform/fuchsia/flutter/component_v1_unittest.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "component_v1.h"
-
-#include <gtest/gtest.h>
-#include <optional>
-
-namespace flutter_runner {
-namespace {
-
-TEST(ComponentV1, ParseProgramMetadata) {
-  // The ProgramMetadata field may be null. We should parse this as if no
-  // fields were specified.
-  ProgramMetadata result = ComponentV1::ParseProgramMetadata(nullptr);
-
-  EXPECT_EQ(result.data_path, "");
-  EXPECT_EQ(result.assets_path, "");
-  EXPECT_EQ(result.old_gen_heap_size, std::nullopt);
-
-  // The ProgramMetadata field may be empty. Treat this the same as null.
-  fidl::VectorPtr<fuchsia::sys::ProgramMetadata> program_metadata(size_t{0});
-  result = ComponentV1::ParseProgramMetadata(program_metadata);
-
-  EXPECT_EQ(result.data_path, "");
-  EXPECT_EQ(result.assets_path, "");
-  EXPECT_EQ(result.old_gen_heap_size, std::nullopt);
-
-  // The assets_path defaults to the "data" value if unspecified.
-  program_metadata = {{"data", "foobar"}};
-  result = ComponentV1::ParseProgramMetadata(program_metadata);
-
-  EXPECT_EQ(result.data_path, "pkg/foobar");
-  EXPECT_EQ(result.assets_path, "pkg/foobar");
-  EXPECT_EQ(result.old_gen_heap_size, std::nullopt);
-
-  // Invalid keys are ignored.
-  program_metadata = {{"not_data", "foo"}, {"data", "bar"}, {"assets", "baz"}};
-  result = ComponentV1::ParseProgramMetadata(program_metadata);
-
-  EXPECT_EQ(result.data_path, "pkg/bar");
-  EXPECT_EQ(result.assets_path, "pkg/baz");
-  EXPECT_EQ(result.old_gen_heap_size, std::nullopt);
-
-  // The old_gen_heap_size can be specified.
-  program_metadata = {{"old_gen_heap_size", "100"}};
-  result = ComponentV1::ParseProgramMetadata(program_metadata);
-
-  EXPECT_EQ(result.data_path, "");
-  EXPECT_EQ(result.assets_path, "");
-  EXPECT_EQ(result.old_gen_heap_size, 100);
-
-  // Invalid old_gen_heap_sizes should be ignored.
-  program_metadata = {{"old_gen_heap_size", "asdf100"}};
-  result = ComponentV1::ParseProgramMetadata(program_metadata);
-
-  EXPECT_EQ(result.data_path, "");
-  EXPECT_EQ(result.assets_path, "");
-  EXPECT_EQ(result.old_gen_heap_size, std::nullopt);
-}
-
-}  // anonymous namespace
-}  // namespace flutter_runner
diff --git a/shell/platform/fuchsia/flutter/meta/aot_product_runtime b/shell/platform/fuchsia/flutter/meta/aot_product_runtime
deleted file mode 100644
index 244bbc8..0000000
--- a/shell/platform/fuchsia/flutter/meta/aot_product_runtime
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-    "runner": "fuchsia-pkg://fuchsia.com/flutter_aot_product_runner#meta/flutter_aot_product_runner.cmx"
-}
diff --git a/shell/platform/fuchsia/flutter/meta/aot_runtime b/shell/platform/fuchsia/flutter/meta/aot_runtime
deleted file mode 100644
index 8e1b724..0000000
--- a/shell/platform/fuchsia/flutter/meta/aot_runtime
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-    "runner": "fuchsia-pkg://fuchsia.com/flutter_aot_runner#meta/flutter_aot_runner.cmx"
-}
\ No newline at end of file
diff --git a/shell/platform/fuchsia/flutter/meta/flutter_aot_product_runner.cmx b/shell/platform/fuchsia/flutter/meta/flutter_aot_product_runner.cmx
deleted file mode 100644
index ec1e197..0000000
--- a/shell/platform/fuchsia/flutter/meta/flutter_aot_product_runner.cmx
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-    "program": {
-        "data": "data"
-    },
-    "sandbox": {
-        "features": [
-            "config-data",
-            "isolated-cache-storage",
-            "root-ssl-certificates",
-            "vulkan"
-        ],
-        "services": [
-            "fuchsia.accessibility.semantics.SemanticsManager",
-            "fuchsia.device.NameProvider",
-            "fuchsia.feedback.CrashReporter",
-            "fuchsia.fonts.Provider",
-            "fuchsia.intl.PropertyProvider",
-            "fuchsia.logger.LogSink",
-            "fuchsia.memorypressure.Provider",
-            "fuchsia.net.name.Lookup",
-            "fuchsia.posix.socket.Provider",
-            "fuchsia.sysmem.Allocator",
-            "fuchsia.tracing.provider.Registry",
-            "fuchsia.ui.composition.Allocator",
-            "fuchsia.ui.composition.Flatland",
-            "fuchsia.ui.input.ImeService",
-            "fuchsia.ui.input3.Keyboard",
-            "fuchsia.ui.scenic.Scenic",
-            "fuchsia.ui.pointerinjector.Registry",
-            "fuchsia.vulkan.loader.Loader"
-        ]
-    }
-}
diff --git a/shell/platform/fuchsia/flutter/meta/flutter_aot_runner.cmx b/shell/platform/fuchsia/flutter/meta/flutter_aot_runner.cmx
deleted file mode 100644
index ec1e197..0000000
--- a/shell/platform/fuchsia/flutter/meta/flutter_aot_runner.cmx
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-    "program": {
-        "data": "data"
-    },
-    "sandbox": {
-        "features": [
-            "config-data",
-            "isolated-cache-storage",
-            "root-ssl-certificates",
-            "vulkan"
-        ],
-        "services": [
-            "fuchsia.accessibility.semantics.SemanticsManager",
-            "fuchsia.device.NameProvider",
-            "fuchsia.feedback.CrashReporter",
-            "fuchsia.fonts.Provider",
-            "fuchsia.intl.PropertyProvider",
-            "fuchsia.logger.LogSink",
-            "fuchsia.memorypressure.Provider",
-            "fuchsia.net.name.Lookup",
-            "fuchsia.posix.socket.Provider",
-            "fuchsia.sysmem.Allocator",
-            "fuchsia.tracing.provider.Registry",
-            "fuchsia.ui.composition.Allocator",
-            "fuchsia.ui.composition.Flatland",
-            "fuchsia.ui.input.ImeService",
-            "fuchsia.ui.input3.Keyboard",
-            "fuchsia.ui.scenic.Scenic",
-            "fuchsia.ui.pointerinjector.Registry",
-            "fuchsia.vulkan.loader.Loader"
-        ]
-    }
-}
diff --git a/shell/platform/fuchsia/flutter/meta/flutter_jit_product_runner.cmx b/shell/platform/fuchsia/flutter/meta/flutter_jit_product_runner.cmx
deleted file mode 100644
index b0a626c..0000000
--- a/shell/platform/fuchsia/flutter/meta/flutter_jit_product_runner.cmx
+++ /dev/null
@@ -1,34 +0,0 @@
-{
-    "program": {
-        "data": "data"
-    },
-    "sandbox": {
-        "features": [
-            "config-data",
-            "deprecated-ambient-replace-as-executable",
-            "isolated-cache-storage",
-            "root-ssl-certificates",
-            "vulkan"
-        ],
-        "services": [
-            "fuchsia.accessibility.semantics.SemanticsManager",
-            "fuchsia.device.NameProvider",
-            "fuchsia.feedback.CrashReporter",
-            "fuchsia.fonts.Provider",
-            "fuchsia.intl.PropertyProvider",
-            "fuchsia.logger.LogSink",
-            "fuchsia.memorypressure.Provider",
-            "fuchsia.net.name.Lookup",
-            "fuchsia.posix.socket.Provider",
-            "fuchsia.sysmem.Allocator",
-            "fuchsia.tracing.provider.Registry",
-            "fuchsia.ui.composition.Allocator",
-            "fuchsia.ui.composition.Flatland",
-            "fuchsia.ui.input.ImeService",
-            "fuchsia.ui.input3.Keyboard",
-            "fuchsia.ui.scenic.Scenic",
-            "fuchsia.ui.pointerinjector.Registry",
-            "fuchsia.vulkan.loader.Loader"
-        ]
-    }
-}
diff --git a/shell/platform/fuchsia/flutter/meta/flutter_jit_runner.cmx b/shell/platform/fuchsia/flutter/meta/flutter_jit_runner.cmx
deleted file mode 100644
index b0a626c..0000000
--- a/shell/platform/fuchsia/flutter/meta/flutter_jit_runner.cmx
+++ /dev/null
@@ -1,34 +0,0 @@
-{
-    "program": {
-        "data": "data"
-    },
-    "sandbox": {
-        "features": [
-            "config-data",
-            "deprecated-ambient-replace-as-executable",
-            "isolated-cache-storage",
-            "root-ssl-certificates",
-            "vulkan"
-        ],
-        "services": [
-            "fuchsia.accessibility.semantics.SemanticsManager",
-            "fuchsia.device.NameProvider",
-            "fuchsia.feedback.CrashReporter",
-            "fuchsia.fonts.Provider",
-            "fuchsia.intl.PropertyProvider",
-            "fuchsia.logger.LogSink",
-            "fuchsia.memorypressure.Provider",
-            "fuchsia.net.name.Lookup",
-            "fuchsia.posix.socket.Provider",
-            "fuchsia.sysmem.Allocator",
-            "fuchsia.tracing.provider.Registry",
-            "fuchsia.ui.composition.Allocator",
-            "fuchsia.ui.composition.Flatland",
-            "fuchsia.ui.input.ImeService",
-            "fuchsia.ui.input3.Keyboard",
-            "fuchsia.ui.scenic.Scenic",
-            "fuchsia.ui.pointerinjector.Registry",
-            "fuchsia.vulkan.loader.Loader"
-        ]
-    }
-}
diff --git a/shell/platform/fuchsia/flutter/meta/jit_product_runtime b/shell/platform/fuchsia/flutter/meta/jit_product_runtime
deleted file mode 100644
index 03707e7..0000000
--- a/shell/platform/fuchsia/flutter/meta/jit_product_runtime
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-    "runner": "fuchsia-pkg://fuchsia.com/flutter_jit_product_runner#meta/flutter_jit_product_runner.cmx"
-}
diff --git a/shell/platform/fuchsia/flutter/meta/jit_runtime b/shell/platform/fuchsia/flutter/meta/jit_runtime
deleted file mode 100644
index d23fb95..0000000
--- a/shell/platform/fuchsia/flutter/meta/jit_runtime
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-    "runner": "fuchsia-pkg://fuchsia.com/flutter_jit_runner#meta/flutter_jit_runner.cmx"
-}
\ No newline at end of file
diff --git a/shell/platform/fuchsia/flutter/runner.cc b/shell/platform/fuchsia/flutter/runner.cc
index 97cb8dd..e49c689 100644
--- a/shell/platform/fuchsia/flutter/runner.cc
+++ b/shell/platform/fuchsia/flutter/runner.cc
@@ -187,8 +187,6 @@
 
   SetThreadName("io.flutter.runner.main");
 
-  context_->outgoing()->AddPublicService<fuchsia::sys::Runner>(
-      std::bind(&Runner::RegisterComponentV1, this, std::placeholders::_1));
   context_->outgoing()
       ->AddPublicService<fuchsia::component::runner::ComponentRunner>(
           std::bind(&Runner::RegisterComponentV2, this, std::placeholders::_1));
@@ -214,82 +212,6 @@
 #endif  // !defined(DART_PRODUCT)
 }
 
-// CF v1 lifecycle methods.
-
-void Runner::RegisterComponentV1(
-    fidl::InterfaceRequest<fuchsia::sys::Runner> request) {
-  active_components_v1_bindings_.AddBinding(this, std::move(request));
-}
-
-void Runner::StartComponent(
-    fuchsia::sys::Package package,
-    fuchsia::sys::StartupInfo startup_info,
-    fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller) {
-  // TRACE_DURATION currently requires that the string data does not change
-  // in the traced scope. Since |package| gets moved in the Component::Create
-  // call below, we cannot ensure that |package.resolved_url| does not move or
-  // change, so we make a copy to pass to TRACE_DURATION.
-  // TODO(PT-169): Remove this copy when TRACE_DURATION reads string arguments
-  // eagerly.
-  std::string url_copy = package.resolved_url;
-  TRACE_EVENT1("flutter", "StartComponent", "url", url_copy.c_str());
-  // Notes on component termination: Components typically terminate on the
-  // thread on which they were created. This usually means the thread was
-  // specifically created to host the component. But we want to ensure that
-  // access to the active components collection is made on the same thread. So
-  // we capture the runner in the termination callback. There is no risk of
-  // there being multiple component runner instances in the process at the same
-  // time. So it is safe to use the raw pointer.
-  ComponentV1::TerminationCallback termination_callback =
-      [component_runner = this](const ComponentV1* component) {
-        component_runner->task_runner_->PostTask(
-            [component_runner, component]() {
-              component_runner->OnComponentV1Terminate(component);
-            });
-      };
-
-  ActiveComponentV1 active_component = ComponentV1::Create(
-      std::move(termination_callback),  // termination callback
-      std::move(package),               // component package
-      std::move(startup_info),          // startup info
-      context_->svc(),                  // runner incoming services
-      std::move(controller)             // controller request
-  );
-
-  auto key = active_component.component.get();
-  active_components_v1_[key] = std::move(active_component);
-}
-
-void Runner::OnComponentV1Terminate(const ComponentV1* component) {
-  auto app = active_components_v1_.find(component);
-  if (app == active_components_v1_.end()) {
-    FML_LOG(INFO)
-        << "The remote end of the component runner tried to terminate an "
-           "component that has already been terminated, possibly because we "
-           "initiated the termination";
-    return;
-  }
-  ActiveComponentV1& active_component = app->second;
-
-  // Grab the items out of the entry because we will have to rethread the
-  // destruction.
-  std::unique_ptr<ComponentV1> component_to_destroy =
-      std::move(active_component.component);
-  std::unique_ptr<fml::Thread> component_thread =
-      std::move(active_component.platform_thread);
-
-  // Delete the entry.
-  active_components_v1_.erase(component);
-
-  // Post the task to destroy the component and quit its message loop.
-  component_thread->GetTaskRunner()->PostTask(fml::MakeCopyable(
-      [instance = std::move(component_to_destroy),
-       thread = component_thread.get()]() mutable { instance.reset(); }));
-
-  // Terminate and join the thread's message loop.
-  component_thread->Join();
-}
-
 // CF v2 lifecycle methods.
 
 void Runner::RegisterComponentV2(
@@ -409,7 +331,6 @@
             latch.Wait();
           }
         };
-        write_profile_trace_for_components(runner->active_components_v1_);
         write_profile_trace_for_components(runner->active_components_v2_);
 
         Dart_StopProfiling();
diff --git a/shell/platform/fuchsia/flutter/runner.h b/shell/platform/fuchsia/flutter/runner.h
index 2d5c711..4c077b6 100644
--- a/shell/platform/fuchsia/flutter/runner.h
+++ b/shell/platform/fuchsia/flutter/runner.h
@@ -15,7 +15,6 @@
 #include <lib/trace-engine/instrumentation.h>
 #include <lib/trace/observer.h>
 
-#include "component_v1.h"
 #include "component_v2.h"
 #include "flutter/fml/macros.h"
 #include "fml/memory/ref_ptr.h"
@@ -25,14 +24,13 @@
 
 namespace flutter_runner {
 
-/// Publishes the CF v1 and CF v2 runner services.
+/// Publishes the CF v2 runner service.
 ///
 /// Each component will be run on a separate thread dedicated to that component.
 ///
 /// TODO(fxb/50694): Add unit tests for CF v2.
 class Runner final
-    : public fuchsia::sys::Runner /* CF v1 */,
-      public fuchsia::component::runner::ComponentRunner /* CF v2 */ {
+    : public fuchsia::component::runner::ComponentRunner /* CF v2 */ {
  public:
   // Does not take ownership of context.
   Runner(fml::RefPtr<fml::TaskRunner> task_runner,
@@ -41,25 +39,6 @@
   ~Runner();
 
  private:
-  // CF v1 lifecycle methods.
-  // TODO(fxb/50694) Deprecate these once all Flutter components have been
-  // ported to CF v2.
-
-  // |fuchsia::sys::Runner|
-  void StartComponent(fuchsia::sys::Package package,
-                      fuchsia::sys::StartupInfo startup_info,
-                      fidl::InterfaceRequest<fuchsia::sys::ComponentController>
-                          controller) override;
-
-  /// Registers a new CF v1 component with this runner, binding the component
-  /// to this runner.
-  void RegisterComponentV1(
-      fidl::InterfaceRequest<fuchsia::sys::Runner> request);
-
-  /// Callback that should be fired when a registered CF v2 component is
-  /// terminated.
-  void OnComponentV1Terminate(const ComponentV1* component);
-
   // CF v2 lifecycle methods.
 
   // |fuchsia::component::runner::ComponentRunner|
@@ -97,11 +76,6 @@
 
   sys::ComponentContext* context_;
 
-  // CF v1 component state.
-  fidl::BindingSet<fuchsia::sys::Runner> active_components_v1_bindings_;
-  std::unordered_map<const ComponentV1*, ActiveComponentV1>
-      active_components_v1_;
-
   // CF v2 component state.
 
   /// The components that are currently bound to this runner.
diff --git a/shell/platform/linux/fl_platform_plugin.cc b/shell/platform/linux/fl_platform_plugin.cc
index 1507626..2a2065b 100644
--- a/shell/platform/linux/fl_platform_plugin.cc
+++ b/shell/platform/linux/fl_platform_plugin.cc
@@ -14,15 +14,25 @@
 static constexpr char kBadArgumentsError[] = "Bad Arguments";
 static constexpr char kUnknownClipboardFormatError[] =
     "Unknown Clipboard Format";
-static constexpr char kFailedError[] = "Failed";
+static constexpr char kInProgressError[] = "In Progress";
 static constexpr char kGetClipboardDataMethod[] = "Clipboard.getData";
 static constexpr char kSetClipboardDataMethod[] = "Clipboard.setData";
 static constexpr char kClipboardHasStringsMethod[] = "Clipboard.hasStrings";
+static constexpr char kExitApplicationMethod[] = "System.exitApplication";
+static constexpr char kRequestAppExitMethod[] = "System.requestAppExit";
 static constexpr char kPlaySoundMethod[] = "SystemSound.play";
 static constexpr char kSystemNavigatorPopMethod[] = "SystemNavigator.pop";
 static constexpr char kTextKey[] = "text";
 static constexpr char kValueKey[] = "value";
 
+static constexpr char kExitTypeKey[] = "type";
+static constexpr char kExitTypeCancelable[] = "cancelable";
+static constexpr char kExitTypeRequired[] = "required";
+
+static constexpr char kExitResponseKey[] = "response";
+static constexpr char kExitResponseCancel[] = "cancel";
+static constexpr char kExitResponseExit[] = "exit";
+
 static constexpr char kTextPlainFormat[] = "text/plain";
 
 static constexpr char kSoundTypeAlert[] = "SystemSoundType.alert";
@@ -32,6 +42,8 @@
   GObject parent_instance;
 
   FlMethodChannel* channel;
+  FlMethodCall* exit_application_method_call;
+  GCancellable* cancellable;
 };
 
 G_DEFINE_TYPE(FlPlatformPlugin, fl_platform_plugin, G_TYPE_OBJECT)
@@ -140,6 +152,138 @@
   return nullptr;
 }
 
+// Get the exit response from a System.requestAppExit method call.
+static gchar* get_exit_response(FlMethodResponse* response) {
+  if (response == nullptr) {
+    return nullptr;
+  }
+
+  g_autoptr(GError) error = nullptr;
+  FlValue* result = fl_method_response_get_result(response, &error);
+  if (result == nullptr) {
+    g_warning("Error returned from System.requestAppExit: %s", error->message);
+    return nullptr;
+  }
+  if (fl_value_get_type(result) != FL_VALUE_TYPE_MAP) {
+    g_warning("System.requestAppExit result argument map missing or malformed");
+    return nullptr;
+  }
+
+  FlValue* response_value = fl_value_lookup_string(result, kExitResponseKey);
+  if (fl_value_get_type(response_value) != FL_VALUE_TYPE_STRING) {
+    g_warning("Invalid response from System.requestAppExit");
+    return nullptr;
+  }
+  return g_strdup(fl_value_get_string(response_value));
+}
+
+// Quit this application
+static void quit_application() {
+  GApplication* app = g_application_get_default();
+  if (app == nullptr) {
+    // Unable to gracefully quit, so just exit the process.
+    exit(0);
+  } else {
+    g_application_quit(app);
+  }
+}
+
+// Handle response of System.requestAppExit.
+static void request_app_exit_response_cb(GObject* object,
+                                         GAsyncResult* result,
+                                         gpointer user_data) {
+  FlPlatformPlugin* self = FL_PLATFORM_PLUGIN(user_data);
+
+  g_autoptr(GError) error = nullptr;
+  g_autoptr(FlMethodResponse) method_response =
+      fl_method_channel_invoke_method_finish(FL_METHOD_CHANNEL(object), result,
+                                             &error);
+  g_autofree gchar* exit_response = nullptr;
+  if (method_response == nullptr) {
+    if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+      return;
+    }
+    g_warning("Failed to complete System.requestAppExit: %s", error->message);
+  } else {
+    exit_response = get_exit_response(method_response);
+  }
+  // If something went wrong, then just exit.
+  if (exit_response == nullptr) {
+    exit_response = g_strdup(kExitResponseExit);
+  }
+
+  if (g_str_equal(exit_response, kExitResponseExit)) {
+    quit_application();
+  } else if (g_str_equal(exit_response, kExitResponseCancel)) {
+    // Canceled - no action to take.
+  }
+
+  // If request was due to a request from Flutter, pass result back.
+  if (self->exit_application_method_call != nullptr) {
+    g_autoptr(FlValue) exit_result = fl_value_new_map();
+    fl_value_set_string_take(exit_result, kExitResponseKey,
+                             fl_value_new_string(exit_response));
+    g_autoptr(FlMethodResponse) exit_response =
+        FL_METHOD_RESPONSE(fl_method_success_response_new(exit_result));
+    if (!fl_method_call_respond(self->exit_application_method_call,
+                                exit_response, &error)) {
+      g_warning("Failed to send response to System.exitApplication: %s",
+                error->message);
+    }
+    g_clear_object(&self->exit_application_method_call);
+  }
+}
+
+// Send a request to Flutter to exit the application.
+static void request_app_exit(FlPlatformPlugin* self, const char* type) {
+  g_autoptr(FlValue) args = fl_value_new_map();
+  fl_value_set_string_take(args, kExitTypeKey, fl_value_new_string(type));
+  fl_method_channel_invoke_method(self->channel, kRequestAppExitMethod, args,
+                                  self->cancellable,
+                                  request_app_exit_response_cb, self);
+}
+
+// Called when Flutter wants to exit the application.
+static FlMethodResponse* system_exit_application(FlPlatformPlugin* self,
+                                                 FlMethodCall* method_call) {
+  FlValue* args = fl_method_call_get_args(method_call);
+  if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) {
+    return FL_METHOD_RESPONSE(fl_method_error_response_new(
+        kBadArgumentsError, "Argument map missing or malformed", nullptr));
+  }
+
+  FlValue* type_value = fl_value_lookup_string(args, kExitTypeKey);
+  if (type_value == nullptr ||
+      fl_value_get_type(type_value) != FL_VALUE_TYPE_STRING) {
+    return FL_METHOD_RESPONSE(fl_method_error_response_new(
+        kBadArgumentsError, "Missing type argument", nullptr));
+  }
+  const char* type = fl_value_get_string(type_value);
+
+  // Save method call to respond to when our request to Flutter completes.
+  if (self->exit_application_method_call != nullptr) {
+    return FL_METHOD_RESPONSE(fl_method_error_response_new(
+        kInProgressError, "Request already in progress", nullptr));
+  }
+  self->exit_application_method_call =
+      FL_METHOD_CALL(g_object_ref(method_call));
+
+  // Requested to immediately quit.
+  if (g_str_equal(type, kExitTypeRequired)) {
+    quit_application();
+    g_autoptr(FlValue) exit_result = fl_value_new_map();
+    fl_value_set_string_take(exit_result, kExitResponseKey,
+                             fl_value_new_string(kExitResponseExit));
+    return FL_METHOD_RESPONSE(fl_method_success_response_new(exit_result));
+  }
+
+  // Send the request back to Flutter to follow the standard process.
+  request_app_exit(self, type);
+
+  // Will respond later.
+  return nullptr;
+}
+
 // Called when Flutter wants to play a sound.
 static FlMethodResponse* system_sound_play(FlPlatformPlugin* self,
                                            FlValue* args) {
@@ -165,14 +309,7 @@
 
 // Called when Flutter wants to quit the application.
 static FlMethodResponse* system_navigator_pop(FlPlatformPlugin* self) {
-  GApplication* app = g_application_get_default();
-  if (app == nullptr) {
-    return FL_METHOD_RESPONSE(fl_method_error_response_new(
-        kFailedError, "Unable to get GApplication", nullptr));
-  }
-
-  g_application_quit(app);
-
+  quit_application();
   return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
 }
 
@@ -192,6 +329,8 @@
     response = clipboard_get_data_async(self, method_call);
   } else if (strcmp(method, kClipboardHasStringsMethod) == 0) {
     response = clipboard_has_strings_async(self, method_call);
+  } else if (strcmp(method, kExitApplicationMethod) == 0) {
+    response = system_exit_application(self, method_call);
   } else if (strcmp(method, kPlaySoundMethod) == 0) {
     response = system_sound_play(self, args);
   } else if (strcmp(method, kSystemNavigatorPopMethod) == 0) {
@@ -208,7 +347,11 @@
 static void fl_platform_plugin_dispose(GObject* object) {
   FlPlatformPlugin* self = FL_PLATFORM_PLUGIN(object);
 
+  g_cancellable_cancel(self->cancellable);
+
   g_clear_object(&self->channel);
+  g_clear_object(&self->exit_application_method_call);
+  g_clear_object(&self->cancellable);
 
   G_OBJECT_CLASS(fl_platform_plugin_parent_class)->dispose(object);
 }
@@ -217,7 +360,9 @@
   G_OBJECT_CLASS(klass)->dispose = fl_platform_plugin_dispose;
 }
 
-static void fl_platform_plugin_init(FlPlatformPlugin* self) {}
+static void fl_platform_plugin_init(FlPlatformPlugin* self) {
+  self->cancellable = g_cancellable_new();
+}
 
 FlPlatformPlugin* fl_platform_plugin_new(FlBinaryMessenger* messenger) {
   g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);
@@ -233,3 +378,9 @@
 
   return self;
 }
+
+void fl_platform_plugin_request_app_exit(FlPlatformPlugin* self) {
+  g_return_if_fail(FL_IS_PLATFORM_PLUGIN(self));
+  // Request a cancellable exit.
+  request_app_exit(self, kExitTypeCancelable);
+}
diff --git a/shell/platform/linux/fl_platform_plugin.h b/shell/platform/linux/fl_platform_plugin.h
index 72f91ea..c25874d 100644
--- a/shell/platform/linux/fl_platform_plugin.h
+++ b/shell/platform/linux/fl_platform_plugin.h
@@ -33,6 +33,15 @@
  */
 FlPlatformPlugin* fl_platform_plugin_new(FlBinaryMessenger* messenger);
 
+/**
+ * fl_platform_plugin_request_app_exit:
+ * @plugin: an #FlPlatformPlugin
+ *
+ * Request the application exits (i.e. due to the window being requested to be
+ * closed).
+ */
+void fl_platform_plugin_request_app_exit(FlPlatformPlugin* plugin);
+
 G_END_DECLS
 
 #endif  // FLUTTER_SHELL_PLATFORM_LINUX_FL_PLATFORM_PLUGIN_H_
diff --git a/shell/platform/linux/fl_platform_plugin_test.cc b/shell/platform/linux/fl_platform_plugin_test.cc
index 88051e8..0bf5b80 100644
--- a/shell/platform/linux/fl_platform_plugin_test.cc
+++ b/shell/platform/linux/fl_platform_plugin_test.cc
@@ -26,6 +26,67 @@
   return false;
 }
 
+class MethodCallMatcher {
+ public:
+  using is_gtest_matcher = void;
+
+  explicit MethodCallMatcher(::testing::Matcher<std::string> name,
+                             ::testing::Matcher<FlValue*> args)
+      : name_(std::move(name)), args_(std::move(args)) {}
+
+  bool MatchAndExplain(GBytes* method_call,
+                       ::testing::MatchResultListener* result_listener) const {
+    g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new();
+    g_autoptr(GError) error = nullptr;
+    g_autofree gchar* name = nullptr;
+    g_autoptr(FlValue) args = nullptr;
+    gboolean result = fl_method_codec_decode_method_call(
+        FL_METHOD_CODEC(codec), method_call, &name, &args, &error);
+    if (!result) {
+      *result_listener << ::testing::PrintToString(error->message);
+      return false;
+    }
+    if (!name_.MatchAndExplain(name, result_listener)) {
+      *result_listener << " where the name doesn't match: \"" << name << "\"";
+      return false;
+    }
+    if (!args_.MatchAndExplain(args, result_listener)) {
+      *result_listener << " where the args don't match: "
+                       << ::testing::PrintToString(args);
+      return false;
+    }
+    return true;
+  }
+
+  void DescribeTo(std::ostream* os) const {
+    *os << "method name ";
+    name_.DescribeTo(os);
+    *os << " and args ";
+    args_.DescribeTo(os);
+  }
+
+  void DescribeNegationTo(std::ostream* os) const {
+    *os << "method name ";
+    name_.DescribeNegationTo(os);
+    *os << " or args ";
+    args_.DescribeNegationTo(os);
+  }
+
+ private:
+  ::testing::Matcher<std::string> name_;
+  ::testing::Matcher<FlValue*> args_;
+};
+
+static ::testing::Matcher<GBytes*> MethodCall(
+    const std::string& name,
+    ::testing::Matcher<FlValue*> args) {
+  return MethodCallMatcher(::testing::StrEq(name), std::move(args));
+}
+
+MATCHER_P(FlValueEq, value, "equal to " + ::testing::PrintToString(value)) {
+  return fl_value_equal(arg, value);
+}
+
 TEST(FlPlatformPluginTest, PlaySound) {
   ::testing::NiceMock<flutter::testing::MockBinaryMessenger> messenger;
 
@@ -45,3 +106,28 @@
 
   messenger.ReceiveMessage("flutter/platform", message);
 }
+
+TEST(FlPlatformPluginTest, ExitApplication) {
+  ::testing::NiceMock<flutter::testing::MockBinaryMessenger> messenger;
+
+  g_autoptr(FlPlatformPlugin) plugin = fl_platform_plugin_new(messenger);
+  EXPECT_NE(plugin, nullptr);
+
+  g_autoptr(FlValue) args = fl_value_new_map();
+  fl_value_set_string_take(args, "type", fl_value_new_string("cancelable"));
+  g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new();
+  g_autoptr(GBytes) message = fl_method_codec_encode_method_call(
+      FL_METHOD_CODEC(codec), "System.exitApplication", args, nullptr);
+
+  g_autoptr(FlValue) requestArgs = fl_value_new_map();
+  fl_value_set_string_take(requestArgs, "type",
+                           fl_value_new_string("cancelable"));
+  EXPECT_CALL(messenger,
+              fl_binary_messenger_send_on_channel(
+                  ::testing::Eq<FlBinaryMessenger*>(messenger),
+                  ::testing::StrEq("flutter/platform"),
+                  MethodCall("System.requestAppExit", FlValueEq(requestArgs)),
+                  ::testing::_, ::testing::_, ::testing::_));
+
+  messenger.ReceiveMessage("flutter/platform", message);
+}
diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc
index cb77e0c..58f11eb 100644
--- a/shell/platform/linux/fl_view.cc
+++ b/shell/platform/linux/fl_view.cc
@@ -89,6 +89,15 @@
                 G_IMPLEMENT_INTERFACE(fl_text_input_view_delegate_get_type(),
                                       fl_view_text_input_delegate_iface_init))
 
+// Signal handler for GtkWidget::delete-event
+static gboolean window_delete_event_cb(GtkWidget* widget,
+                                       GdkEvent* event,
+                                       FlView* self) {
+  fl_platform_plugin_request_app_exit(self->platform_plugin);
+  // Stop the event from propagating.
+  return TRUE;
+}
+
 // Initialize keyboard manager.
 static void init_keyboard(FlView* self) {
   FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(self->engine);
@@ -475,6 +484,11 @@
   FlView* self = FL_VIEW(widget);
   g_autoptr(GError) error = nullptr;
 
+  // Handle requests by the user to close the application.
+  GtkWidget* toplevel_window = gtk_widget_get_toplevel(GTK_WIDGET(self));
+  g_signal_connect(toplevel_window, "delete-event",
+                   G_CALLBACK(window_delete_event_cb), self);
+
   init_keyboard(self);
 
   if (!fl_renderer_start(self->renderer, self, &error)) {
diff --git a/shell/platform/windows/accessibility_bridge_windows_unittests.cc b/shell/platform/windows/accessibility_bridge_windows_unittests.cc
index d2d4d79..089e3aa 100644
--- a/shell/platform/windows/accessibility_bridge_windows_unittests.cc
+++ b/shell/platform/windows/accessibility_bridge_windows_unittests.cc
@@ -151,11 +151,11 @@
   // Add node 4: text child (with no text) of node 2.
   FlutterSemanticsNode node4{sizeof(FlutterSemanticsNode), 4};
 
-  bridge->AddFlutterSemanticsNodeUpdate(&node0);
-  bridge->AddFlutterSemanticsNodeUpdate(&node1);
-  bridge->AddFlutterSemanticsNodeUpdate(&node2);
-  bridge->AddFlutterSemanticsNodeUpdate(&node3);
-  bridge->AddFlutterSemanticsNodeUpdate(&node4);
+  bridge->AddFlutterSemanticsNodeUpdate(node0);
+  bridge->AddFlutterSemanticsNodeUpdate(node1);
+  bridge->AddFlutterSemanticsNodeUpdate(node2);
+  bridge->AddFlutterSemanticsNodeUpdate(node3);
+  bridge->AddFlutterSemanticsNodeUpdate(node4);
   bridge->CommitUpdates();
 }
 
diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc
index 8eddb3f..b49e6ec 100644
--- a/shell/platform/windows/flutter_windows_engine.cc
+++ b/shell/platform/windows/flutter_windows_engine.cc
@@ -332,14 +332,13 @@
     auto host = static_cast<FlutterWindowsEngine*>(user_data);
 
     for (size_t i = 0; i < update->nodes_count; i++) {
-      const FlutterSemanticsNode* node = &update->nodes[i];
-      host->accessibility_bridge_->AddFlutterSemanticsNodeUpdate(node);
+      host->accessibility_bridge_->AddFlutterSemanticsNodeUpdate(
+          update->nodes[i]);
     }
 
     for (size_t i = 0; i < update->custom_actions_count; i++) {
-      const FlutterSemanticsCustomAction* action = &update->custom_actions[i];
       host->accessibility_bridge_->AddFlutterSemanticsCustomActionUpdate(
-          action);
+          update->custom_actions[i]);
     }
 
     host->accessibility_bridge_->CommitUpdates();
diff --git a/shell/platform/windows/flutter_windows_view_unittests.cc b/shell/platform/windows/flutter_windows_view_unittests.cc
index c057f79..bff5080 100644
--- a/shell/platform/windows/flutter_windows_view_unittests.cc
+++ b/shell/platform/windows/flutter_windows_view_unittests.cc
@@ -162,7 +162,7 @@
   node.label = "name";
   node.value = "value";
   node.platform_view_id = -1;
-  bridge->AddFlutterSemanticsNodeUpdate(&node);
+  bridge->AddFlutterSemanticsNodeUpdate(node);
   bridge->CommitUpdates();
 
   // Look up the root windows node delegate.
@@ -275,10 +275,10 @@
   node3.label = "city";
   node3.value = "Uji";
 
-  bridge->AddFlutterSemanticsNodeUpdate(&node0);
-  bridge->AddFlutterSemanticsNodeUpdate(&node1);
-  bridge->AddFlutterSemanticsNodeUpdate(&node2);
-  bridge->AddFlutterSemanticsNodeUpdate(&node3);
+  bridge->AddFlutterSemanticsNodeUpdate(node0);
+  bridge->AddFlutterSemanticsNodeUpdate(node1);
+  bridge->AddFlutterSemanticsNodeUpdate(node2);
+  bridge->AddFlutterSemanticsNodeUpdate(node3);
   bridge->CommitUpdates();
 
   // Look up the root windows node delegate.
@@ -465,8 +465,8 @@
   node2.label = "prefecture";
   node2.value = "Kyoto";
 
-  bridge->AddFlutterSemanticsNodeUpdate(&node1);
-  bridge->AddFlutterSemanticsNodeUpdate(&node2);
+  bridge->AddFlutterSemanticsNodeUpdate(node1);
+  bridge->AddFlutterSemanticsNodeUpdate(node2);
   bridge->CommitUpdates();
 
   // Look up the root windows node delegate.
@@ -618,10 +618,10 @@
   node3.label = "city";
   node3.value = "Uji";
 
-  bridge->AddFlutterSemanticsNodeUpdate(&node0);
-  bridge->AddFlutterSemanticsNodeUpdate(&node1);
-  bridge->AddFlutterSemanticsNodeUpdate(&node2);
-  bridge->AddFlutterSemanticsNodeUpdate(&node3);
+  bridge->AddFlutterSemanticsNodeUpdate(node0);
+  bridge->AddFlutterSemanticsNodeUpdate(node1);
+  bridge->AddFlutterSemanticsNodeUpdate(node2);
+  bridge->AddFlutterSemanticsNodeUpdate(node3);
   bridge->CommitUpdates();
 
   // Look up the root windows node delegate.
@@ -743,7 +743,7 @@
   root.flags = static_cast<FlutterSemanticsFlag>(
       FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState |
       FlutterSemanticsFlag::kFlutterSemanticsFlagIsChecked);
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   bridge->CommitUpdates();
 
@@ -782,7 +782,7 @@
   // Test unchecked too.
   root.flags = static_cast<FlutterSemanticsFlag>(
       FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState);
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
   bridge->CommitUpdates();
 
   {
@@ -821,7 +821,7 @@
   root.flags = static_cast<FlutterSemanticsFlag>(
       FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState |
       FlutterSemanticsFlag::kFlutterSemanticsFlagIsCheckStateMixed);
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
   bridge->CommitUpdates();
 
   {
@@ -889,7 +889,7 @@
   root.flags = static_cast<FlutterSemanticsFlag>(
       FlutterSemanticsFlag::kFlutterSemanticsFlagHasToggledState |
       FlutterSemanticsFlag::kFlutterSemanticsFlagIsToggled);
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   bridge->CommitUpdates();
 
@@ -938,7 +938,7 @@
   // Test unpressed too.
   root.flags = static_cast<FlutterSemanticsFlag>(
       FlutterSemanticsFlag::kFlutterSemanticsFlagHasToggledState);
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
   bridge->CommitUpdates();
 
   {
@@ -1006,7 +1006,7 @@
   root.custom_accessibility_actions_count = 0;
   root.flags = static_cast<FlutterSemanticsFlag>(
       FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField);
-  bridge->AddFlutterSemanticsNodeUpdate(&root);
+  bridge->AddFlutterSemanticsNodeUpdate(root);
 
   bridge->CommitUpdates();
   auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
diff --git a/sky/packages/sky_engine/LICENSE b/sky/packages/sky_engine/LICENSE
index f38346b..7cf2b9f 100644
--- a/sky/packages/sky_engine/LICENSE
+++ b/sky/packages/sky_engine/LICENSE
@@ -28049,6 +28049,38 @@
 --------------------------------------------------------------------------------
 skia
 
+Copyright 2023 Google LLC.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+  * Neither the name of the copyright holder nor the names of its
+    contributors may be used to endorse or promote products derived
+    from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------------
+skia
+
 Copyright 2023 The Android Open Source Project
 
 Redistribution and use in source and binary forms, with or without
diff --git a/testing/dart/assets_test.dart b/testing/dart/assets_test.dart
index 198f952..21e0c76 100644
--- a/testing/dart/assets_test.dart
+++ b/testing/dart/assets_test.dart
@@ -70,7 +70,7 @@
     /// Manually load font asset through dart.
     final Uint8List encoded = utf8.encoder.convert(Uri(path: Uri.encodeFull('Roboto-Medium.ttf')).path);
     final Completer<Uint8List> result = Completer<Uint8List>();
-    window.sendPlatformMessage('flutter/assets', encoded.buffer.asByteData(), (ByteData? data) {
+    PlatformDispatcher.instance.sendPlatformMessage('flutter/assets', encoded.buffer.asByteData(), (ByteData? data) {
       result.complete(data!.buffer.asUint8List());
     });
 
diff --git a/testing/dart/color_test.dart b/testing/dart/color_test.dart
index 8876fa8..5d8f680 100644
--- a/testing/dart/color_test.dart
+++ b/testing/dart/color_test.dart
@@ -7,7 +7,7 @@
 import 'package:litetest/litetest.dart';
 
 class NotAColor extends Color {
-  const NotAColor(int value) : super(value);
+  const NotAColor(super.value);
 }
 
 void main() {
diff --git a/testing/dart/observatory/skp_test.dart b/testing/dart/observatory/skp_test.dart
index 00c7235..239e3b5 100644
--- a/testing/dart/observatory/skp_test.dart
+++ b/testing/dart/observatory/skp_test.dart
@@ -25,7 +25,7 @@
     );
 
     final Completer<void> completer = Completer<void>();
-    window.onBeginFrame = (Duration timeStamp) {
+    PlatformDispatcher.instance.onBeginFrame = (Duration timeStamp) {
       final PictureRecorder recorder = PictureRecorder();
       final Canvas canvas = Canvas(recorder);
       canvas.drawRect(const Rect.fromLTRB(10, 10, 20, 20), Paint());
@@ -35,14 +35,11 @@
       builder.addPicture(Offset.zero, picture);
       final Scene scene = builder.build();
 
-      window.render(scene);
+      PlatformDispatcher.instance.implicitView!.render(scene);
       scene.dispose();
-      // window.onBeginFrame = (Duration timeStamp) {
-        completer.complete();
-      // };
-      // window.scheduleFrame();
+      completer.complete();
     };
-    window.scheduleFrame();
+    PlatformDispatcher.instance.scheduleFrame();
     await completer.future;
 
     final vms.Response response = await vmService.callServiceExtension('_flutter.screenshotSkp');
diff --git a/testing/dart/observatory/tracing_test.dart b/testing/dart/observatory/tracing_test.dart
index 6f709bf..9c9f961 100644
--- a/testing/dart/observatory/tracing_test.dart
+++ b/testing/dart/observatory/tracing_test.dart
@@ -23,7 +23,7 @@
     );
 
     final Completer<void> completer = Completer<void>();
-    window.onBeginFrame = (Duration timeStamp) async {
+    PlatformDispatcher.instance.onBeginFrame = (Duration timeStamp) async {
       final PictureRecorder recorder = PictureRecorder();
       final Canvas canvas = Canvas(recorder);
       canvas.drawColor(const Color(0xff0000ff), BlendMode.srcOut);
@@ -45,7 +45,7 @@
       scene.dispose();
       completer.complete();
     };
-    window.scheduleFrame();
+    PlatformDispatcher.instance.scheduleFrame();
     await completer.future;
 
     final vms.Timeline timeline = await vmService.getVMTimeline();
diff --git a/testing/dart/observatory/vmservice_methods_test.dart b/testing/dart/observatory/vmservice_methods_test.dart
index e74caac..7ba1565 100644
--- a/testing/dart/observatory/vmservice_methods_test.dart
+++ b/testing/dart/observatory/vmservice_methods_test.dart
@@ -75,7 +75,7 @@
       }
 
       final Completer<PlatformResponse> completer = Completer<PlatformResponse>();
-      ui.window.onPlatformMessage = (String name, ByteData? data, ui.PlatformMessageResponseCallback? callback) {
+      ui.PlatformDispatcher.instance.onPlatformMessage = (String name, ByteData? data, ui.PlatformMessageResponseCallback? callback) {
         final ByteBuffer buffer = data!.buffer;
         final Uint8List list = buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
         completer.complete(PlatformResponse(name: name, contents: utf8.decode(list)));
diff --git a/testing/dart/platform_view_test.dart b/testing/dart/platform_view_test.dart
index c234e63..146c865 100644
--- a/testing/dart/platform_view_test.dart
+++ b/testing/dart/platform_view_test.dart
@@ -12,7 +12,7 @@
     builder.addPlatformView(1);
     final Scene scene = builder.build();
 
-    window.render(scene);
+    PlatformDispatcher.instance.implicitView!.render(scene);
     scene.dispose();
     // Test harness asserts that this does not emit an error from the shell logs.
   });
diff --git a/testing/dart/pubspec.yaml b/testing/dart/pubspec.yaml
index 971314f..cebfd58 100644
--- a/testing/dart/pubspec.yaml
+++ b/testing/dart/pubspec.yaml
@@ -14,7 +14,7 @@
 # relative to this directory into //third_party/dart
 
 environment:
-  sdk: '>=2.12.0 <3.0.0'
+  sdk: '>=2.17.0 <3.0.0'
 
 dependencies:
   litetest: any
diff --git a/testing/dart/text_test.dart b/testing/dart/text_test.dart
index e0f9c82..db23069 100644
--- a/testing/dart/text_test.dart
+++ b/testing/dart/text_test.dart
@@ -195,10 +195,10 @@
 
 void testLoadFontFromList() {
   test('loadFontFromList will send platform message after font is loaded', () async {
-    final PlatformMessageCallback? oldHandler = window.onPlatformMessage;
+    final PlatformMessageCallback? oldHandler = PlatformDispatcher.instance.onPlatformMessage;
     late String actualName;
     late String message;
-    window.onPlatformMessage = (String name, ByteData? data, PlatformMessageResponseCallback? callback) {
+    PlatformDispatcher.instance.onPlatformMessage = (String name, ByteData? data, PlatformMessageResponseCallback? callback) {
       assert(data != null);
       actualName = name;
       final Uint8List list = data!.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
@@ -206,7 +206,7 @@
     };
     final Uint8List fontData = Uint8List(0);
     await loadFontFromList(fontData, fontFamily: 'fake');
-    window.onPlatformMessage = oldHandler;
+    PlatformDispatcher.instance.onPlatformMessage = oldHandler;
     expect(actualName, 'flutter/system');
     expect(message, '{"type":"fontsChange"}');
   });
diff --git a/testing/dart/window_test.dart b/testing/dart/window_test.dart
index 66bcefa..018c72a 100644
--- a/testing/dart/window_test.dart
+++ b/testing/dart/window_test.dart
@@ -12,7 +12,7 @@
   test('window.sendPlatformMessage preserves callback zone', () {
     runZoned(() {
       final Zone innerZone = Zone.current;
-      window.sendPlatformMessage('test', ByteData.view(Uint8List(0).buffer), expectAsync1((ByteData? data) {
+      PlatformDispatcher.instance.sendPlatformMessage('test', ByteData.view(Uint8List(0).buffer), expectAsync1((ByteData? data) {
         final Zone runZone = Zone.current;
         expect(runZone, isNotNull);
         expect(runZone, same(innerZone));
@@ -76,7 +76,7 @@
       const Locale.fromSubtags(languageCode: 'en'),
     ];
     // The default implementation returns null due to lack of a real platform.
-    final Locale? result = window.computePlatformResolvedLocale(supportedLocales);
+    final Locale? result = PlatformDispatcher.instance.computePlatformResolvedLocale(supportedLocales);
     expect(result, null);
   });
 }
diff --git a/tools/activate_emsdk.py b/tools/activate_emsdk.py
index 30fd1b0..9b4e3ae 100644
--- a/tools/activate_emsdk.py
+++ b/tools/activate_emsdk.py
@@ -9,7 +9,9 @@
 import subprocess
 import sys
 
-EMSDK_ROOT = os.path.join('src', 'buildtools', 'emsdk')
+EMSDK_ROOT = os.path.abspath(
+    os.path.join(__file__, '..', '..', '..', 'buildtools', 'emsdk')
+)
 
 EMSDK_PATH = os.path.join(EMSDK_ROOT, 'emsdk.py')
 
diff --git a/tools/fuchsia/flutter/flutter_build_config.gni b/tools/fuchsia/flutter/flutter_build_config.gni
index b7c033a..a322a7e 100644
--- a/tools/fuchsia/flutter/flutter_build_config.gni
+++ b/tools/fuchsia/flutter/flutter_build_config.gni
@@ -12,7 +12,6 @@
 # Builds the component in a non-product JIT build. This will
 # launch the vm service in the runner.
 flutter_debug_build_cfg = {
-  runtime_meta = "//flutter/shell/platform/fuchsia/flutter/meta/jit_runtime"
   runner_dep = "//flutter/shell/platform/fuchsia/flutter:flutter_jit_runner"
   platform_name = "flutter_runner"
   is_aot = false
@@ -25,7 +24,6 @@
 # This configuration is not compatible with a --release build since the
 # profile aot runner is built without asserts.
 flutter_aot_debug_build_cfg = {
-  runtime_meta = "//flutter/shell/platform/fuchsia/flutter/meta/aot_runtime"
   runner_dep = "//flutter/shell/platform/fuchsia/flutter:flutter_aot_runner"
   platform_name = "flutter_runner"
   is_aot = true
@@ -36,9 +34,6 @@
 # Builds the component in a non-product AOT build. This will
 # launch the vm service in the runner.
 flutter_profile_build_cfg = {
-  runtime_meta =
-      "//flutter/shell/platform/fuchsia/flutter/meta/aot_runtime"  # profile
-                                                                   # runner
   runner_dep = "//flutter/shell/platform/fuchsia/flutter:flutter_aot_runner"
   platform_name = "flutter_runner"
   is_aot = true
@@ -49,8 +44,6 @@
 # Builds the component in a product JIT build. This will
 # not launch the vm service in the runner.
 flutter_jit_release_build_cfg = {
-  runtime_meta =
-      "//flutter/shell/platform/fuchsia/flutter/meta/jit_product_runtime"
   runner_dep =
       "//flutter/shell/platform/fuchsia/flutter:flutter_jit_product_runner"
   platform_name = "flutter_runner"
@@ -62,8 +55,6 @@
 # Builds the component in a product AOT build. This will
 # not launch the vm service in the runner.
 flutter_release_build_cfg = {
-  runtime_meta =
-      "//flutter/shell/platform/fuchsia/flutter/meta/aot_product_runtime"
   runner_dep =
       "//flutter/shell/platform/fuchsia/flutter:flutter_aot_product_runner"
   platform_name = "flutter_runner"
diff --git a/tools/gn b/tools/gn
index 4aa78f2..b893752 100755
--- a/tools/gn
+++ b/tools/gn
@@ -380,6 +380,10 @@
   else:
     gn_args['dart_runtime_mode'] = runtime_mode
 
+  # If we are building the dart sdk in-tree, exclude the wasm-opt target, as
+  # it doesn't build properly with our gn configuration.
+  gn_args['dart_include_wasm_opt'] = False
+
   # Desktop embeddings can have more dependencies than the engine library,
   # which can be problematic in some build environments (e.g., building on
   # Linux will bring in pkg-config dependencies at generation time). These