diff --git a/DEPS b/DEPS
index 90c222e..c44fb8d 100644
--- a/DEPS
+++ b/DEPS
@@ -285,7 +285,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '4deec479d43bb5667bc93c656f1b9320b7e82031',
+  'skia_revision': '85d9e67653b13c6ad1457ed461055968b5adca7e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -312,7 +312,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
-  'fuchsia_version': 'version:12.20230418.1.1',
+  'fuchsia_version': 'version:12.20230418.3.1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -412,7 +412,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '692846d0a07b7d5e5e923102b73e66444b54eb4d',
+  'dawn_revision': 'f4b9f95b68942a0fec8414c735c112756b93922c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -771,7 +771,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '7c980170b6cdc8553da644e6858d2355996e8c56',
+    '89e99fbe95441798f5879b09ec052925cbd30116',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1195,7 +1195,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9e36ef60d0b3b3da1d79cf388275697281d27f21',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '54762c22175e17dce4f4eab18c5942c06e82478f',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1858,7 +1858,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'cefabb95fc47d2962fb14d46ffdf2b89326e860b',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'a14d9250cfe6fb4c516733e22357e62d76d8ccf2',
 
   'src/third_party/webrtc':
     Var('webrtc_git') + '/src.git' + '@' + 'b43f06572853093010d826c9b49ebf23c765be57',
@@ -1951,7 +1951,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': Var('chrome_git') + '/chrome/src-internal.git@25b07a74bfe56e4a0b9e462419785cf53f7ca8b9',
+    'url': Var('chrome_git') + '/chrome/src-internal.git@7d73a0e1fa2ee7d3aa14b0401a000d7d43457c03',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java
index ad49a46..30a7bfa 100644
--- a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java
+++ b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java
@@ -106,9 +106,8 @@
             "SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL";
 
     /**
-     * @deprecated Feature was renamed to WEB_MESSAGE_ARRAY_BUFFER.
+     * Feature was renamed to WEB_MESSAGE_ARRAY_BUFFER.
      */
-    @Deprecated()
     public static final String WEB_MESSAGE_GET_MESSAGE_PAYLOAD = "WEB_MESSAGE_GET_MESSAGE_PAYLOAD";
 
     // JsReplyProxy.postMessageWithPayload
diff --git a/ash/assistant/ui/main_stage/assistant_text_element_view_unittest.cc b/ash/assistant/ui/main_stage/assistant_text_element_view_unittest.cc
index e48fec7..bb8a089 100644
--- a/ash/assistant/ui/main_stage/assistant_text_element_view_unittest.cc
+++ b/ash/assistant/ui/main_stage/assistant_text_element_view_unittest.cc
@@ -5,7 +5,6 @@
 #include "ash/assistant/ui/main_stage/assistant_text_element_view.h"
 
 #include "ash/assistant/ui/assistant_ui_constants.h"
-#include "ash/constants/ash_features.h"
 #include "ash/constants/ash_pref_names.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
@@ -13,7 +12,6 @@
 #include "ash/style/dark_light_mode_controller_impl.h"
 #include "ash/test/ash_test_base.h"
 #include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/widget/widget.h"
 
@@ -25,10 +23,6 @@
 using AssistantTextElementViewTest = AshTestBase;
 
 TEST_F(AssistantTextElementViewTest, DarkAndLightTheme) {
-  base::test::ScopedFeatureList scoped_feature_list(
-      chromeos::features::kDarkLightMode);
-  ASSERT_TRUE(chromeos::features::IsDarkLightModeEnabled());
-
   auto* color_provider = AshColorProvider::Get();
   auto* dark_light_mode_controller = DarkLightModeControllerImpl::Get();
   dark_light_mode_controller->OnActiveUserPrefServiceChanged(
diff --git a/ash/assistant/ui/main_stage/suggestion_chip_view_unittest.cc b/ash/assistant/ui/main_stage/suggestion_chip_view_unittest.cc
index a1b22f7e..006bc45 100644
--- a/ash/assistant/ui/main_stage/suggestion_chip_view_unittest.cc
+++ b/ash/assistant/ui/main_stage/suggestion_chip_view_unittest.cc
@@ -8,7 +8,6 @@
 #include "ash/assistant/ui/assistant_view_ids.h"
 #include "ash/assistant/ui/test_support/mock_assistant_view_delegate.h"
 #include "ash/assistant/util/test_support/macros.h"
-#include "ash/constants/ash_features.h"
 #include "ash/constants/ash_pref_names.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
@@ -19,7 +18,6 @@
 #include "cc/paint/paint_flags.h"
 #include "cc/test/pixel_comparator.h"
 #include "chromeos/ash/services/assistant/public/cpp/assistant_service.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/ui/vector_icons/vector_icons.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -119,10 +117,6 @@
 }
 
 TEST_F(SuggestionChipViewTest, DarkAndLightTheme) {
-  base::test::ScopedFeatureList scoped_feature_list(
-      chromeos::features::kDarkLightMode);
-  ASSERT_TRUE(chromeos::features::IsDarkLightModeEnabled());
-
   auto* dark_light_mode_controller = DarkLightModeControllerImpl::Get();
   dark_light_mode_controller->OnActiveUserPrefServiceChanged(
       Shell::Get()->session_controller()->GetActivePrefService());
diff --git a/ash/assistant/ui/main_stage/ui_element_container_view_unittest.cc b/ash/assistant/ui/main_stage/ui_element_container_view_unittest.cc
index fc355d7d..cc67adb 100644
--- a/ash/assistant/ui/main_stage/ui_element_container_view_unittest.cc
+++ b/ash/assistant/ui/main_stage/ui_element_container_view_unittest.cc
@@ -7,7 +7,6 @@
 #include "ash/assistant/assistant_interaction_controller_impl.h"
 #include "ash/assistant/test/assistant_ash_test_base.h"
 #include "ash/assistant/ui/assistant_view_ids.h"
-#include "ash/constants/ash_features.h"
 #include "ash/constants/ash_pref_names.h"
 #include "ash/public/cpp/assistant/controller/assistant_interaction_controller.h"
 #include "ash/session/session_controller_impl.h"
@@ -17,7 +16,6 @@
 #include "base/test/scoped_feature_list.h"
 #include "cc/base/math_util.h"
 #include "chromeos/ash/services/libassistant/public/cpp/assistant_interaction_metadata.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/compositor/layer.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/views/background.h"
@@ -34,10 +32,6 @@
 using UiElementContainerViewTest = AssistantAshTestBase;
 
 TEST_F(UiElementContainerViewTest, DarkAndLightTheme) {
-  base::test::ScopedFeatureList scoped_feature_list(
-      chromeos::features::kDarkLightMode);
-  ASSERT_TRUE(chromeos::features::IsDarkLightModeEnabled());
-
   auto* dark_light_mode_controller = DarkLightModeControllerImpl::Get();
   dark_light_mode_controller->OnActiveUserPrefServiceChanged(
       Shell::Get()->session_controller()->GetActivePrefService());
diff --git a/ash/components/arc/arc_util_unittest.cc b/ash/components/arc/arc_util_unittest.cc
index 9dcb1187..9d313f2 100644
--- a/ash/components/arc/arc_util_unittest.cc
+++ b/ash/components/arc/arc_util_unittest.cc
@@ -389,12 +389,11 @@
 }
 
 TEST_F(ArcUtilTest, IsArcAllowedForUser) {
+  TestingPrefServiceSimple local_state;
   user_manager::FakeUserManager* fake_user_manager =
-      new user_manager::FakeUserManager();
+      new user_manager::FakeUserManager(&local_state);
   user_manager::ScopedUserManager scoped_user_manager(
       base::WrapUnique(fake_user_manager));
-  TestingPrefServiceSimple local_state;
-  fake_user_manager->set_local_state(&local_state);
 
   struct {
     user_manager::UserType user_type;
diff --git a/ash/constants/ash_constants.h b/ash/constants/ash_constants.h
index 1255523..42e8c7027 100644
--- a/ash/constants/ash_constants.h
+++ b/ash/constants/ash_constants.h
@@ -67,9 +67,6 @@
 // a new autoclick.
 constexpr int kDefaultAutoclickMovementThreshold = 20;
 
-// Whether long press diacritics is enabled by default.
-constexpr bool kDefaultLongPressDiacriticsEnabled = true;
-
 // Whether keyboard auto repeat is enabled by default.
 constexpr bool kDefaultKeyAutoRepeatEnabled = true;
 
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 78d5d64..eca9334 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -501,6 +501,11 @@
              "DiacriticsOnPhysicalKeyboardLongpress",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Enables diacritics on longpress on the physical keyboard by default.
+BASE_FEATURE(kDiacriticsOnPhysicalKeyboardLongpressDefaultOn,
+             "DiacriticsOnPhysicalKeyboardLongpressDefaultOn",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Disables the CryptAuth v1 DeviceSync flow. Note: During the first phase
 // of the v2 DeviceSync rollout, v1 and v2 DeviceSync run in parallel. This flag
 // is needed to disable the v1 service during the second phase of the rollout.
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index acdf39d..0d64f05 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -159,6 +159,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kDiacriticsOnPhysicalKeyboardLongpress);
 COMPONENT_EXPORT(ASH_CONSTANTS)
+BASE_DECLARE_FEATURE(kDiacriticsOnPhysicalKeyboardLongpressDefaultOn);
+COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kDisableCryptAuthV1DeviceSync);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kDisableIdleSocketsCloseOnMemoryPressure);
diff --git a/ash/frame/non_client_frame_view_ash_unittest.cc b/ash/frame/non_client_frame_view_ash_unittest.cc
index d984175..114f21d 100644
--- a/ash/frame/non_client_frame_view_ash_unittest.cc
+++ b/ash/frame/non_client_frame_view_ash_unittest.cc
@@ -27,7 +27,6 @@
 #include "base/command_line.h"
 #include "base/containers/flat_set.h"
 #include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/ui/base/window_properties.h"
 #include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h"
 #include "chromeos/ui/frame/default_frame_header.h"
@@ -40,7 +39,6 @@
 #include "ui/aura/window_targeter.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/accelerators/test_accelerator_target.h"
-#include "ui/base/ui_base_features.h"
 #include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/test/draw_waiter_for_test.h"
@@ -961,12 +959,9 @@
 // Tests to make sure that the NonClientFrameViewAsh tracks default frame colors
 // for both light and dark mode.
 TEST_P(NonClientFrameViewAshFrameColorTest, DefaultFrameColorsDarkAndLight) {
-  base::test::ScopedFeatureList scoped_feature_list(
-      chromeos::features::kDarkLightMode);
   auto* dark_light_mode_controller = DarkLightModeControllerImpl::Get();
   dark_light_mode_controller->OnActiveUserPrefServiceChanged(
       Shell::Get()->session_controller()->GetActivePrefService());
-  ASSERT_TRUE(chromeos::features::IsDarkLightModeEnabled());
   const bool initial_dark_mode_status =
       dark_light_mode_controller->IsDarkModeEnabled();
 
@@ -1010,12 +1005,9 @@
 // colors when the kTrackDefaultFrameColors property is set to false.
 TEST_P(NonClientFrameViewAshFrameColorTest,
        CanSetPersistentFrameColorsDarkAndLight) {
-  base::test::ScopedFeatureList scoped_feature_list(
-      chromeos::features::kDarkLightMode);
   auto* dark_light_mode_controller = DarkLightModeControllerImpl::Get();
   dark_light_mode_controller->OnActiveUserPrefServiceChanged(
       Shell::Get()->session_controller()->GetActivePrefService());
-  ASSERT_TRUE(chromeos::features::IsDarkLightModeEnabled());
   const bool initial_dark_mode_status =
       dark_light_mode_controller->IsDarkModeEnabled();
 
diff --git a/ash/keyboard/keyboard_controller_impl.cc b/ash/keyboard/keyboard_controller_impl.cc
index 90028252..f78e80f 100644
--- a/ash/keyboard/keyboard_controller_impl.cc
+++ b/ash/keyboard/keyboard_controller_impl.cc
@@ -99,7 +99,8 @@
     PrefRegistrySimple* registry) {
   registry->RegisterBooleanPref(
       ash::prefs::kLongPressDiacriticsEnabled,
-      ash::kDefaultLongPressDiacriticsEnabled,
+      base::FeatureList::IsEnabled(
+          ash::features::kDiacriticsOnPhysicalKeyboardLongpressDefaultOn),
       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
   registry->RegisterBooleanPref(
       ash::prefs::kXkbAutoRepeatEnabled, ash::kDefaultKeyAutoRepeatEnabled,
diff --git a/ash/resources/vector_icons/system_menu_cast.icon b/ash/resources/vector_icons/system_menu_cast.icon
index 0bf96449f..d1058a2 100644
--- a/ash/resources/vector_icons/system_menu_cast.icon
+++ b/ash/resources/vector_icons/system_menu_cast.icon
@@ -2,70 +2,49 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-CANVAS_DIMENSIONS, 40,
-MOVE_TO, 4, 30.06f,
-V_LINE_TO, 34,
-R_H_LINE_TO, 4,
-R_CUBIC_TO, 0, -2.18f, -1.79f, -3.94f, -4, -3.94f,
-CLOSE,
-R_MOVE_TO, 0, -6.3f,
-R_V_LINE_TO, 2.93f,
-R_CUBIC_TO, 4.1f, 0, 7.43f, 3.28f, 7.43f, 7.32f,
-H_LINE_TO, 14.4f,
-R_CUBIC_TO, 0, -5.66f, -4.65f, -10.24f, -10.4f, -10.24f,
-CLOSE,
-R_MOVE_TO, 0, -5.52f,
-R_V_LINE_TO, 2.87f,
-R_CUBIC_TO, 7.23f, 0, 13.09f, 5.77f, 13.09f, 12.89f,
-H_LINE_TO, 20,
-R_CUBIC_TO, 0, -8.71f, -7.17f, -15.76f, -16, -15.76f,
-CLOSE,
-MOVE_TO, 6.91f, 8,
-CUBIC_TO, 5.31f, 8, 4, 9.3f, 4, 10.89f,
-V_LINE_TO, 15,
-R_H_LINE_TO, 3,
-R_V_LINE_TO, -4,
-R_H_LINE_TO, 26,
-R_V_LINE_TO, 20,
-H_LINE_TO, 23,
-R_V_LINE_TO, 3,
-R_H_LINE_TO, 10.09f,
-R_CUBIC_TO, 1.6f, 0, 2.91f, -1.3f, 2.91f, -2.89f,
-V_LINE_TO, 10.89f,
-CUBIC_TO, 36, 9.3f, 34.69f, 8, 33.09f, 8,
-H_LINE_TO, 6.91f,
-CLOSE
-
-CANVAS_DIMENSIONS, 20,
-MOVE_TO, 2, 15.03f,
-V_LINE_TO, 17,
-R_H_LINE_TO, 2,
-R_CUBIC_TO, 0, -1.09f, -0.89f, -1.97f, -2, -1.97f,
-CLOSE,
-R_MOVE_TO, 0, -3.15f,
-R_V_LINE_TO, 1.46f,
-R_CUBIC_TO, 2.05f, 0, 3.71f, 1.64f, 3.71f, 3.66f,
-H_LINE_TO, 7.2f,
-R_CUBIC_TO, 0, -2.83f, -2.33f, -5.12f, -5.2f, -5.12f,
-CLOSE,
-MOVE_TO, 2, 9.12f,
-R_V_LINE_TO, 1.43f,
-R_CUBIC_TO, 3.62f, 0, 6.55f, 2.89f, 6.55f, 6.45f,
-H_LINE_TO, 10,
-R_CUBIC_TO, 0, -4.36f, -3.58f, -7.88f, -8, -7.88f,
-CLOSE,
-MOVE_TO, 3.46f, 4,
-CUBIC_TO, 2.66f, 4, 2, 4.65f, 2, 5.44f,
-V_LINE_TO, 8,
-R_H_LINE_TO, 2,
-V_LINE_TO, 6,
-R_H_LINE_TO, 12,
-R_V_LINE_TO, 9,
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 4, 4,
+R_H_LINE_TO, 16,
+R_CUBIC_TO, 0.55f, 0, 1.02f, 0.2f, 1.4f, 0.6f,
+R_CUBIC_TO, 0.4f, 0.38f, 0.6f, 0.85f, 0.6f, 1.4f,
+R_V_LINE_TO, 12,
+R_CUBIC_TO, 0, 0.55f, -0.2f, 1.02f, -0.6f, 1.43f,
+R_CUBIC_TO, -0.38f, 0.38f, -0.85f, 0.57f, -1.4f, 0.57f,
 R_H_LINE_TO, -5,
+R_V_LINE_TO, -2,
+R_H_LINE_TO, 5,
+V_LINE_TO, 6,
+H_LINE_TO, 4,
+R_V_LINE_TO, 1,
+H_LINE_TO, 2,
+V_LINE_TO, 6,
+R_CUBIC_TO, 0, -0.55f, 0.19f, -1.02f, 0.57f, -1.4f,
+R_CUBIC_TO, 0.4f, -0.4f, 0.88f, -0.6f, 1.43f, -0.6f,
+CLOSE,
+MOVE_TO, 2, 20,
+R_H_LINE_TO, 3,
+R_CUBIC_TO, 0, -0.83f, -0.29f, -1.54f, -0.87f, -2.12f,
+ARC_TO, 2.89f, 2.89f, 0, 0, 0, 2, 17,
+R_V_LINE_TO, 3,
+CLOSE,
+R_MOVE_TO, 5, 0,
+R_H_LINE_TO, 2,
+R_CUBIC_TO, 0, -1.95f, -0.68f, -3.6f, -2.05f, -4.95f,
+CUBIC_TO, 5.6f, 13.68f, 3.95f, 13, 2, 13,
 R_V_LINE_TO, 2,
-R_H_LINE_TO, 5.55f,
-R_CUBIC_TO, 0.8f, 0, 1.46f, -0.65f, 1.46f, -1.44f,
-V_LINE_TO, 5.44f,
-CUBIC_TO, 18, 4.65f, 17.35f, 4, 16.55f, 4,
-H_LINE_TO, 3.46f,
-CLOSE
+R_CUBIC_TO, 1.38f, 0, 2.56f, 0.49f, 3.53f, 1.48f,
+CUBIC_TO, 6.51f, 17.44f, 7, 18.62f, 7, 20,
+CLOSE,
+MOVE_TO, 2, 9,
+R_V_LINE_TO, 2,
+R_CUBIC_TO, 1.25f, 0, 2.42f, 0.24f, 3.5f, 0.73f,
+R_ARC_TO, 8.69f, 8.69f, 0, 0, 1, 2.85f, 1.93f,
+R_CUBIC_TO, 0.82f, 0.8f, 1.46f, 1.75f, 1.93f, 2.85f,
+ARC_TO, 8.49f, 8.49f, 0, 0, 1, 11, 20,
+R_H_LINE_TO, 2,
+R_CUBIC_TO, 0, -1.52f, -0.29f, -2.94f, -0.87f, -4.28f,
+R_ARC_TO, 10.96f, 10.96f, 0, 0, 0, -2.35f, -3.5f,
+R_CUBIC_TO, -1, -1, -2.17f, -1.78f, -3.5f, -2.35f,
+ARC_TO, 10.55f, 10.55f, 0, 0, 0, 2, 9,
+CLOSE,
+NEW_PATH
diff --git a/ash/resources/vector_icons/system_menu_cast_paused.icon b/ash/resources/vector_icons/system_menu_cast_paused.icon
index 6960d247..23e7f04 100644
--- a/ash/resources/vector_icons/system_menu_cast_paused.icon
+++ b/ash/resources/vector_icons/system_menu_cast_paused.icon
@@ -2,69 +2,70 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-CANVAS_DIMENSIONS, 20,
-MOVE_TO, 18, 11.2f,
-CUBIC_TO, 17.54f, 11.47f, 17.03f, 11.67f, 16.5f, 11.81f,
-V_LINE_TO, 14.5f,
-H_LINE_TO, 11.5f,
-V_LINE_TO, 16,
-H_LINE_TO, 16.5f,
-CUBIC_TO, 16.92f, 16, 17.27f, 15.85f, 17.56f, 15.56f,
-CUBIC_TO, 17.85f, 15.26f, 18, 14.9f, 18, 14.5f,
-V_LINE_TO, 11.2f,
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 4, 4,
+R_CUBIC_TO, -0.5f, 0, -1, 0.2f, -1.4f, 0.6f,
+CUBIC_TO, 2.2f, 5, 2, 5.5f, 2, 6,
+R_V_LINE_TO, 1,
+R_H_LINE_TO, 2,
+V_LINE_TO, 6,
+R_H_LINE_TO, 7,
+R_CUBIC_TO, 0.1f, -0.7f, 0.2f, -1.4f, 0.5f, -2,
+H_LINE_TO, 4,
 CLOSE,
-MOVE_TO, 9.34f, 4,
-H_LINE_TO, 3.5f,
-CUBIC_TO, 3.1f, 4, 2.74f, 4.15f, 2.44f, 4.46f,
-CUBIC_TO, 2.15f, 4.75f, 2, 5.1f, 2, 5.5f,
-V_LINE_TO, 6.5f,
-H_LINE_TO, 3.5f,
-V_LINE_TO, 5.5f,
-H_LINE_TO, 9.02f,
-CUBIC_TO, 9.06f, 4.98f, 9.17f, 4.48f, 9.34f, 4,
+MOVE_TO, 20, 18,
+R_H_LINE_TO, -5,
+R_V_LINE_TO, 2,
+R_H_LINE_TO, 5,
+R_CUBIC_TO, 0.5f, 0, 1, -0.2f, 1.4f, -0.6f,
+R_CUBIC_TO, 0.4f, -0.4f, 0.6f, -0.9f, 0.6f, -1.4f,
+R_V_LINE_TO, -5.1f,
+R_CUBIC_TO, -0.6f, 0.4f, -1.3f, 0.7f, -2, 0.8f,
+V_LINE_TO, 18,
 CLOSE,
-MOVE_TO, 4, 16,
-H_LINE_TO, 2,
-V_LINE_TO, 14,
-CUBIC_TO, 2.56f, 14, 3.03f, 14.19f, 3.42f, 14.58f,
-CUBIC_TO, 3.81f, 14.97f, 4, 15.44f, 4, 16,
+MOVE_TO, 2, 17,
+R_V_LINE_TO, 3,
+R_H_LINE_TO, 3,
+R_CUBIC_TO, 0, -0.8f, -0.3f, -1.5f, -0.9f, -2.1f,
+CUBIC_TO_SHORTHAND, 2.8f, 17, 2, 17,
 CLOSE,
-MOVE_TO, 7, 16,
-H_LINE_TO, 5.5f,
-CUBIC_TO, 5.5f, 15.03f, 5.16f, 14.2f, 4.48f, 13.52f,
-CUBIC_TO, 3.8f, 12.84f, 2.97f, 12.5f, 2, 12.5f,
-V_LINE_TO, 11,
-CUBIC_TO, 3.39f, 11, 4.57f, 11.49f, 5.54f, 12.46f,
-CUBIC_TO, 6.51f, 13.43f, 7, 14.61f, 7, 16,
-CLOSE,
-MOVE_TO, 2, 9.5f,
-V_LINE_TO, 8,
-CUBIC_TO, 3.11f, 8, 4.15f, 8.21f, 5.1f, 8.63f,
-CUBIC_TO, 6.08f, 9.04f, 6.92f, 9.62f, 7.65f, 10.35f,
-CUBIC_TO, 8.38f, 11.08f, 8.96f, 11.92f, 9.38f, 12.9f,
-CUBIC_TO, 9.79f, 13.85f, 10, 14.89f, 10, 16,
-H_LINE_TO, 8.5f,
-CUBIC_TO, 8.5f, 15.1f, 8.33f, 14.26f, 7.98f, 13.48f,
-CUBIC_TO, 7.65f, 12.69f, 7.18f, 12, 6.58f, 11.42f,
-CUBIC_TO, 6, 10.82f, 5.31f, 10.35f, 4.52f, 10.02f,
-CUBIC_TO, 3.74f, 9.67f, 2.9f, 9.5f, 2, 9.5f,
+MOVE_TO, 2, 13,
+R_V_LINE_TO, 2,
+R_CUBIC_TO, 1.4f, 0, 2.6f, 0.5f, 3.5f, 1.5f,
+R_CUBIC_TO, 1, 1, 1.5f, 2.1f, 1.5f, 3.5f,
+R_H_LINE_TO, 2,
+R_CUBIC_TO, 0, -2, -0.7f, -3.6f, -2, -5,
+R_CUBIC_TO, -1.4f, -1.3f, -3, -2, -5, -2,
 CLOSE,
 NEW_PATH,
-MOVE_TO, 15, 1.2f,
-CUBIC_TO, 12.35f, 1.2f, 10.2f, 3.35f, 10.2f, 6,
-CUBIC_TO, 10.2f, 8.65f, 12.35f, 10.8f, 15, 10.8f,
-CUBIC_TO, 17.65f, 10.8f, 19.8f, 8.65f, 19.8f, 6,
-CUBIC_TO, 19.8f, 3.35f, 17.65f, 1.2f, 15, 1.2f,
+MOVE_TO, 9.8f, 12.2f,
+R_CUBIC_TO, -1, -1, -2.2f, -1.8f, -3.5f, -2.3f,
+CUBIC_TO, 4.9f, 9.3f, 3.5f, 9, 2, 9,
+R_V_LINE_TO, 2,
+R_CUBIC_TO, 1.2f, 0, 2.4f, 0.2f, 3.5f, 0.7f,
+R_CUBIC_TO, 1.1f, 0.5f, 2, 1.1f, 2.8f, 1.9f,
+R_CUBIC_TO, 0.8f, 0.8f, 1.5f, 1.8f, 1.9f, 2.8f,
+R_CUBIC_TO, 0.5f, 1.1f, 0.7f, 2.2f, 0.7f, 3.5f,
+R_H_LINE_TO, 2,
+R_CUBIC_TO, 0, -1.5f, -0.3f, -2.9f, -0.9f, -4.3f,
+R_CUBIC_TO, -0.4f, -1.2f, -1.2f, -2.4f, -2.2f, -3.4f,
 CLOSE,
-MOVE_TO, 14.4f, 7.8f,
-H_LINE_TO, 13.2f,
-V_LINE_TO, 4.2f,
-H_LINE_TO, 14.4f,
-V_LINE_TO, 7.8f,
+NEW_PATH,
+MOVE_TO, 18.2f, 1.5f,
+R_CUBIC_TO, -3, 0.1f, -5.3f, 2.5f, -5.2f, 5.4f,
+R_CUBIC_TO, 0.1f, 2.8f, 2.4f, 5.1f, 5.2f, 5.1f,
+R_CUBIC_TO, 3, -0.1f, 5.3f, -2.5f, 5.2f, -5.4f,
+R_CUBIC_TO, 0, -2.8f, -2.3f, -5, -5.2f, -5.1f,
 CLOSE,
-MOVE_TO, 16.8f, 7.8f,
-H_LINE_TO, 15.6f,
-V_LINE_TO, 4.2f,
-H_LINE_TO, 16.8f,
-V_LINE_TO, 7.8f,
-CLOSE
\ No newline at end of file
+R_MOVE_TO, -0.6f, 7.2f,
+R_H_LINE_TO, -1.3f,
+V_LINE_TO, 4.8f,
+R_H_LINE_TO, 1.3f,
+R_V_LINE_TO, 3.9f,
+CLOSE,
+R_MOVE_TO, 2.7f, 0,
+H_LINE_TO, 19,
+V_LINE_TO, 4.8f,
+R_H_LINE_TO, 1.3f,
+R_V_LINE_TO, 3.9f,
+CLOSE
diff --git a/ash/style/style_viewer/system_ui_components_grid_view.h b/ash/style/style_viewer/system_ui_components_grid_view.h
index 4443dcc8..e47d982 100644
--- a/ash/style/style_viewer/system_ui_components_grid_view.h
+++ b/ash/style/style_viewer/system_ui_components_grid_view.h
@@ -41,9 +41,9 @@
   // Adds a new instance and returns the raw pointer of the instance.
   template <typename T>
   T* AddInstance(const std::u16string& name, std::unique_ptr<T> instance) {
-    T* raw_ptr = instance.get();
+    T* instance_ptr = instance.get();
     AddInstanceImpl(name, instance.release());
-    return raw_ptr;
+    return instance_ptr;
   }
 
   // views::View:
diff --git a/ash/style/tab_slider.h b/ash/style/tab_slider.h
index 4f3b641..ea16974 100644
--- a/ash/style/tab_slider.h
+++ b/ash/style/tab_slider.h
@@ -49,9 +49,9 @@
   // AddButton(std::make_unique<SliderButtonType>(...)).
   template <typename T>
   T* AddButton(std::unique_ptr<T> button) {
-    T* raw_ptr = button.get();
+    T* button_ptr = button.get();
     AddButtonInternal(button.release());
-    return raw_ptr;
+    return button_ptr;
   }
 
   // Add a button with the button's ctor arguments. For example
diff --git a/ash/system/accessibility/dictation_bubble_controller_unittest.cc b/ash/system/accessibility/dictation_bubble_controller_unittest.cc
index cfe41add..adab763e 100644
--- a/ash/system/accessibility/dictation_bubble_controller_unittest.cc
+++ b/ash/system/accessibility/dictation_bubble_controller_unittest.cc
@@ -13,7 +13,6 @@
 #include "ash/system/accessibility/dictation_bubble_view.h"
 #include "ash/test/ash_test_base.h"
 #include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 
 namespace ash {
 
@@ -157,10 +156,6 @@
 // Verifies that the bubble UI respects the dark mode setting. For convenience
 // purposes, we perform checks on the label's text and background color.
 TEST_F(DictationBubbleControllerTest, DarkMode) {
-  // Enable dark mode feature.
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(chromeos::features::kDarkLightMode);
-  ASSERT_TRUE(chromeos::features::IsDarkLightModeEnabled());
   auto* dark_light_mode_controller = DarkLightModeControllerImpl::Get();
   dark_light_mode_controller->OnActiveUserPrefServiceChanged(
       Shell::Get()->session_controller()->GetPrimaryUserPrefService());
diff --git a/ash/system/video_conference/bubble/return_to_app_panel.cc b/ash/system/video_conference/bubble/return_to_app_panel.cc
index 14b607d..f7436029 100644
--- a/ash/system/video_conference/bubble/return_to_app_panel.cc
+++ b/ash/system/video_conference/bubble/return_to_app_panel.cc
@@ -11,6 +11,8 @@
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/video_conference/bubble/bubble_view_ids.h"
 #include "ash/system/video_conference/video_conference_tray_controller.h"
+#include "base/functional/callback_helpers.h"
+#include "base/memory/weak_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "base/unguessable_token.h"
@@ -18,11 +20,13 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/image_model.h"
 #include "ui/chromeos/styles/cros_tokens_color_mappings.h"
+#include "ui/compositor/layer.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/gfx/animation/linear_animation.h"
 #include "ui/gfx/animation/tween.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/scoped_canvas.h"
+#include "ui/views/animation/animation_builder.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
@@ -41,6 +45,58 @@
 
 constexpr auto kPanelBoundsChangeAnimationDuration = base::Milliseconds(200);
 
+// Performs fade in/fade out animation using `AnimationBuilder`.
+void FadeInView(views::View* view, int delay_in_ms, int duration_in_ms) {
+  // If we are in testing with animation (non zero duration), we shouldn't have
+  // delays so that we can properly track when animation is completed in test.
+  if (ui::ScopedAnimationDurationScaleMode::duration_multiplier() ==
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION) {
+    delay_in_ms = 0;
+  }
+
+  // The view must have a layer to perform animation.
+  CHECK(view->layer());
+
+  views::AnimationBuilder()
+      .SetPreemptionStrategy(
+          ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
+      .Once()
+      .SetDuration(base::TimeDelta())
+      .SetOpacity(view, 0.0f)
+      .At(base::Milliseconds(delay_in_ms))
+      .SetDuration(base::Milliseconds(duration_in_ms))
+      .SetOpacity(view, 1.0f);
+}
+
+void FadeOutView(views::View* view,
+                 base::WeakPtr<ReturnToAppPanel> parent_weak_ptr) {
+  auto on_animation_ended = base::BindOnce(
+      [](base::WeakPtr<ReturnToAppPanel> parent_weak_ptr, views::View* view) {
+        if (parent_weak_ptr) {
+          view->layer()->SetOpacity(1.0f);
+          view->SetVisible(false);
+        }
+      },
+      parent_weak_ptr, view);
+
+  std::pair<base::OnceClosure, base::OnceClosure> split =
+      base::SplitOnceCallback(std::move(on_animation_ended));
+
+  // The view must have a layer to perform animation.
+  CHECK(view->layer());
+
+  view->SetVisible(true);
+  views::AnimationBuilder()
+      .SetPreemptionStrategy(
+          ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
+      .OnEnded(std::move(split.first))
+      .OnAborted(std::move(split.second))
+      .Once()
+      .SetDuration(base::Milliseconds(50))
+      .SetVisibility(view, false)
+      .SetOpacity(view, 0.0f);
+}
+
 // Creates a view containing camera, microphone, and screen share icons that
 // shows capturing state of a media app.
 std::unique_ptr<views::View> CreateReturnToAppIconsContainer(
@@ -199,6 +255,10 @@
     expand_indicator->SetTooltipText(l10n_util::GetStringUTF16(
         IDS_ASH_VIDEO_CONFERENCE_RETURN_TO_APP_SHOW_TOOLTIP));
     expand_indicator_ = AddChildView(std::move(expand_indicator));
+
+    // Add a layer for icons container in the top row to perform animation.
+    icons_container_->SetPaintToLayer();
+    icons_container_->layer()->SetFillsBoundsOpaquely(false);
   }
 
   // TODO(b/253646076): Double check accessible name for this button.
@@ -206,6 +266,12 @@
 
   // When we show the bubble for the first time, only the top row is visible.
   SetVisible(is_top_row);
+
+  if (!is_top_row) {
+    // Add a layer to perform fade in animation.
+    SetPaintToLayer();
+    layer()->SetFillsBoundsOpaquely(false);
+  }
 }
 
 ReturnToAppButton::~ReturnToAppButton() = default;
@@ -244,6 +310,10 @@
       expanded_ ? IDS_ASH_VIDEO_CONFERENCE_RETURN_TO_APP_HIDE_TOOLTIP
                 : IDS_ASH_VIDEO_CONFERENCE_RETURN_TO_APP_SHOW_TOOLTIP;
   expand_indicator_->SetTooltipText(l10n_util::GetStringUTF16(tooltip_text_id));
+
+  if (icons_container_->GetVisible()) {
+    FadeInView(icons_container_, /*delay_in_ms=*/100, /*duration_in_ms=*/100);
+  }
 }
 
 // -----------------------------------------------------------------------------
@@ -356,6 +426,12 @@
       continue;
     }
     child->SetVisible(expanded);
+
+    if (expanded) {
+      FadeInView(child, /*delay_in_ms=*/50, /*duration_in_ms=*/150);
+    } else {
+      FadeOutView(child, weak_ptr_factory_.GetWeakPtr());
+    }
   }
 
   // In tests, widget might be null and the animation, in some cases, might be
diff --git a/ash/system/video_conference/bubble/return_to_app_panel_unittest.cc b/ash/system/video_conference/bubble/return_to_app_panel_unittest.cc
index 6cbafff..8cf377e5 100644
--- a/ash/system/video_conference/bubble/return_to_app_panel_unittest.cc
+++ b/ash/system/video_conference/bubble/return_to_app_panel_unittest.cc
@@ -21,6 +21,7 @@
 #include "chromeos/crosapi/mojom/video_conference.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/compositor/test/layer_animation_stopped_waiter.h"
 #include "ui/gfx/animation/linear_animation.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
@@ -443,6 +444,18 @@
   LeftClickOn(summary_row);
   EXPECT_TRUE(GetBoundsChangeAnimation()->is_animating());
 
+  // Normally, a layer animation will be performed to fade out the return to app
+  // buttons. However, since we are simulating different stage of the bounds
+  // change animation, we will set visibility right away here to prevent the
+  // layer animation from interfering with the bounds change animation
+  // simulation.
+  auto* first_app_row =
+      static_cast<ReturnToAppButton*>(return_to_app_container->children()[1]);
+  auto* second_app_row =
+      static_cast<ReturnToAppButton*>(return_to_app_container->children()[2]);
+  first_app_row->SetVisible(false);
+  second_app_row->SetVisible(false);
+
   AnimateToValue(0.5);
 
   auto panel_mid_animation_height = return_to_app_panel->size().height();
@@ -465,4 +478,69 @@
             bubble_end_animation_height - bubble_mid_animation_height);
 }
 
+// Verify that the layer animations to show/hide the view are performed with
+// the expected visibility and opacity before and after the animation.
+TEST_F(ReturnToAppPanelTest, LayerAnimations) {
+  ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+
+  controller()->ClearMediaApps();
+  controller()->AddMediaApp(CreateFakeMediaApp(
+      /*is_capturing_camera=*/true, /*is_capturing_microphone=*/false,
+      /*is_capturing_screen=*/false, /*title=*/u"Meet",
+      /*url=*/kMeetTestUrl));
+  controller()->AddMediaApp(CreateFakeMediaApp(
+      /*is_capturing_camera=*/false, /*is_capturing_microphone=*/true,
+      /*is_capturing_screen=*/true, /*title=*/u"Zoom",
+      /*url=*/""));
+
+  LeftClickOn(toggle_bubble_button());
+
+  auto* return_to_app_panel = GetReturnToAppPanel();
+  auto* return_to_app_container = GetReturnToAppContainer(return_to_app_panel);
+  auto* summary_row = static_cast<ReturnToAppButton*>(
+      return_to_app_container->children().front());
+
+  // Expand animation: The return to app buttons should fade in.
+  LeftClickOn(summary_row);
+
+  auto* first_app_row =
+      static_cast<ReturnToAppButton*>(return_to_app_container->children()[1]);
+  auto* second_app_row =
+      static_cast<ReturnToAppButton*>(return_to_app_container->children()[2]);
+
+  EXPECT_EQ(0, first_app_row->layer()->opacity());
+  EXPECT_EQ(0, second_app_row->layer()->opacity());
+
+  ui::LayerAnimationStoppedWaiter layer_animation_waiter;
+  layer_animation_waiter.Wait(first_app_row->layer());
+  layer_animation_waiter.Wait(second_app_row->layer());
+
+  EXPECT_EQ(1, first_app_row->layer()->opacity());
+  EXPECT_EQ(1, second_app_row->layer()->opacity());
+
+  // End the rest of the animation to test collapse animation.
+  SimulateAnimationEnded();
+  ASSERT_TRUE(summary_row->expanded());
+
+  // Collapse animation: The return to app buttons should fade out and the
+  // summary icons should fade in.
+  LeftClickOn(summary_row);
+  EXPECT_TRUE(GetBoundsChangeAnimation()->is_animating());
+
+  auto* summary_icons = summary_row->icons_container();
+  EXPECT_EQ(0, summary_icons->layer()->opacity());
+
+  EXPECT_TRUE(first_app_row->GetVisible());
+  EXPECT_TRUE(second_app_row->GetVisible());
+
+  layer_animation_waiter.Wait(summary_icons->layer());
+  layer_animation_waiter.Wait(first_app_row->layer());
+  layer_animation_waiter.Wait(second_app_row->layer());
+
+  EXPECT_EQ(1, summary_icons->layer()->opacity());
+  EXPECT_FALSE(first_app_row->GetVisible());
+  EXPECT_FALSE(second_app_row->GetVisible());
+}
+
 }  // namespace ash::video_conference
\ No newline at end of file
diff --git a/ash/webui/camera_app_ui/camera_app_helper.mojom b/ash/webui/camera_app_ui/camera_app_helper.mojom
index fe58ff0..5515907 100644
--- a/ash/webui/camera_app_ui/camera_app_helper.mojom
+++ b/ash/webui/camera_app_ui/camera_app_helper.mojom
@@ -132,6 +132,14 @@
   Focus() => ();
 };
 
+enum ToteMetricFormat {
+  PHOTO = 0,
+  SCAN_JPG = 1,
+  SCAN_PDF = 2,
+  VIDEO_GIF = 3,
+  VIDEO_MP4 = 4,
+};
+
 enum DocumentOutputFormat {
   JPEG = 0,
   PDF = 1,
@@ -206,6 +214,9 @@
   // will be used to generate the URI for the broadcast.
   SendNewCaptureBroadcast(bool is_video, string name);
 
+  // Notifies Tote client when a photo/pdf/video/gif is captured.
+  NotifyTote(ToteMetricFormat format, string name);
+
   // Monitors the deletion for given file |name| in the camera folder. The
   // function will return when the deletion happens, or when another monitor
   // request is raised, or when the error occurs. We can determine the cases
diff --git a/ash/webui/camera_app_ui/camera_app_helper_impl.cc b/ash/webui/camera_app_ui/camera_app_helper_impl.cc
index 591281fc..ae32c2f 100644
--- a/ash/webui/camera_app_ui/camera_app_helper_impl.cc
+++ b/ash/webui/camera_app_ui/camera_app_helper_impl.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/public/cpp/holding_space/holding_space_client.h"
 #include "ash/public/cpp/new_window_delegate.h"
 #include "ash/public/cpp/tablet_mode.h"
 #include "ash/public/cpp/window_properties.h"
@@ -22,6 +23,7 @@
 namespace {
 
 using camera_app::mojom::DocumentOutputFormat;
+using camera_app::mojom::ToteMetricFormat;
 using chromeos::machine_learning::mojom::Rotation;
 
 camera_app::mojom::ScreenState ToMojoScreenState(ScreenBacklightState s) {
@@ -108,14 +110,16 @@
     CameraAppUI* camera_app_ui,
     CameraResultCallback camera_result_callback,
     SendBroadcastCallback send_broadcast_callback,
-    aura::Window* window)
+    aura::Window* window,
+    HoldingSpaceClient* holding_space_client)
     : camera_app_ui_(camera_app_ui),
       camera_result_callback_(std::move(camera_result_callback)),
       send_broadcast_callback_(std::move(send_broadcast_callback)),
       has_external_screen_(HasExternalScreen()),
       pending_intent_id_(absl::nullopt),
       window_(window),
-      document_scanner_service_(DocumentScannerServiceClient::Create()) {
+      document_scanner_service_(DocumentScannerServiceClient::Create()),
+      holding_space_client_(holding_space_client) {
   DCHECK(camera_app_ui);
   DCHECK(window);
   window->SetProperty(kCanConsumeSystemKeysKey, true);
@@ -295,6 +299,37 @@
   send_broadcast_callback_.Run(is_video, file_path);
 }
 
+void CameraAppHelperImpl::NotifyTote(const ToteMetricFormat format,
+                                     const std::string& name) {
+  CHECK(holding_space_client_);
+  base::FilePath file_path =
+      camera_app_ui_->delegate()->GetFilePathByName(name);
+  switch (format) {
+    case ToteMetricFormat::PHOTO:
+      holding_space_client_->AddItemOfType(
+          HoldingSpaceItem::Type::kCameraAppPhoto, file_path);
+      return;
+    case ToteMetricFormat::SCAN_JPG:
+      holding_space_client_->AddItemOfType(
+          HoldingSpaceItem::Type::kCameraAppScanJpg, file_path);
+      return;
+    case ToteMetricFormat::SCAN_PDF:
+      holding_space_client_->AddItemOfType(
+          HoldingSpaceItem::Type::kCameraAppScanPdf, file_path);
+      return;
+    case ToteMetricFormat::VIDEO_GIF:
+      holding_space_client_->AddItemOfType(
+          HoldingSpaceItem::Type::kCameraAppVideoGif, file_path);
+      return;
+    case ToteMetricFormat::VIDEO_MP4:
+      holding_space_client_->AddItemOfType(
+          HoldingSpaceItem::Type::kCameraAppVideoMp4, file_path);
+      return;
+    default:
+      NOTREACHED() << "Unexpected new metric format.";
+  }
+}
+
 void CameraAppHelperImpl::MonitorFileDeletion(
     const std::string& name,
     MonitorFileDeletionCallback callback) {
diff --git a/ash/webui/camera_app_ui/camera_app_helper_impl.h b/ash/webui/camera_app_ui/camera_app_helper_impl.h
index c54898b..9bb44087 100644
--- a/ash/webui/camera_app_ui/camera_app_helper_impl.h
+++ b/ash/webui/camera_app_ui/camera_app_helper_impl.h
@@ -46,7 +46,8 @@
   CameraAppHelperImpl(CameraAppUI* camera_app_ui,
                       CameraResultCallback camera_result_callback,
                       SendBroadcastCallback send_broadcast_callback,
-                      aura::Window* window);
+                      aura::Window* window,
+                      HoldingSpaceClient* holding_space_client);
 
   CameraAppHelperImpl(const CameraAppHelperImpl&) = delete;
   CameraAppHelperImpl& operator=(const CameraAppHelperImpl&) = delete;
@@ -80,6 +81,8 @@
   void GetWindowStateController(
       GetWindowStateControllerCallback callback) override;
   void SendNewCaptureBroadcast(bool is_video, const std::string& name) override;
+  void NotifyTote(const camera_app::mojom::ToteMetricFormat format,
+                  const std::string& name) override;
   void MonitorFileDeletion(const std::string& name,
                            MonitorFileDeletionCallback callback) override;
   void GetDocumentScannerReadyState(
@@ -159,6 +162,8 @@
   // Client to connect to document detection service.
   std::unique_ptr<DocumentScannerServiceClient> document_scanner_service_;
 
+  base::raw_ptr<HoldingSpaceClient> const holding_space_client_;
+
   base::WeakPtrFactory<CameraAppHelperImpl> weak_factory_{this};
 };
 
diff --git a/ash/webui/camera_app_ui/camera_app_ui.cc b/ash/webui/camera_app_ui/camera_app_ui.cc
index a81a31c..b8772106 100644
--- a/ash/webui/camera_app_ui/camera_app_ui.cc
+++ b/ash/webui/camera_app_ui/camera_app_ui.cc
@@ -31,6 +31,7 @@
 #include "services/network/public/mojom/content_security_policy.mojom.h"
 #include "services/video_capture/public/mojom/video_capture_service.mojom.h"
 #include "ui/aura/window.h"
+#include "ui/webui/color_change_listener/color_change_handler.h"
 #include "ui/webui/webui_allowlist.h"
 
 namespace ash {
@@ -178,7 +179,8 @@
 std::unique_ptr<CameraAppHelperImpl> CreateCameraAppHelper(
     CameraAppUI* camera_app_ui,
     content::BrowserContext* browser_context,
-    aura::Window* window) {
+    aura::Window* window,
+    HoldingSpaceClient* holding_space_client) {
   DCHECK_NE(window, nullptr);
   auto handle_result_callback =
       base::BindRepeating(&HandleCameraResult, browser_context);
@@ -187,7 +189,7 @@
 
   return std::make_unique<CameraAppHelperImpl>(
       camera_app_ui, std::move(handle_result_callback),
-      std::move(send_broadcast_callback), window);
+      std::move(send_broadcast_callback), window, holding_space_client);
 }
 
 }  // namespace
@@ -271,10 +273,21 @@
 void CameraAppUI::BindInterface(
     mojo::PendingReceiver<camera_app::mojom::CameraAppHelper> receiver) {
   helper_ = CreateCameraAppHelper(
-      this, web_ui()->GetWebContents()->GetBrowserContext(), window());
+      this, web_ui()->GetWebContents()->GetBrowserContext(), window(),
+      delegate_->GetHoldingSpaceClient());
   helper_->Bind(std::move(receiver));
 }
 
+void CameraAppUI::BindInterface(
+    mojo::PendingReceiver<color_change_listener::mojom::PageHandler> receiver) {
+  views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window());
+  // Camera app is always dark.
+  widget->SetColorModeOverride(ui::ColorProviderManager::ColorMode::kDark);
+
+  color_provider_handler_ = std::make_unique<ui::ColorChangeHandler>(
+      web_ui()->GetWebContents(), std::move(receiver));
+}
+
 aura::Window* CameraAppUI::window() {
   return web_ui()->GetWebContents()->GetTopLevelNativeWindow();
 }
diff --git a/ash/webui/camera_app_ui/camera_app_ui.h b/ash/webui/camera_app_ui/camera_app_ui.h
index 0f2365d..85a2031 100644
--- a/ash/webui/camera_app_ui/camera_app_ui.h
+++ b/ash/webui/camera_app_ui/camera_app_ui.h
@@ -15,11 +15,16 @@
 #include "media/capture/video/chromeos/mojom/camera_app.mojom.h"
 #include "ui/aura/window.h"
 #include "ui/webui/mojo_web_ui_controller.h"
+#include "ui/webui/resources/cr_components/color_change_listener/color_change_listener.mojom.h"
 
 namespace media {
 class CameraAppDeviceProviderImpl;
 }  // namespace media
 
+namespace ui {
+class ColorChangeHandler;
+}  // namespace ui
+
 namespace ash {
 
 class CameraAppHelperImpl;
@@ -55,6 +60,12 @@
   void BindInterface(
       mojo::PendingReceiver<camera_app::mojom::CameraAppHelper> receiver);
 
+  // Instantiates implementor of the mojom::PageHandler mojo interface passing
+  // the pending receiver that will be internally bound.
+  void BindInterface(
+      mojo::PendingReceiver<color_change_listener::mojom::PageHandler>
+          receiver);
+
   CameraAppUIDelegate* delegate() { return delegate_.get(); }
 
   aura::Window* window();
@@ -79,6 +90,8 @@
 
   std::unique_ptr<CameraAppHelperImpl> helper_;
 
+  std::unique_ptr<ui::ColorChangeHandler> color_provider_handler_;
+
   WEB_UI_CONTROLLER_TYPE_DECL();
 };
 
diff --git a/ash/webui/camera_app_ui/camera_app_ui_delegate.h b/ash/webui/camera_app_ui/camera_app_ui_delegate.h
index c3f40e2..29e9b06 100644
--- a/ash/webui/camera_app_ui/camera_app_ui_delegate.h
+++ b/ash/webui/camera_app_ui/camera_app_ui_delegate.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/files/file_path.h"
 #include "base/functional/callback.h"
 
 namespace content {
@@ -15,6 +16,7 @@
 }  // namespace content
 
 namespace ash {
+class HoldingSpaceClient;
 
 // A delegate which exposes browser functionality from //chrome to the camera
 // app ui page handler.
@@ -51,6 +53,8 @@
 
   virtual ~CameraAppUIDelegate() = default;
 
+  virtual HoldingSpaceClient* GetHoldingSpaceClient() = 0;
+
   // Sets Downloads folder as launch directory by File Handling API so that we
   // can get the handle on the app side.
   virtual void SetLaunchDirectory() = 0;
@@ -95,6 +99,9 @@
 
   // Open "Storage management" page in system's Settings app.
   virtual void OpenStorageManagement() = 0;
+
+  // Gets the file path by given file |name|.
+  virtual base::FilePath GetFilePathByName(const std::string& name) = 0;
 };
 
 }  // namespace ash
diff --git a/ash/webui/camera_app_ui/resources/BUILD.gn b/ash/webui/camera_app_ui/resources/BUILD.gn
index 241358a4..d1c7156 100644
--- a/ash/webui/camera_app_ui/resources/BUILD.gn
+++ b/ash/webui/camera_app_ui/resources/BUILD.gn
@@ -69,6 +69,7 @@
   deps = [
     "//third_party/material_web_components:bundle_lit_ts",
     "//third_party/material_web_components:library",
+    "//ui/webui/resources/cr_components/color_change_listener:build_ts",
     "//ui/webui/resources/mojo:build_ts",
   ]
 
diff --git a/ash/webui/camera_app_ui/resources/css/colors_default.css b/ash/webui/camera_app_ui/resources/css/colors_default.css
new file mode 100644
index 0000000..0fcbd19
--- /dev/null
+++ b/ash/webui/camera_app_ui/resources/css/colors_default.css
@@ -0,0 +1,32 @@
+/* Copyright 2023 The Chromium Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+/* This file will override dynamic color tokens for a color scheme that is same
+ * as the theme before dynamic color.
+ * TODO(pihsun): Remove this file and all references once dynamic color is
+ * enabled by default.
+ */
+:root {
+  --cros-sys-app_base: var(--grey-900);
+  --cros-sys-app_base_elevated: var(--grey-200);
+  --cros-sys-focus_ring: var(--blue-300);
+  --cros-sys-inverse_on_surface: black;
+  --cros-sys-on_surface: var(--grey-200);
+}
+
+.mode-item > input:checked + span {
+  background: white;
+  box-shadow: 0 2px 3px rgba(var(--grey-900-rgb), 0.3);
+}
+
+.mode-subgroup {
+  backdrop-filter: blur(30px);
+  background: rgba(255, 255, 255, 0.06);
+}
+
+.mode-subgroup > .item input:checked + div.label {
+  background: var(--grey-200);
+  box-shadow: 0 2px 3px rgba(var(--grey-900-rgb), 0.3);
+  color: var(--grey-900);
+}
diff --git a/ash/webui/camera_app_ui/resources/css/css.gni b/ash/webui/camera_app_ui/resources/css/css.gni
index 76cbcfe1..e173fa1 100644
--- a/ash/webui/camera_app_ui/resources/css/css.gni
+++ b/ash/webui/camera_app_ui/resources/css/css.gni
@@ -4,6 +4,7 @@
 
 css_files = [
   "button.css",
+  "colors_default.css",
   "custom_toast.css",
   "flash.css",
   "inkdrop.css",
diff --git a/ash/webui/camera_app_ui/resources/css/main.css b/ash/webui/camera_app_ui/resources/css/main.css
index 76183fb..d73ed9a 100644
--- a/ash/webui/camera_app_ui/resources/css/main.css
+++ b/ash/webui/camera_app_ui/resources/css/main.css
@@ -49,7 +49,7 @@
 }
 
 body {
-  background: var(--grey-900);
+  background: var(--cros-sys-app_base);
   bottom: 0;
   font-family: var(--default-font-family);
   height: 100%;
@@ -328,10 +328,8 @@
 }
 
 .mode-item>input:checked + span {
-  background: white;
-  box-shadow: 0 2px 3px rgba(32, 33, 36, 0.3);
-  color: black;
-  text-shadow: none;
+  background: var(--cros-sys-primary);
+  color: var(--cros-sys-inverse_on_surface);
 }
 
 button.shutter {
@@ -543,7 +541,6 @@
 }
 
 #switch-device {
-  background-image: url(/images/camera_button_switch_device.svg);
   height: var(--big-icon);
   outline-offset: 8px;
   width: var(--big-icon);
@@ -1484,7 +1481,7 @@
 }
 
 [tabindex='0']:focus-visible {
-  outline: 2px solid var(--blue-300);
+  outline: 2px solid var(--cros-sys-focus_ring);
 }
 
 .circle :is(button, input) {
@@ -1556,6 +1553,7 @@
   width: 20px;
 }
 
-#open-settings {
-  --color: white;
+#open-settings,
+#switch-device {
+  color: var(--cros-sys-on_surface);
 }
diff --git a/ash/webui/camera_app_ui/resources/css/mode/mode.css b/ash/webui/camera_app_ui/resources/css/mode/mode.css
index cc6e2d4b..f88710b 100644
--- a/ash/webui/camera_app_ui/resources/css/mode/mode.css
+++ b/ash/webui/camera_app_ui/resources/css/mode/mode.css
@@ -3,11 +3,10 @@
  * found in the LICENSE file. */
 
 .mode-subgroup {
-  backdrop-filter: blur(30px);
-  background-color: rgba(255, 255, 255, 0.06);
+  background: var(--cros-sys-app_base_elevated);
   border-radius: var(--border-radius-rounded-with-short-side);
   bottom: calc(var(--bottom-line) * 2 + 8px);
-  color: white;
+  color: var(--cros-sys-on_surface);
   display: flex;
   left: 50%;
   position: absolute;
@@ -40,7 +39,6 @@
 }
 
 .mode-subgroup > .item input:checked + div.label {
-  background: var(--grey-200);
-  box-shadow: 0 2px 3px rgba(var(--grey-900-rgb), 0.3);
-  color: var(--grey-900);
+  background: var(--cros-sys-primary);
+  color: var(--cros-sys-inverse_on_surface);
 }
diff --git a/ash/webui/camera_app_ui/resources/images/camera_button_settings.svg b/ash/webui/camera_app_ui/resources/images/camera_button_settings.svg
index 23fcc25..d9c6c18 100644
--- a/ash/webui/camera_app_ui/resources/images/camera_button_settings.svg
+++ b/ash/webui/camera_app_ui/resources/images/camera_button_settings.svg
@@ -1,3 +1,3 @@
 <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path fill-rule="evenodd" clip-rule="evenodd" d="M11.4781 18H8.51899C7.92717 18 7.43132 17.5783 7.35934 17.0083L7.14341 15.5325C6.92747 15.4231 6.71954 15.306 6.5116 15.1733L5.07204 15.7355C4.51221 15.9385 3.89639 15.7121 3.62448 15.2279L2.16092 12.7526C1.881 12.2372 2.00097 11.6281 2.44883 11.2845L3.67246 10.3553C3.66446 10.2382 3.65647 10.121 3.65647 9.9961C3.65647 9.87897 3.66446 9.75403 3.67246 9.6369L2.45683 8.70766C1.98497 8.35627 1.86501 7.72377 2.16092 7.23963L3.64047 4.74866C3.91239 4.26452 4.5282 4.04588 5.07204 4.25671L6.5196 4.82674C6.72753 4.694 6.93547 4.57687 7.14341 4.46755L7.35934 2.97609C7.43132 2.42948 7.92717 2 8.51099 2H11.4701C12.0619 2 12.5578 2.42167 12.6297 2.9917L12.8457 4.46755C13.0616 4.57687 13.2695 4.694 13.4775 4.82674L14.917 4.26452C15.4849 4.06149 16.1007 4.28795 16.3726 4.77208L17.8442 7.25525C18.1321 7.77062 18.0041 8.3797 17.5562 8.72328L16.3406 9.65251C16.3486 9.76964 16.3566 9.88677 16.3566 10.0117C16.3566 10.1367 16.3486 10.2538 16.3406 10.3709L17.5562 11.3001C18.0041 11.6515 18.1321 12.2606 17.8522 12.7526L16.3646 15.267C16.0927 15.7511 15.4769 15.9697 14.925 15.7589L13.4855 15.1967C13.2775 15.3294 13.0696 15.4466 12.8617 15.5559L12.6457 17.0473C12.5658 17.5783 12.0699 18 11.4781 18ZM8.94703 16H11.0606L11.344 14.1455L11.7498 13.9855C12.0868 13.8545 12.4237 13.6655 12.776 13.4182L13.1206 13.1709L14.9432 13.8691L16 12.1236L14.4454 10.9745L14.499 10.5673C14.522 10.3782 14.545 10.1964 14.545 10C14.545 9.80364 14.522 9.61455 14.499 9.43273L14.4454 9.02545L16 7.87636L14.9355 6.13091L13.1053 6.82909L12.7607 6.57455C12.4391 6.34182 12.0944 6.15273 11.7422 6.01455L11.344 5.85455L11.0606 4H8.94703L8.66369 5.85455L8.25782 6.00727C7.92087 6.14545 7.58392 6.32727 7.23165 6.58182L6.88705 6.82182L5.06445 6.13091L4 7.86909L5.55456 9.01818L5.50096 9.42545C5.47798 9.61455 5.45501 9.81091 5.45501 10C5.45501 10.1891 5.47033 10.3855 5.50096 10.5673L5.55456 10.9745L4 12.1236L5.0568 13.8691L6.88705 13.1709L7.23165 13.4255C7.56094 13.6655 7.89024 13.8473 8.25016 13.9855L8.65603 14.1455L8.94703 16ZM10 12.5C11.3807 12.5 12.5 11.3807 12.5 10C12.5 8.61929 11.3807 7.5 10 7.5C8.61929 7.5 7.5 8.61929 7.5 10C7.5 11.3807 8.61929 12.5 10 12.5Z" fill="var(--color)"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M11.4781 18H8.51899C7.92717 18 7.43132 17.5783 7.35934 17.0083L7.14341 15.5325C6.92747 15.4231 6.71954 15.306 6.5116 15.1733L5.07204 15.7355C4.51221 15.9385 3.89639 15.7121 3.62448 15.2279L2.16092 12.7526C1.881 12.2372 2.00097 11.6281 2.44883 11.2845L3.67246 10.3553C3.66446 10.2382 3.65647 10.121 3.65647 9.9961C3.65647 9.87897 3.66446 9.75403 3.67246 9.6369L2.45683 8.70766C1.98497 8.35627 1.86501 7.72377 2.16092 7.23963L3.64047 4.74866C3.91239 4.26452 4.5282 4.04588 5.07204 4.25671L6.5196 4.82674C6.72753 4.694 6.93547 4.57687 7.14341 4.46755L7.35934 2.97609C7.43132 2.42948 7.92717 2 8.51099 2H11.4701C12.0619 2 12.5578 2.42167 12.6297 2.9917L12.8457 4.46755C13.0616 4.57687 13.2695 4.694 13.4775 4.82674L14.917 4.26452C15.4849 4.06149 16.1007 4.28795 16.3726 4.77208L17.8442 7.25525C18.1321 7.77062 18.0041 8.3797 17.5562 8.72328L16.3406 9.65251C16.3486 9.76964 16.3566 9.88677 16.3566 10.0117C16.3566 10.1367 16.3486 10.2538 16.3406 10.3709L17.5562 11.3001C18.0041 11.6515 18.1321 12.2606 17.8522 12.7526L16.3646 15.267C16.0927 15.7511 15.4769 15.9697 14.925 15.7589L13.4855 15.1967C13.2775 15.3294 13.0696 15.4466 12.8617 15.5559L12.6457 17.0473C12.5658 17.5783 12.0699 18 11.4781 18ZM8.94703 16H11.0606L11.344 14.1455L11.7498 13.9855C12.0868 13.8545 12.4237 13.6655 12.776 13.4182L13.1206 13.1709L14.9432 13.8691L16 12.1236L14.4454 10.9745L14.499 10.5673C14.522 10.3782 14.545 10.1964 14.545 10C14.545 9.80364 14.522 9.61455 14.499 9.43273L14.4454 9.02545L16 7.87636L14.9355 6.13091L13.1053 6.82909L12.7607 6.57455C12.4391 6.34182 12.0944 6.15273 11.7422 6.01455L11.344 5.85455L11.0606 4H8.94703L8.66369 5.85455L8.25782 6.00727C7.92087 6.14545 7.58392 6.32727 7.23165 6.58182L6.88705 6.82182L5.06445 6.13091L4 7.86909L5.55456 9.01818L5.50096 9.42545C5.47798 9.61455 5.45501 9.81091 5.45501 10C5.45501 10.1891 5.47033 10.3855 5.50096 10.5673L5.55456 10.9745L4 12.1236L5.0568 13.8691L6.88705 13.1709L7.23165 13.4255C7.56094 13.6655 7.89024 13.8473 8.25016 13.9855L8.65603 14.1455L8.94703 16ZM10 12.5C11.3807 12.5 12.5 11.3807 12.5 10C12.5 8.61929 11.3807 7.5 10 7.5C8.61929 7.5 7.5 8.61929 7.5 10C7.5 11.3807 8.61929 12.5 10 12.5Z"/>
 </svg>
diff --git a/ash/webui/camera_app_ui/resources/images/camera_button_switch_device.svg b/ash/webui/camera_app_ui/resources/images/camera_button_switch_device.svg
index 3b4bef1..6ace9e3 100644
--- a/ash/webui/camera_app_ui/resources/images/camera_button_switch_device.svg
+++ b/ash/webui/camera_app_ui/resources/images/camera_button_switch_device.svg
@@ -1,19 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <!-- Generator: Sketch 51.1 (57501) - http://www.bohemiancoding.com/sketch -->
-    <title>btn_switch_1x</title>
-    <desc>Created with Sketch.</desc>
-    <defs></defs>
-    <g id="btn_switch_1x" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g id="component/switchcamera" fill="#FEFEFE">
-            <g id="Group" transform="translate(4.000000, 4.000000)">
-                <circle id="Oval-2" cx="20" cy="20" r="6"></circle>
-                <g id="Group-2">
-                    <path d="M36.0014647,32 C32.3526394,36.8577868 26.5432713,40 20,40 C8.954305,40 0,31.045695 0,20 L3,20 C3,29.3888407 10.6111593,37 20,37 C24.704999,37 28.9635724,35.0886249 32.0415948,32 L36.0014647,32 Z M40,20 L37,20 C37,10.6111593 29.3888407,3 20,3 C15.295001,3 11.0364276,4.91137512 7.9584052,8 L3.99853525,8 C7.64736057,3.14221319 13.4567287,0 20,0 C31.045695,0 40,8.954305 40,20 Z" id="Combined-Shape"></path>
-                </g>
-                <polygon id="Rectangle-2" points="3 2 13 12 3 12"></polygon>
-                <polygon id="Rectangle-2" transform="translate(32.000000, 33.000000) rotate(180.000000) translate(-32.000000, -33.000000) " points="27 28 37 38 27 38"></polygon>
-            </g>
-        </g>
+    <g transform="translate(4.000000, 4.000000)">
+        <circle cx="20" cy="20" r="6"></circle>
+        <path d="M36.0014647,32 C32.3526394,36.8577868 26.5432713,40 20,40 C8.954305,40 0,31.045695 0,20 L3,20 C3,29.3888407 10.6111593,37 20,37 C24.704999,37 28.9635724,35.0886249 32.0415948,32 L36.0014647,32 Z M40,20 L37,20 C37,10.6111593 29.3888407,3 20,3 C15.295001,3 11.0364276,4.91137512 7.9584052,8 L3.99853525,8 C7.64736057,3.14221319 13.4567287,0 20,0 C31.045695,0 40,8.954305 40,20 Z"></path>
+        <polygon points="3 2 13 12 3 12"></polygon>
+        <polygon transform="translate(32.000000, 33.000000) rotate(180.000000) translate(-32.000000, -33.000000) " points="27 28 37 38 27 38"></polygon>
     </g>
-</svg>
\ No newline at end of file
+</svg>
diff --git a/ash/webui/camera_app_ui/resources/js/flag.ts b/ash/webui/camera_app_ui/resources/js/flag.ts
index d9df6b3..595a3c9 100644
--- a/ash/webui/camera_app_ui/resources/js/flag.ts
+++ b/ash/webui/camera_app_ui/resources/js/flag.ts
@@ -6,5 +6,6 @@
  * Name of the chrome flags.
  */
 export enum Flag {
+  JELLY = 'jelly',
   TIME_LAPSE = 'timeLapse',
 }
diff --git a/ash/webui/camera_app_ui/resources/js/gallerybutton.ts b/ash/webui/camera_app_ui/resources/js/gallerybutton.ts
index ce2e441a..0628c14 100644
--- a/ash/webui/camera_app_ui/resources/js/gallerybutton.ts
+++ b/ash/webui/camera_app_ui/resources/js/gallerybutton.ts
@@ -15,6 +15,7 @@
 import {ResultSaver} from './models/result_saver.js';
 import {TimeLapseSaver, VideoSaver} from './models/video_saver.js';
 import {ChromeHelper} from './mojo/chrome_helper.js';
+import {ToteMetricFormat} from './mojo/type.js';
 import {extractImageFromBlob} from './thumbnailer.js';
 import {
   ErrorLevel,
@@ -224,8 +225,9 @@
     return cameraFolderStable.wait();
   }
 
-  async savePhoto(blob: Blob, name: string, metadata: Metadata|null):
-      Promise<void> {
+  async savePhoto(
+      blob: Blob, format: ToteMetricFormat, name: string,
+      metadata: Metadata|null): Promise<void> {
     const file = await filesystem.saveBlob(blob, name);
     if (metadata !== null) {
       const metadataBlob =
@@ -235,11 +237,13 @@
 
     ChromeHelper.getInstance().sendNewCaptureBroadcast(
         {isVideo: false, name: file.name});
+    ChromeHelper.getInstance().notifyTote(format, name);
     await this.updateCover(file);
   }
 
   async saveGif(blob: Blob, name: string): Promise<void> {
     const file = await filesystem.saveBlob(blob, name);
+    ChromeHelper.getInstance().notifyTote(ToteMetricFormat.VIDEO_GIF, name);
     await this.updateCover(file);
   }
 
@@ -256,6 +260,8 @@
     await file.moveTo(this.directory, videoName);
     ChromeHelper.getInstance().sendNewCaptureBroadcast(
         {isVideo: true, name: file.name});
+    ChromeHelper.getInstance().notifyTote(
+        ToteMetricFormat.VIDEO_MP4, file.name);
     await this.updateCover(file);
   }
 }
diff --git a/ash/webui/camera_app_ui/resources/js/lit/svg_wrapper.ts b/ash/webui/camera_app_ui/resources/js/lit/svg_wrapper.ts
index 62c2a89..a3ef888 100644
--- a/ash/webui/camera_app_ui/resources/js/lit/svg_wrapper.ts
+++ b/ash/webui/camera_app_ui/resources/js/lit/svg_wrapper.ts
@@ -20,6 +20,9 @@
     :host {
       display: block;
     }
+    svg {
+      fill: currentColor;
+    }
   `;
 
   static override properties = {
diff --git a/ash/webui/camera_app_ui/resources/js/main.ts b/ash/webui/camera_app_ui/resources/js/main.ts
index a2c6487..aa4e0040 100644
--- a/ash/webui/camera_app_ui/resources/js/main.ts
+++ b/ash/webui/camera_app_ui/resources/js/main.ts
@@ -3,6 +3,11 @@
 // found in the LICENSE file.
 
 import {
+  startColorChangeUpdater,
+} from
+    'chrome://resources/cr_components/color_change_listener/colors_css_updater.js';
+
+import {
   getDefaultWindowSize,
 } from './app_window.js';
 import {assert, assertInstanceof} from './assert.js';
@@ -406,6 +411,27 @@
 }
 
 /**
+ * Append dynamic color CSS files and setup watcher for color changes.
+ */
+async function setupDynamicColor(): Promise<void> {
+  function loadCSS(url: string): Promise<void> {
+    return new Promise((resolve) => {
+      const link = document.createElement('link');
+      link.rel = 'stylesheet';
+      link.href = url;
+      link.addEventListener('load', () => resolve());
+      document.head.appendChild(link);
+    });
+  }
+  if (loadTimeData.getChromeFlag(Flag.JELLY)) {
+    await loadCSS('chrome://theme/colors.css?sets=sys');
+    startColorChangeUpdater();
+  } else {
+    await loadCSS('/css/colors_default.css');
+  }
+}
+
+/**
  * Singleton of the App object.
  */
 let instance: App|null = null;
@@ -420,6 +446,8 @@
 
   const perfLogger = new PerfLogger();
 
+  await setupDynamicColor();
+
   const {intent, facing, mode, autoTake, openFrom} = parseSearchParams();
 
   state.set(state.State.INTENT, intent !== null);
diff --git a/ash/webui/camera_app_ui/resources/js/models/result_saver.ts b/ash/webui/camera_app_ui/resources/js/models/result_saver.ts
index 1b64801..62fa672 100644
--- a/ash/webui/camera_app_ui/resources/js/models/result_saver.ts
+++ b/ash/webui/camera_app_ui/resources/js/models/result_saver.ts
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {ToteMetricFormat} from '../mojo/type.js';
 import {Metadata} from '../type.js';
 
 import {TimeLapseSaver, VideoSaver} from './video_saver.js';
@@ -14,10 +15,13 @@
    * Saves photo capture result.
    *
    * @param blob Data of the photo to be added.
+   * @param format Tote metric format of the photo to be added.
    * @param name Name of the photo to be saved.
    * @param metadata Data of the photo to be added.
    */
-  savePhoto(blob: Blob, name: string, metadata: Metadata|null): Promise<void>;
+  savePhoto(
+      blob: Blob, format: ToteMetricFormat, name: string,
+      metadata: Metadata|null): Promise<void>;
 
   /**
    * Saves gif capture result.
diff --git a/ash/webui/camera_app_ui/resources/js/mojo/chrome_helper.ts b/ash/webui/camera_app_ui/resources/js/mojo/chrome_helper.ts
index 688f5b7..4cf1133 100644
--- a/ash/webui/camera_app_ui/resources/js/mojo/chrome_helper.ts
+++ b/ash/webui/camera_app_ui/resources/js/mojo/chrome_helper.ts
@@ -27,6 +27,7 @@
   StorageMonitorCallbackRouter,
   StorageMonitorStatus,
   TabletModeMonitorCallbackRouter,
+  ToteMetricFormat,
 } from './type.js';
 import {wrapEndpoint} from './util.js';
 
@@ -275,6 +276,13 @@
   }
 
   /**
+   * Notifies Tote client when a photo/pdf/video/gif is captured.
+   */
+  notifyTote(format: ToteMetricFormat, name: string): void {
+    this.remote.notifyTote(format, name);
+  }
+
+  /**
    * Monitors for the file deletion of the file given by its |name| and triggers
    * |callback| when the file is deleted. Note that a previous monitor request
    * will be canceled once another monitor request is sent.
diff --git a/ash/webui/camera_app_ui/resources/js/mojo/type.ts b/ash/webui/camera_app_ui/resources/js/mojo/type.ts
index 08e9579..c8f5341b8 100644
--- a/ash/webui/camera_app_ui/resources/js/mojo/type.ts
+++ b/ash/webui/camera_app_ui/resources/js/mojo/type.ts
@@ -24,6 +24,7 @@
   StorageMonitorCallbackRouter,
   StorageMonitorStatus,
   TabletModeMonitorCallbackRouter,
+  ToteMetricFormat,
   WindowStateControllerRemote,
   WindowStateMonitorCallbackRouter,
   WindowStateType,
diff --git a/ash/webui/camera_app_ui/resources/js/views/camera.ts b/ash/webui/camera_app_ui/resources/js/views/camera.ts
index 34897f58..4a553505 100644
--- a/ash/webui/camera_app_ui/resources/js/views/camera.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/camera.ts
@@ -30,6 +30,7 @@
 import {VideoSaver} from '../models/video_saver.js';
 import {ChromeHelper} from '../mojo/chrome_helper.js';
 import {DeviceOperator} from '../mojo/device_operator.js';
+import {ToteMetricFormat} from '../mojo/type.js';
 import * as nav from '../nav.js';
 import {PerfLogger} from '../perf.js';
 import * as sound from '../sound.js';
@@ -523,7 +524,8 @@
     });
     try {
       const name = (new Filenamer(timestamp)).newImageName();
-      await this.resultSaver.savePhoto(blob, name, metadata);
+      await this.resultSaver.savePhoto(
+          blob, ToteMetricFormat.PHOTO, name, metadata);
     } catch (e) {
       toast.show(I18nString.ERROR_MSG_SAVE_FILE_FAILED);
       throw e;
@@ -572,7 +574,8 @@
 
       try {
         const name = (new Filenamer(timestamp)).newImageName();
-        await this.resultSaver.savePhoto(blob, name, metadata);
+        await this.resultSaver.savePhoto(
+            blob, ToteMetricFormat.PHOTO, name, metadata);
       } catch (e) {
         toast.show(I18nString.ERROR_MSG_SAVE_FILE_FAILED);
         throw e;
@@ -614,7 +617,8 @@
       const filenamer = new Filenamer(timestamp);
       const name = filenamer.newBurstName(false);
       try {
-        await this.resultSaver.savePhoto(blob, name, metadata);
+        await this.resultSaver.savePhoto(
+            blob, ToteMetricFormat.PHOTO, name, metadata);
       } catch (e) {
         toast.show(I18nString.ERROR_MSG_SAVE_FILE_FAILED);
         throw e;
@@ -625,7 +629,8 @@
         const {blob: portraitBlob, metadata: portraitMetadata} =
             await pendingPortrait;
         const name = filenamer.newBurstName(true);
-        await this.resultSaver.savePhoto(portraitBlob, name, portraitMetadata);
+        await this.resultSaver.savePhoto(
+            portraitBlob, ToteMetricFormat.PHOTO, name, portraitMetadata);
       } catch (e) {
         toast.show(I18nString.ERROR_MSG_TAKE_PORTRAIT_BOKEH_PHOTO_FAILED);
         // PortraitModeProcessError might be thrown when no face is detected
diff --git a/ash/webui/camera_app_ui/resources/js/views/document_review.ts b/ash/webui/camera_app_ui/resources/js/views/document_review.ts
index 8738033..c159a95 100644
--- a/ash/webui/camera_app_ui/resources/js/views/document_review.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/document_review.ts
@@ -17,6 +17,7 @@
 import {getI18nMessage} from '../models/load_time_data.js';
 import {ResultSaver} from '../models/result_saver.js';
 import {ChromeHelper} from '../mojo/chrome_helper.js';
+import {ToteMetricFormat} from '../mojo/type.js';
 import * as nav from '../nav.js';
 import {speakMessage} from '../spoken_msg.js';
 import {show as showToast} from '../toast.js';
@@ -253,10 +254,12 @@
     const blobs = this.pages.map((page) => page.croppedBlob);
     const name = (new Filenamer()).newDocumentName(mimeType);
     if (mimeType === MimeType.JPEG) {
-      await this.resultSaver.savePhoto(blobs[0], name, null);
+      await this.resultSaver.savePhoto(
+          blobs[0], ToteMetricFormat.SCAN_JPG, name, null);
     } else {
       const pdfBlob = await ChromeHelper.getInstance().convertToPdf(blobs);
-      await this.resultSaver.savePhoto(pdfBlob, name, null);
+      await this.resultSaver.savePhoto(
+          pdfBlob, ToteMetricFormat.SCAN_PDF, name, null);
     }
   }
 
diff --git a/ash/webui/camera_app_ui/resources/views/main.html b/ash/webui/camera_app_ui/resources/views/main.html
index 228ed9f3..75fb8a9 100644
--- a/ash/webui/camera_app_ui/resources/views/main.html
+++ b/ash/webui/camera_app_ui/resources/views/main.html
@@ -210,7 +210,8 @@
       </div>
       <div class="bottom-stripe left-stripe buttons circle">
         <button id="switch-device" tabindex="0"
-                i18n-label="switch_camera_button"></button>
+                i18n-label="switch_camera_button"
+                data-svg="camera_button_switch_device.svg"></button>
       </div>
       <div id="mode-selector" class="bottom-stripe">
         <div id="modes-group" class="buttons" role="radiogroup"
diff --git a/ash/webui/connectivity_diagnostics/BUILD.gn b/ash/webui/connectivity_diagnostics/BUILD.gn
index e15d330..1f95f7d0 100644
--- a/ash/webui/connectivity_diagnostics/BUILD.gn
+++ b/ash/webui/connectivity_diagnostics/BUILD.gn
@@ -20,6 +20,7 @@
     "//ui/webui",
   ]
   deps = [
+    "//ash/webui/common:chrome_os_webui_config",
     "//ash/webui/network_ui:network_diagnostics_resource_provider",
     "//ash/webui/network_ui:network_health_resource_provider",
     "//ash/webui/resources:connectivity_diagnostics_resources",
diff --git a/ash/webui/connectivity_diagnostics/connectivity_diagnostics_ui.h b/ash/webui/connectivity_diagnostics/connectivity_diagnostics_ui.h
index 068e9c4..347bc9a 100644
--- a/ash/webui/connectivity_diagnostics/connectivity_diagnostics_ui.h
+++ b/ash/webui/connectivity_diagnostics/connectivity_diagnostics_ui.h
@@ -7,14 +7,29 @@
 
 #include <string>
 
+#include "ash/webui/common/chrome_os_webui_config.h"
+#include "ash/webui/connectivity_diagnostics/url_constants.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/services/network_health/public/mojom/network_diagnostics.mojom-forward.h"
 #include "chromeos/services/network_health/public/mojom/network_health.mojom-forward.h"
+#include "content/public/common/url_constants.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "ui/webui/mojo_web_ui_controller.h"
 
 namespace ash {
 
+class ConnectivityDiagnosticsUI;
+
+class ConnectivityDiagnosticsUIConfig
+    : public ChromeOSWebUIConfig<ConnectivityDiagnosticsUI> {
+ public:
+  explicit ConnectivityDiagnosticsUIConfig(
+      CreateWebUIControllerFunc create_controller_func)
+      : ChromeOSWebUIConfig(content::kChromeUIScheme,
+                            ash::kChromeUIConnectivityDiagnosticsHost,
+                            create_controller_func) {}
+};
+
 class ConnectivityDiagnosticsUI : public ui::MojoWebUIController {
  public:
   using BindNetworkDiagnosticsServiceCallback = base::RepeatingCallback<void(
diff --git a/ash/wm/gestures/back_gesture/back_gesture_affordance.cc b/ash/wm/gestures/back_gesture/back_gesture_affordance.cc
index b4832ff..729f874e 100644
--- a/ash/wm/gestures/back_gesture/back_gesture_affordance.cc
+++ b/ash/wm/gestures/back_gesture/back_gesture_affordance.cc
@@ -16,7 +16,6 @@
 #include "ash/wm/splitview/split_view_divider.h"
 #include "ash/wm/window_util.h"
 #include "base/i18n/rtl.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/vector_icons/vector_icons.h"
 #include "ui/aura/window.h"
 #include "ui/compositor/layer.h"
@@ -47,16 +46,6 @@
 constexpr int kArrowSize = 20;
 constexpr int kBackgroundRadius = 20;
 
-// The background shadow for the circle.
-// TODO(michelefan@): Clean up the shadows after the
-// `chromeos::features::IsDarkLightModeEnabled()` is enabled by default.
-constexpr int kBackNudgeShadowOffsetY1 = 1;
-constexpr int kBackNudgeShadowBlurRadius1 = 2;
-constexpr SkColor kBackNudgeShadowColor1 = SkColorSetA(SK_ColorBLACK, 0x4D);
-constexpr int kBackNudgeShadowOffsetY2 = 2;
-constexpr int kBackNudgeShadowBlurRadius2 = 6;
-constexpr SkColor kBackNudgeShadowColor2 = SkColorSetA(SK_ColorBLACK, 0x26);
-
 // Radius of the ripple while x-axis movement of the affordance achieves
 // |kDistanceForFullRadius|.
 constexpr int kFullRippleRadius = 32;
@@ -156,26 +145,14 @@
         x_offset_ >= kDistanceForFullRadius ||
         state_ == BackGestureAffordance::State::COMPLETING;
 
-    if (chromeos::features::IsDarkLightModeEnabled())
-      // Draw highlight border circles.
-      DrawCircleHighlightBorder(this, canvas, center_point, kBackgroundRadius);
+    // Draw highlight border circles.
+    DrawCircleHighlightBorder(this, canvas, center_point, kBackgroundRadius);
 
     // Draw the arrow background circle.
     cc::PaintFlags bg_flags;
     bg_flags.setAntiAlias(true);
     bg_flags.setStyle(cc::PaintFlags::kFill_Style);
 
-    if (!chromeos::features::IsDarkLightModeEnabled()) {
-      gfx::ShadowValues shadows;
-      shadows.push_back(gfx::ShadowValue(
-          gfx::Vector2d(0, kBackNudgeShadowOffsetY1),
-          kBackNudgeShadowBlurRadius1, kBackNudgeShadowColor1));
-      shadows.push_back(gfx::ShadowValue(
-          gfx::Vector2d(0, kBackNudgeShadowOffsetY2),
-          kBackNudgeShadowBlurRadius2, kBackNudgeShadowColor2));
-      bg_flags.setLooper(gfx::CreateShadowDrawLooper(shadows));
-    }
-
     const auto* color_provider = GetColorProvider();
     bg_flags.setColor(color_provider->GetColor(
         is_activated ? kColorAshControlBackgroundColorActive
diff --git a/ash/wm/gestures/back_gesture/back_gesture_contextual_nudge.cc b/ash/wm/gestures/back_gesture/back_gesture_contextual_nudge.cc
index ff4113c8..60b4ad42 100644
--- a/ash/wm/gestures/back_gesture/back_gesture_contextual_nudge.cc
+++ b/ash/wm/gestures/back_gesture/back_gesture_contextual_nudge.cc
@@ -15,7 +15,6 @@
 #include "base/functional/callback.h"
 #include "base/i18n/rtl.h"
 #include "base/timer/timer.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/layer_animation_observer.h"
@@ -52,16 +51,6 @@
 // Top and bottom inset of the label.
 constexpr int kLabelTopBottomInset = 6;
 
-// Shadow values for the back nudge circle.
-// TODO (michelefan@): remove the shadow for the back gesture nudge after D/L
-// flag is enabled by default.
-constexpr int kBackNudgeShadowOffsetY1 = 1;
-constexpr int kBackNudgeShadowBlurRadius1 = 2;
-constexpr SkColor kBackNudgeShadowColor1 = SkColorSetA(SK_ColorBLACK, 0x4D);
-constexpr int kBackNudgeShadowOffsetY2 = 2;
-constexpr int kBackNudgeShadowBlurRadius2 = 6;
-constexpr SkColor kBackNudgeShadowColor2 = SkColorSetA(SK_ColorBLACK, 0x26);
-
 // Duration of the pause before sliding in to show the nudge.
 constexpr base::TimeDelta kPauseBeforeShowAnimationDuration = base::Seconds(10);
 
@@ -254,17 +243,6 @@
       circle_flags.setColor(
           color_provider->GetColor(kColorAshShieldAndBaseOpaque));
 
-      if (!chromeos::features::IsDarkLightModeEnabled()) {
-        gfx::ShadowValues shadows;
-        shadows.push_back(gfx::ShadowValue(
-            gfx::Vector2d(0, kBackNudgeShadowOffsetY1),
-            kBackNudgeShadowBlurRadius1, kBackNudgeShadowColor1));
-        shadows.push_back(gfx::ShadowValue(
-            gfx::Vector2d(0, kBackNudgeShadowOffsetY2),
-            kBackNudgeShadowBlurRadius2, kBackNudgeShadowColor2));
-        circle_flags.setLooper(gfx::CreateShadowDrawLooper(shadows));
-      }
-
       gfx::PointF center_point;
       if (base::i18n::IsRTL()) {
         const gfx::Point right_center = GetLocalBounds().right_center();
@@ -277,10 +255,8 @@
       }
       canvas->DrawCircle(center_point, kCircleRadius, circle_flags);
 
-      if (chromeos::features::IsDarkLightModeEnabled()) {
-        // Draw highlight border circles for the affordance.
-        DrawCircleHighlightBorder(this, canvas, center_point, kCircleRadius);
-      }
+      // Draw highlight border circles for the affordance.
+      DrawCircleHighlightBorder(this, canvas, center_point, kCircleRadius);
 
       // Draw the black round rectangle around the text.
       cc::PaintFlags round_rect_flags;
@@ -293,11 +269,9 @@
           gfx::Insets::VH(-kLabelTopBottomInset, -kLabelCornerRadius));
       canvas->DrawRoundRect(label_bounds, kLabelCornerRadius, round_rect_flags);
 
-      if (chromeos::features::IsDarkLightModeEnabled()) {
-        // Draw highlight border for the black round rectangle around the text.
-        DrawRoundRectHighlightBorder(this, canvas, label_bounds,
-                                     kLabelCornerRadius);
-      }
+      // Draw highlight border for the black round rectangle around the text.
+      DrawRoundRectHighlightBorder(this, canvas, label_bounds,
+                                   kLabelCornerRadius);
     }
 
     // ui::ImplicitAnimationObserver:
diff --git a/ash/wm/splitview/split_view_divider_view.cc b/ash/wm/splitview/split_view_divider_view.cc
index cb69e76..95a7b076 100644
--- a/ash/wm/splitview/split_view_divider_view.cc
+++ b/ash/wm/splitview/split_view_divider_view.cc
@@ -20,7 +20,6 @@
 #include "ash/wm/splitview/split_view_divider.h"
 #include "ash/wm/splitview/split_view_divider_handler_view.h"
 #include "ash/wm/splitview/split_view_utils.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
@@ -139,10 +138,8 @@
       AshColorProvider::Get()->GetBaseLayerColor(
           AshColorProvider::BaseLayerType::kOpaque));
 
-  if (chromeos::features::IsDarkLightModeEnabled()) {
-    SetBorder(std::make_unique<views::HighlightBorder>(
-        /*corner_radius=*/0, views::HighlightBorder::Type::kHighlightBorder1));
-  }
+  SetBorder(std::make_unique<views::HighlightBorder>(
+      /*corner_radius=*/0, views::HighlightBorder::Type::kHighlightBorder1));
 }
 
 bool SplitViewDividerView::OnMousePressed(const ui::MouseEvent& event) {
diff --git a/ash/wm/workspace/backdrop_controller.cc b/ash/wm/workspace/backdrop_controller.cc
index 43487ab9..4f6c608 100644
--- a/ash/wm/workspace/backdrop_controller.cc
+++ b/ash/wm/workspace/backdrop_controller.cc
@@ -489,15 +489,6 @@
   if (backdrop_mode == WindowBackdrop::BackdropMode::kDisabled)
     return false;
 
-  // If |window| is the current active window and is an ARC app window, |window|
-  // should have a backdrop when spoken feedback is enabled.
-  if (window->GetProperty(aura::client::kAppType) ==
-          static_cast<int>(AppType::ARC_APP) &&
-      wm::IsActiveWindow(window) &&
-      Shell::Get()->accessibility_controller()->spoken_feedback().enabled()) {
-    return true;
-  }
-
   if (!desks_util::IsDeskContainer(container_))
     return false;
 
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index 65d40847..916249f 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -1960,50 +1960,6 @@
   EXPECT_EQ(kNoSoundKey, client.GetPlayedEarconAndReset());
 }
 
-TEST_F(WorkspaceLayoutManagerBackdropTest, SpokenFeedbackForArc) {
-  WorkspaceController* wc = ShellTestApi().workspace_controller();
-  WorkspaceControllerTestApi test_helper(wc);
-  AccessibilityControllerImpl* controller =
-      Shell::Get()->accessibility_controller();
-  TestAccessibilityControllerClient client;
-
-  controller->SetSpokenFeedbackEnabled(true, A11Y_NOTIFICATION_NONE);
-  EXPECT_TRUE(controller->spoken_feedback().enabled());
-
-  aura::test::TestWindowDelegate delegate;
-  std::unique_ptr<aura::Window> window_arc(CreateTestWindowInShellWithDelegate(
-      &delegate, 0, gfx::Rect(0, 0, 100, 100)));
-  window_arc->Show();
-  std::unique_ptr<aura::Window> window_nonarc(
-      CreateTestWindowInShellWithDelegate(&delegate, 0,
-                                          gfx::Rect(0, 0, 100, 100)));
-  window_nonarc->Show();
-
-  window_arc->SetProperty(aura::client::kAppType,
-                          static_cast<int>(AppType::ARC_APP));
-  EXPECT_FALSE(test_helper.GetBackdropWindow());
-
-  // ARC window will have a backdrop only when it's active.
-  wm::ActivateWindow(window_arc.get());
-  EXPECT_TRUE(test_helper.GetBackdropWindow());
-
-  wm::ActivateWindow(window_nonarc.get());
-  EXPECT_FALSE(test_helper.GetBackdropWindow());
-
-  wm::ActivateWindow(window_arc.get());
-  EXPECT_TRUE(test_helper.GetBackdropWindow());
-
-  // Make sure that clicking the backdrop window will play sound.
-  ui::test::EventGenerator* generator = GetEventGenerator();
-  generator->MoveMouseTo(300, 300);
-  generator->ClickLeftButton();
-  EXPECT_EQ(Sound::kVolumeAdjust, client.GetPlayedEarconAndReset());
-
-  generator->MoveMouseTo(70, 70);
-  generator->ClickLeftButton();
-  EXPECT_EQ(kNoSoundKey, client.GetPlayedEarconAndReset());
-}
-
 class WorkspaceLayoutManagerKeyboardTest : public AshTestBase {
  public:
   WorkspaceLayoutManagerKeyboardTest() : layout_manager_(nullptr) {}
diff --git a/base/allocator/partition_allocator/partition_alloc.gni b/base/allocator/partition_allocator/partition_alloc.gni
index 6085681..67e8136 100644
--- a/base/allocator/partition_allocator/partition_alloc.gni
+++ b/base/allocator/partition_allocator/partition_alloc.gni
@@ -14,7 +14,8 @@
 if (is_nacl) {
   # NaCl targets don't use 64-bit pointers.
   has_64_bit_pointers = false
-} else if (current_cpu == "x64" || current_cpu == "arm64") {
+} else if (current_cpu == "x64" || current_cpu == "arm64" ||
+           current_cpu == "loong64") {
   has_64_bit_pointers = true
 } else if (current_cpu == "x86" || current_cpu == "arm") {
   has_64_bit_pointers = false
diff --git a/build/config/siso/configure_siso.py b/build/config/siso/configure_siso.py
index 87ec7b1..2770f6e7 100755
--- a/build/config/siso/configure_siso.py
+++ b/build/config/siso/configure_siso.py
@@ -19,14 +19,16 @@
   project = None
   if not args.rbe_instance:
     return 0
-  elems = args.rbe_instance.split('/')
+  rbe_instance = args.rbe_instance
+  elems = rbe_instance.split('/')
   if len(elems) == 4 and elems[0] == 'projects':
     project = elems[1]
+    rbe_instance = elems[-1]
   siso_env_path = os.path.join(THIS_DIR, '.sisoenv')
   with open(siso_env_path, 'w') as f:
     if project:
       f.write('SISO_PROJECT=%s\n' % project)
-    f.write('SISO_REAPI_INSTANCE=%s\n' % args.rbe_instance)
+    f.write('SISO_REAPI_INSTANCE=%s\n' % rbe_instance)
   return 0
 
 
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index ed2cd19..dd36a6e0 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-12.20230418.2.1
+12.20230418.3.1
diff --git a/cc/paint/image_transfer_cache_entry_unittest.cc b/cc/paint/image_transfer_cache_entry_unittest.cc
index cc2c096..44601c5 100644
--- a/cc/paint/image_transfer_cache_entry_unittest.cc
+++ b/cc/paint/image_transfer_cache_entry_unittest.cc
@@ -16,7 +16,6 @@
 #include "base/notreached.h"
 #include "build/build_config.h"
 #include "cc/paint/image_transfer_cache_entry.h"
-#include "cc/paint/paint_op_writer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -243,14 +242,14 @@
                                            nullptr /* decoded color space*/),
       true /* needs_mips */, absl::nullopt));
   uint32_t size = client_entry->SerializedSize();
-  auto data = PaintOpWriter::AllocateAlignedBuffer<uint8_t>(size);
+  std::vector<uint8_t> data(size);
   ASSERT_TRUE(client_entry->Serialize(
-      base::make_span(static_cast<uint8_t*>(data.get()), size)));
+      base::make_span(static_cast<uint8_t*>(data.data()), size)));
 
   // Create service-side entry from the client-side serialize info
   auto entry(std::make_unique<ServiceImageTransferCacheEntry>());
   ASSERT_TRUE(entry->Deserialize(
-      gr_context(), base::make_span(static_cast<uint8_t*>(data.get()), size)));
+      gr_context(), base::make_span(static_cast<uint8_t*>(data.data()), size)));
   ASSERT_TRUE(entry->is_yuv());
 
   // Check color of pixels
@@ -395,13 +394,12 @@
   ClientImageTransferCacheEntry client_entry(
       ClientImageTransferCacheEntry::Image(&bitmap.pixmap()), true,
       absl::nullopt);
-  const uint32_t storage_size = client_entry.SerializedSize();
-  auto storage = PaintOpWriter::AllocateAlignedBuffer<uint8_t>(storage_size);
-  client_entry.Serialize(base::make_span(storage.get(), storage_size));
+  std::vector<uint8_t> storage(client_entry.SerializedSize());
+  client_entry.Serialize(base::make_span(storage.data(), storage.size()));
 
   ServiceImageTransferCacheEntry service_entry;
   service_entry.Deserialize(gr_context.get(),
-                            base::make_span(storage.get(), storage_size));
+                            base::make_span(storage.data(), storage.size()));
   ASSERT_TRUE(service_entry.image());
   auto pre_mip_image = service_entry.image();
   EXPECT_FALSE(pre_mip_image->isTextureBacked());
@@ -424,13 +422,12 @@
   ClientImageTransferCacheEntry client_entry(
       ClientImageTransferCacheEntry::Image(&bitmap.pixmap()), false,
       absl::nullopt);
-  const uint32_t storage_size = client_entry.SerializedSize();
-  auto storage = PaintOpWriter::AllocateAlignedBuffer<uint8_t>(storage_size);
-  client_entry.Serialize(base::make_span(storage.get(), storage_size));
+  std::vector<uint8_t> storage(client_entry.SerializedSize());
+  client_entry.Serialize(base::make_span(storage.data(), storage.size()));
 
   ServiceImageTransferCacheEntry service_entry;
   service_entry.Deserialize(gr_context.get(),
-                            base::make_span(storage.get(), storage_size));
+                            base::make_span(storage.data(), storage.size()));
   ASSERT_TRUE(service_entry.image());
   auto pre_mip_image = service_entry.image();
   EXPECT_FALSE(pre_mip_image->isTextureBacked());
diff --git a/cc/paint/paint_op_buffer_unittest.cc b/cc/paint/paint_op_buffer_unittest.cc
index 070c3e4fa..a0abe2aa 100644
--- a/cc/paint/paint_op_buffer_unittest.cc
+++ b/cc/paint/paint_op_buffer_unittest.cc
@@ -3319,8 +3319,8 @@
                                               SkRect::MakeWH(100, 100));
 
   TestOptionsProvider options_provider;
-  auto memory = AllocateSerializedBuffer();
-  PaintOpWriter writer(memory.get(), kDefaultSerializedBufferSize,
+  std::vector<uint8_t> memory(kDefaultSerializedBufferSize);
+  PaintOpWriter writer(memory.data(), memory.size(),
                        options_provider.serialize_options(), false);
   writer.Write(filter.get(), SkM44());
   ASSERT_GT(writer.size(), sizeof(float));
@@ -3328,14 +3328,14 @@
   // Replace the first occurrence of rect_size with NaN to make the ClipRectOp
   // invalid.
   for (size_t i = 0; i < writer.size(); i += sizeof(float)) {
-    float* f = reinterpret_cast<float*>(memory.get() + i);
+    float* f = reinterpret_cast<float*>(memory.data() + i);
     if (*f == rect_size) {
       *f = std::numeric_limits<float>::quiet_NaN();
       break;
     }
   }
   sk_sp<PaintFilter> deserialized_filter;
-  PaintOpReader reader(memory.get(), writer.size(),
+  PaintOpReader reader(memory.data(), writer.size(),
                        options_provider.deserialize_options(), false);
   reader.Read(&deserialized_filter);
   EXPECT_FALSE(deserialized_filter);
diff --git a/cc/paint/paint_op_writer.h b/cc/paint/paint_op_writer.h
index dee0d600..ef077f3 100644
--- a/cc/paint/paint_op_writer.h
+++ b/cc/paint/paint_op_writer.h
@@ -50,11 +50,10 @@
                 bool enable_security_constraints = false);
   ~PaintOpWriter();
 
-  template <typename T = char>
-  static std::unique_ptr<T, base::AlignedFreeDeleter> AllocateAlignedBuffer(
+  static std::unique_ptr<char, base::AlignedFreeDeleter> AllocateAlignedBuffer(
       size_t size) {
-    return std::unique_ptr<T, base::AlignedFreeDeleter>(
-        static_cast<T*>(base::AlignedAlloc(size, kMaxAlignment)));
+    return std::unique_ptr<char, base::AlignedFreeDeleter>(
+        static_cast<char*>(base::AlignedAlloc(size, kMaxAlignment)));
   }
 
   const PaintOp::SerializeOptions& options() const { return *options_; }
diff --git a/cc/test/test_options_provider.cc b/cc/test/test_options_provider.cc
index 5eec903..3b2d89f2 100644
--- a/cc/test/test_options_provider.cc
+++ b/cc/test/test_options_provider.cc
@@ -7,7 +7,6 @@
 #include <limits>
 #include <vector>
 
-#include "cc/paint/paint_op_writer.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkColorSpace.h"
 #include "third_party/skia/include/core/SkImageInfo.h"
@@ -115,13 +114,13 @@
   ClientImageTransferCacheEntry cache_entry(
       ClientImageTransferCacheEntry::Image(&bitmap.pixmap()),
       false /* needs_mips */, target_color_params);
-  const uint32_t data_size = cache_entry.SerializedSize();
-  auto data = PaintOpWriter::AllocateAlignedBuffer<uint8_t>(data_size);
-  if (!cache_entry.Serialize(base::span<uint8_t>(data.get(), data_size))) {
+  std::vector<uint8_t> data;
+  data.resize(cache_entry.SerializedSize());
+  if (!cache_entry.Serialize(base::span<uint8_t>(data.data(), data.size()))) {
     return ScopedResult();
   }
 
-  CreateEntryDirect(entry_key, base::span<uint8_t>(data.get(), data_size));
+  CreateEntryDirect(entry_key, base::span<uint8_t>(data.data(), data.size()));
 
   return ScopedResult(DecodedDrawImage(
       image_id, nullptr, SkSize::MakeEmpty(), draw_image.scale(),
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc
index fb9dd49..fde3858 100644
--- a/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -20,7 +20,6 @@
 #include "cc/paint/draw_image.h"
 #include "cc/paint/image_transfer_cache_entry.h"
 #include "cc/paint/paint_image_builder.h"
-#include "cc/paint/paint_op_writer.h"
 #include "cc/test/fake_paint_image_generator.h"
 #include "cc/test/skia_common.h"
 #include "cc/test/test_tile_task_runner.h"
@@ -171,9 +170,7 @@
 
   void* MapTransferCacheEntry(uint32_t serialized_size) override {
     mapped_entry_size_ = serialized_size;
-    auto buffer =
-        PaintOpWriter::AllocateAlignedBuffer<uint8_t>(serialized_size);
-    mapped_entry_.swap(buffer);
+    mapped_entry_.reset(new uint8_t[serialized_size]);
     return mapped_entry_.get();
   }
 
@@ -273,7 +270,7 @@
   raw_ptr<TransferCacheTestHelper> transfer_cache_helper_;
   bool advertise_accelerated_decoding_ = false;
   size_t mapped_entry_size_ = 0;
-  std::unique_ptr<uint8_t, base::AlignedFreeDeleter> mapped_entry_;
+  std::unique_ptr<uint8_t[]> mapped_entry_;
 };
 
 class MockRasterImplementation : public gpu::raster::RasterImplementationGLES {
diff --git a/cc/tiles/picture_layer_tiling.cc b/cc/tiles/picture_layer_tiling.cc
index 3c07f7b..5988429 100644
--- a/cc/tiles/picture_layer_tiling.cc
+++ b/cc/tiles/picture_layer_tiling.cc
@@ -89,9 +89,9 @@
 
   all_tiles_done_ = false;
   std::unique_ptr<Tile> tile = client_->CreateTile(info);
-  Tile* raw_ptr = tile.get();
+  Tile* tile_ptr = tile.get();
   tiles_[key] = std::move(tile);
-  return raw_ptr;
+  return tile_ptr;
 }
 
 void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() {
diff --git a/chrome/VERSION b/chrome/VERSION
index 73866e7..882e39c8 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=114
 MINOR=0
-BUILD=5721
+BUILD=5722
 PATCH=0
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt
index 56944867..6bb1d15 100644
--- a/chrome/android/profiles/arm.newest.txt
+++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-114.0.5715.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-arm-114.0.5715.0_rc-r2-merged.afdo.bz2
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 5b7aed8..28d51ad7 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-114.0.5715.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-114.0.5715.0_rc-r2-merged.afdo.bz2
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index 9ac7b55..7892638 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -4174,6 +4174,9 @@
   <message name="IDS_SETTINGS_PEOPLE_RECOVERY_DISABLE_DIALOG_MESSAGE" desc="Text for the notification informing the user that local data recovery will be disabled">
     You will not be able to recover local data if you forget your password or PIN.
   </message>
+  <message name="IDS_SETTINGS_PEOPLE_RECOVERY_NOT_SUPPORTED_MESSAGE" desc="Text for the notification informing the user that local data recovery not supported">
+    Local data recovery is currently not supported. <ph name="LINK_BEGIN">&lt;a&gt;</ph>Learn more<ph name="LINK_END">&lt;/a&gt;</ph>.
+  </message>
 
   <!-- Kerberos section (OS settings) -->
   <message name="IDS_OS_SETTINGS_KERBEROS" desc="Name of a section in the OS settings page." meaning="Manage Kerberos authetication tickets.">
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PEOPLE_RECOVERY_NOT_SUPPORTED_MESSAGE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PEOPLE_RECOVERY_NOT_SUPPORTED_MESSAGE.png.sha1
new file mode 100644
index 0000000..0857c9f1
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PEOPLE_RECOVERY_NOT_SUPPORTED_MESSAGE.png.sha1
@@ -0,0 +1 @@
+f208598ed03669c2bd93af2bb55cee06f03f109c
\ No newline at end of file
diff --git a/chrome/app/password_manager_ui_strings.grdp b/chrome/app/password_manager_ui_strings.grdp
index 421b1bd..0afc49e4 100644
--- a/chrome/app/password_manager_ui_strings.grdp
+++ b/chrome/app/password_manager_ui_strings.grdp
@@ -75,6 +75,35 @@
   <message name="IDS_PASSWORD_MANAGER_UI_SELECT_FILE" desc="A button in the settings page that triggers import of passwords from a CSV file.">
     Select file
   </message>
+  <message name="IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_TITLE" desc="The title of a dialog, which offers the ability for the user to import passwords into Password Manager. Shown when import has successfully finished with no errors.">
+    Import successful!
+  </message>
+  <message name="IDS_PASSWORD_MANAGER_UI_IMPORT_COMPLETE_TITLE" desc="The title of a dialog, which offers the ability for the user to import passwords into Password Manager. Shown when import has successfully finished, but some errors were found in the imported file.">
+    Import complete
+  </message>
+  <message name="IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_TIP" desc="Message is shown on the dialog for importing passwords, after a successful import. It is an advice for the user, that they should consider deleting the file, which they used for importing passwords from.">
+    Consider deleting <ph name="FILENAME">&lt;span class="bold-text"&gt;$1&lt;/span&gt;<ex>&lt;span class="bold-text"&gt;filename.csv&lt;/span&gt;</ex></ph>, so others who use this device can't see your passwords
+  </message>
+  <message name="IDS_PASSWORD_MANAGER_UI_IMPORT_FAILURES_SUMMARY" desc="Message is shown on the dialog for importing passwords if some passwords weren't imported.">
+    {NUM_PASSWORDS, plural,
+     =1 {1 password not imported}
+     other {{NUM_PASSWORDS} passwords not imported}}
+  </message>
+  <message name="IDS_PASSWORD_MANAGER_UI_IMPORT_BAD_ROWS_FORMAT" desc="An error message for which summarizes all rows that weren't imported, because we weren't able to read them completely due to incorrect formatting. It is shown on the dialog for importing passwords if some passwords weren't imported.">
+    {NUM_PASSWORDS, plural,
+     =1 {1 other password wasn't imported because it's formatted incorrectly}
+     other {{NUM_PASSWORDS} other passwords weren't imported because they're formatted incorrectly}}
+  </message>
+  <message name="IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_SUMMARY_ACCOUNT" desc="Text on the dialog for importing passwords that shows how many passwords have been saved to Google Password Manager, after the user has chosen the file to import passwords from.">
+    {NUM_PASSWORDS, plural,
+     =1 {1 password imported to <ph name="BRAND">$1<ex>Google Password Manager</ex></ph> for <ph name="USER_EMAIL"><ex>elisa.g.becket@gmail.com</ex>$2</ph>}
+     other {{NUM_PASSWORDS} passwords imported to <ph name="BRAND">$1<ex>Google Password Manager</ex></ph> for <ph name="USER_EMAIL"><ex>elisa.g.becket@gmail.com</ex>$2</ph>}}
+  </message>
+  <message name="IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_SUMMARY_DEVICE" desc="Text on the dialog for importing passwords that shows how many passwords have been stored on the user device, after the user has chosen the file to import passwords from.">
+    {NUM_PASSWORDS, plural,
+     =1 {1 password imported to <ph name="BRAND">$1<ex>Google Password Manager</ex></ph> on this device}
+     other {{NUM_PASSWORDS} passwords imported to <ph name="BRAND">$1<ex>Google Password Manager</ex></ph> on this device}}
+  </message>
   <message name="IDS_PASSWORD_MANAGER_UI_EXPORT_TITLE" desc="The title for the password export banner in Password Manager settings.">
     Export passwords
   </message>
diff --git a/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_BAD_ROWS_FORMAT.png.sha1 b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_BAD_ROWS_FORMAT.png.sha1
new file mode 100644
index 0000000..d3578c5
--- /dev/null
+++ b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_BAD_ROWS_FORMAT.png.sha1
@@ -0,0 +1 @@
+fac4aef5248945e9b23aa8158182745025763e17
\ No newline at end of file
diff --git a/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_COMPLETE_TITLE.png.sha1 b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_COMPLETE_TITLE.png.sha1
new file mode 100644
index 0000000..d3578c5
--- /dev/null
+++ b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_COMPLETE_TITLE.png.sha1
@@ -0,0 +1 @@
+fac4aef5248945e9b23aa8158182745025763e17
\ No newline at end of file
diff --git a/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_FAILURES_SUMMARY.png.sha1 b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_FAILURES_SUMMARY.png.sha1
new file mode 100644
index 0000000..d3578c5
--- /dev/null
+++ b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_FAILURES_SUMMARY.png.sha1
@@ -0,0 +1 @@
+fac4aef5248945e9b23aa8158182745025763e17
\ No newline at end of file
diff --git a/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_SUMMARY_ACCOUNT.png.sha1 b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_SUMMARY_ACCOUNT.png.sha1
new file mode 100644
index 0000000..a1b0138
--- /dev/null
+++ b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_SUMMARY_ACCOUNT.png.sha1
@@ -0,0 +1 @@
+a1a84ed3f2303a163a200dc9770feb9e0340cec2
\ No newline at end of file
diff --git a/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_SUMMARY_DEVICE.png.sha1 b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_SUMMARY_DEVICE.png.sha1
new file mode 100644
index 0000000..1e86a0b8
--- /dev/null
+++ b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_SUMMARY_DEVICE.png.sha1
@@ -0,0 +1 @@
+525a8fe8872dab575d7ae451fafd6931da1ba0dd
\ No newline at end of file
diff --git a/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_TIP.png.sha1 b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_TIP.png.sha1
new file mode 100644
index 0000000..a1b0138
--- /dev/null
+++ b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_TIP.png.sha1
@@ -0,0 +1 @@
+a1a84ed3f2303a163a200dc9770feb9e0340cec2
\ No newline at end of file
diff --git a/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_TITLE.png.sha1 b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_TITLE.png.sha1
new file mode 100644
index 0000000..a1b0138
--- /dev/null
+++ b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_TITLE.png.sha1
@@ -0,0 +1 @@
+a1a84ed3f2303a163a200dc9770feb9e0340cec2
\ No newline at end of file
diff --git a/chrome/app/theme/default_100_percent/common/migrate_address_avatar50_x135_y54.png b/chrome/app/theme/default_100_percent/common/migrate_address_avatar50_x135_y54.png
new file mode 100644
index 0000000..84a6ca2c
--- /dev/null
+++ b/chrome/app/theme/default_100_percent/common/migrate_address_avatar50_x135_y54.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/migrate_address_avatar50_x135_y54_dark.png b/chrome/app/theme/default_100_percent/common/migrate_address_avatar50_x135_y54_dark.png
new file mode 100644
index 0000000..046dafd
--- /dev/null
+++ b/chrome/app/theme/default_100_percent/common/migrate_address_avatar50_x135_y54_dark.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/migrate_address_avatar50_x135_y54.png b/chrome/app/theme/default_200_percent/common/migrate_address_avatar50_x135_y54.png
new file mode 100644
index 0000000..0121cb1
--- /dev/null
+++ b/chrome/app/theme/default_200_percent/common/migrate_address_avatar50_x135_y54.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/migrate_address_avatar50_x135_y54_dark.png b/chrome/app/theme/default_200_percent/common/migrate_address_avatar50_x135_y54_dark.png
new file mode 100644
index 0000000..813dff12
--- /dev/null
+++ b/chrome/app/theme/default_200_percent/common/migrate_address_avatar50_x135_y54_dark.png
Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index d0539df0..ca238e0 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -271,6 +271,8 @@
         <structure type="chrome_scaled_image" name="IDR_SAVE_CARD_DARK" file="common/save_card_dark.png" />
         <structure type="chrome_scaled_image" name="IDR_SAVE_CARD_SECURELY_DARK" file="common/save_card_securely_dark.png" />
         <structure type="chrome_scaled_image" name="IDR_SAVE_CARD_SECURELY" file="common/save_card_securely.png" />
+        <structure type="chrome_scaled_image" name="IDR_MIGRATE_ADDRESS_AVATAR50_X135_Y54" file="common/migrate_address_avatar50_x135_y54.png" />
+        <structure type="chrome_scaled_image" name="IDR_MIGRATE_ADDRESS_AVATAR50_X135_Y54_DARK" file="common/migrate_address_avatar50_x135_y54_dark.png" />
         <structure type="chrome_scaled_image" name="IDR_PRIVACY_SANDBOX_CONFIRMATION_BANNER" file="common/privacy_sandbox_confirmation_banner.png" />
         <structure type="chrome_scaled_image" name="IDR_PRIVACY_SANDBOX_CONFIRMATION_BANNER_DARK" file="common/privacy_sandbox_confirmation_banner_dark.png" />
       </if>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 2cbb850f..7191434 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -4987,6 +4987,13 @@
      flag_descriptions::kDiacriticsOnPhysicalKeyboardLongpressDescription,
      kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kDiacriticsOnPhysicalKeyboardLongpress)},
+    {"enable-cros-diacritics-on-physical-keyboard-longpress-on-by-default",
+     flag_descriptions::kDiacriticsOnPhysicalKeyboardLongpressDefaultOnName,
+     flag_descriptions::
+         kDiacriticsOnPhysicalKeyboardLongpressDefaultOnDescription,
+     kOsCrOS,
+     FEATURE_VALUE_TYPE(
+         ash::features::kDiacriticsOnPhysicalKeyboardLongpressDefaultOn)},
     {"enable-cros-first-party-vietnamese-input",
      flag_descriptions::kFirstPartyVietnameseInputName,
      flag_descriptions::kFirstPartyVietnameseInputDescription, kOsCrOS,
diff --git a/chrome/browser/apps/app_service/app_service_proxy_base.cc b/chrome/browser/apps/app_service/app_service_proxy_base.cc
index 24d6c4b..ba2c47df 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_base.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy_base.cc
@@ -491,8 +491,9 @@
     // |activity_label| -> {index, is_generic}
     std::map<std::string, IndexAndGeneric> best_handler_map;
     bool is_file_handling_intent = !intent->files.empty();
-    size_t index = 0;
-    for (const auto& filter : update.IntentFilters()) {
+    const apps::IntentFilters& filters = update.IntentFilters();
+    for (size_t i = 0; i < filters.size(); i++) {
+      const IntentFilterPtr& filter = filters[i];
       DCHECK(filter);
       if (exclude_browsers && filter->IsBrowserFilter()) {
         continue;
@@ -510,12 +511,10 @@
         auto it = best_handler_map.find(activity_label);
         if (it == best_handler_map.end() ||
             (it->second.is_generic && !generic)) {
-          best_handler_map[activity_label] = IndexAndGeneric{index, generic};
+          best_handler_map[activity_label] = IndexAndGeneric{i, generic};
         }
       }
-      index++;
     }
-    const auto& filters = update.IntentFilters();
     for (const auto& handler_entry : best_handler_map) {
       const IntentFilterPtr& filter = filters[handler_entry.second.index];
       IntentLaunchInfo entry = CreateIntentLaunchInfo(intent, filter, update);
diff --git a/chrome/browser/apps/app_service/app_service_proxy_unittest.cc b/chrome/browser/apps/app_service/app_service_proxy_unittest.cc
index 58354572..47c335a 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_unittest.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy_unittest.cc
@@ -1024,5 +1024,58 @@
 
   EXPECT_TRUE(called_multi);
 }
+
+TEST_F(AppServiceProxyTest, GetAppsForIntentBestHandler) {
+  AppServiceProxy proxy(nullptr);
+
+  const char kAppId1[] = "abcdefg";
+  const GURL kTestUrl = GURL("https://www.example.com/");
+
+  std::vector<AppPtr> apps;
+  // A scheme-only filter that will be excluded by the |exclude_browsers|
+  // parameter.
+  AppPtr app = std::make_unique<App>(AppType::kWeb, kAppId1);
+  app->readiness = Readiness::kReady;
+  app->handles_intents = true;
+  auto intent_filter = std::make_unique<apps::IntentFilter>();
+  intent_filter->AddSingleValueCondition(apps::ConditionType::kScheme,
+                                         kTestUrl.scheme(),
+                                         apps::PatternMatchType::kLiteral);
+  intent_filter->activity_name = "name 1";
+  intent_filter->activity_label = "same label";
+  app->intent_filters.push_back(std::move(intent_filter));
+
+  // A regular mime type file filter which we expect to match.
+  auto intent_filter2 = std::make_unique<apps::IntentFilter>();
+  intent_filter2->AddSingleValueCondition(apps::ConditionType::kAction,
+                                          apps_util::kIntentActionView,
+                                          apps::PatternMatchType::kLiteral);
+  intent_filter2->AddSingleValueCondition(apps::ConditionType::kFile,
+                                          "text/plain",
+                                          apps::PatternMatchType::kMimeType);
+  intent_filter2->activity_name = "name 2";
+  intent_filter2->activity_label = "same label";
+  app->intent_filters.push_back(std::move(intent_filter2));
+
+  apps.push_back(std::move(app));
+  proxy.OnApps(std::move(apps), AppType::kWeb, false);
+
+  std::vector<apps::IntentFilePtr> files;
+  auto file = std::make_unique<apps::IntentFile>(GURL("abc.txt"));
+  file->mime_type = "text/plain";
+  file->is_directory = false;
+  files.push_back(std::move(file));
+  apps::IntentPtr intent = std::make_unique<apps::Intent>(
+      apps_util::kIntentActionView, std::move(files));
+
+  std::vector<apps::IntentLaunchInfo> intent_launch_info =
+      proxy.GetAppsForIntent(intent, /*exclude_browsers=*/true);
+
+  // Check that we actually get back the 2nd filter, and not the excluded
+  // scheme-only filter which should have been discarded.
+  EXPECT_EQ(1U, intent_launch_info.size());
+  EXPECT_EQ("name 2", intent_launch_info[0].activity_name);
+}
+
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }  // namespace apps
diff --git a/chrome/browser/ash/arc/arc_util_unittest.cc b/chrome/browser/ash/arc/arc_util_unittest.cc
index ede72ab..be343b82 100644
--- a/chrome/browser/ash/arc/arc_util_unittest.cc
+++ b/chrome/browser/ash/arc/arc_util_unittest.cc
@@ -71,38 +71,10 @@
     command_line->AppendSwitch(switches::kTestType);
 }
 
-class FakeUserManagerWithLocalState : public ash::FakeChromeUserManager {
- public:
-  explicit FakeUserManagerWithLocalState(
-      TestingProfileManager* testing_profile_manager)
-      : testing_profile_manager_(testing_profile_manager),
-        test_local_state_(std::make_unique<TestingPrefServiceSimple>()) {
-    RegisterPrefs(test_local_state_->registry());
-  }
-
-  FakeUserManagerWithLocalState(const FakeUserManagerWithLocalState&) = delete;
-  FakeUserManagerWithLocalState& operator=(
-      const FakeUserManagerWithLocalState&) = delete;
-
-  PrefService* GetLocalState() const override {
-    return test_local_state_.get();
-  }
-
-  TestingProfileManager* testing_profile_manager() {
-    return testing_profile_manager_;
-  }
-
- private:
-  // Unowned pointer.
-  TestingProfileManager* const testing_profile_manager_;
-
-  std::unique_ptr<TestingPrefServiceSimple> test_local_state_;
-};
-
 class ScopedLogIn {
  public:
   ScopedLogIn(
-      FakeUserManagerWithLocalState* fake_user_manager,
+      ash::FakeChromeUserManager* fake_user_manager,
       const AccountId& account_id,
       user_manager::UserType user_type = user_manager::USER_TYPE_REGULAR)
       : fake_user_manager_(fake_user_manager), account_id_(account_id) {
@@ -149,7 +121,7 @@
     fake_user_manager_->LoginUser(account_id_);
   }
 
-  FakeUserManagerWithLocalState* fake_user_manager_;
+  ash::FakeChromeUserManager* fake_user_manager_;
   const AccountId account_id_;
 };
 
@@ -178,8 +150,7 @@
     ASSERT_TRUE(profile_manager_->SetUp());
 
     user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
-        std::make_unique<FakeUserManagerWithLocalState>(
-            profile_manager_.get()));
+        std::make_unique<ash::FakeChromeUserManager>());
 
     profile_ = profile_manager_->CreateTestingProfile(kTestProfileName);
   }
@@ -196,8 +167,8 @@
 
   TestingProfile* profile() { return profile_; }
 
-  FakeUserManagerWithLocalState* GetFakeUserManager() const {
-    return static_cast<FakeUserManagerWithLocalState*>(
+  ash::FakeChromeUserManager* GetFakeUserManager() const {
+    return static_cast<ash::FakeChromeUserManager*>(
         user_manager::UserManager::Get());
   }
 
diff --git a/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc b/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc
index a2dd2e4..dcd16d2 100644
--- a/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc
+++ b/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc
@@ -375,7 +375,6 @@
     }
 
     GetFakeUserManager()->LoginUser(account_id);
-    GetFakeUserManager()->CreateLocalState();
 
     // Create test profile.
     TestingProfile::Builder profile_builder;
diff --git a/chrome/browser/ash/assistant/assistant_util_unittest.cc b/chrome/browser/ash/assistant/assistant_util_unittest.cc
index 35274ce..afa4f24 100644
--- a/chrome/browser/ash/assistant/assistant_util_unittest.cc
+++ b/chrome/browser/ash/assistant/assistant_util_unittest.cc
@@ -46,38 +46,10 @@
   ~ScopedSpoofGoogleBrandedDevice() { OverrideIsGoogleDeviceForTesting(false); }
 };
 
-class FakeUserManagerWithLocalState : public ash::FakeChromeUserManager {
- public:
-  explicit FakeUserManagerWithLocalState(
-      TestingProfileManager* testing_profile_manager)
-      : testing_profile_manager_(testing_profile_manager),
-        test_local_state_(std::make_unique<TestingPrefServiceSimple>()) {
-    RegisterPrefs(test_local_state_->registry());
-  }
-
-  FakeUserManagerWithLocalState(const FakeUserManagerWithLocalState&) = delete;
-  FakeUserManagerWithLocalState& operator=(
-      const FakeUserManagerWithLocalState&) = delete;
-
-  PrefService* GetLocalState() const override {
-    return test_local_state_.get();
-  }
-
-  TestingProfileManager* testing_profile_manager() {
-    return testing_profile_manager_;
-  }
-
- private:
-  // Unowned pointer.
-  TestingProfileManager* const testing_profile_manager_;
-
-  std::unique_ptr<TestingPrefServiceSimple> test_local_state_;
-};
-
 class ScopedLogIn {
  public:
   ScopedLogIn(
-      FakeUserManagerWithLocalState* fake_user_manager,
+      ash::FakeChromeUserManager* fake_user_manager,
       signin::IdentityTestEnvironment* identity_test_env,
       const AccountId& account_id,
       user_manager::UserType user_type = user_manager::USER_TYPE_REGULAR)
@@ -179,7 +151,7 @@
     return account_id_.GetAccountType() == AccountType::GOOGLE;
   }
 
-  FakeUserManagerWithLocalState* fake_user_manager_;
+  ash::FakeChromeUserManager* fake_user_manager_;
   signin::IdentityTestEnvironment* identity_test_env_;
   const AccountId account_id_;
 };
@@ -209,8 +181,7 @@
     identity_test_env_adaptor_ =
         std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile_);
     user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
-        std::make_unique<FakeUserManagerWithLocalState>(
-            profile_manager_.get()));
+        std::make_unique<ash::FakeChromeUserManager>());
 
     ui::DeviceDataManager::CreateInstance();
   }
@@ -230,8 +201,8 @@
     return identity_test_env_adaptor_->identity_test_env();
   }
 
-  FakeUserManagerWithLocalState* GetFakeUserManager() const {
-    return static_cast<FakeUserManagerWithLocalState*>(
+  ash::FakeChromeUserManager* GetFakeUserManager() const {
+    return static_cast<ash::FakeChromeUserManager*>(
         user_manager::UserManager::Get());
   }
 
diff --git a/chrome/browser/ash/authpolicy/authpolicy_credentials_manager_unittest.cc b/chrome/browser/ash/authpolicy/authpolicy_credentials_manager_unittest.cc
index 3554e55..3d1ba631 100644
--- a/chrome/browser/ash/authpolicy/authpolicy_credentials_manager_unittest.cc
+++ b/chrome/browser/ash/authpolicy/authpolicy_credentials_manager_unittest.cc
@@ -38,8 +38,8 @@
 class AuthPolicyCredentialsManagerTest : public testing::Test {
  public:
   AuthPolicyCredentialsManagerTest()
-      : user_manager_enabler_(std::make_unique<FakeChromeUserManager>()),
-        local_state_(TestingBrowserProcess::GetGlobal()) {}
+      : local_state_(TestingBrowserProcess::GetGlobal()),
+        user_manager_enabler_(std::make_unique<FakeChromeUserManager>()) {}
 
   AuthPolicyCredentialsManagerTest(const AuthPolicyCredentialsManagerTest&) =
       delete;
@@ -118,6 +118,8 @@
   }
 
   content::BrowserTaskEnvironment task_environment_;
+  ScopedTestingLocalState local_state_;
+
   NetworkHandlerTestHelper network_handler_test_helper_;
   AccountId account_id_;
   std::unique_ptr<TestingProfile> profile_;
@@ -127,8 +129,6 @@
   user_manager::ScopedUserManager user_manager_enabler_;
 
   std::unique_ptr<NotificationDisplayServiceTester> display_service_;
-
-  ScopedTestingLocalState local_state_;
 };
 
 // Tests saving display and given name into user manager. No error means no
diff --git a/chrome/browser/ash/bruschetta/bruschetta_installer.cc b/chrome/browser/ash/bruschetta/bruschetta_installer.cc
index 0775f53..8c0d111 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_installer.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_installer.cc
@@ -16,15 +16,15 @@
     ENTRY(kUnknown);
     ENTRY(kSuccess);
     ENTRY(kInstallationProhibited);
-    ENTRY(kDlcInstallError);
+    ENTRY(kToolsDlcInstallError);
     ENTRY(kDownloadError);
-    ENTRY(kInvalidFirmware);
     ENTRY(kInvalidBootDisk);
     ENTRY(kInvalidPflash);
     ENTRY(kUnableToOpenImages);
     ENTRY(kCreateDiskError);
     ENTRY(kStartVmFailed);
     ENTRY(kInstallPflashError);
+    ENTRY(kFirmwareDlcInstallError);
   }
 #undef ENTRY
 #undef USTR
diff --git a/chrome/browser/ash/bruschetta/bruschetta_installer.h b/chrome/browser/ash/bruschetta/bruschetta_installer.h
index f74a68e4..389dc4b 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_installer.h
+++ b/chrome/browser/ash/bruschetta/bruschetta_installer.h
@@ -17,16 +17,17 @@
   kUnknown = 0,
   kSuccess = 1,
   kInstallationProhibited = 2,
-  kDlcInstallError = 3,
+  kToolsDlcInstallError = 3,
   kDownloadError = 4,
-  kInvalidFirmware = 5,
+  // Deprecated: kInvalidFirmware = 5,
   kInvalidBootDisk = 6,
   kInvalidPflash = 7,
   kUnableToOpenImages = 8,
   kCreateDiskError = 9,
   kStartVmFailed = 10,
   kInstallPflashError = 11,
-  kMaxValue = kInstallPflashError,
+  kFirmwareDlcInstallError = 12,
+  kMaxValue = kFirmwareDlcInstallError,
 };
 
 // Returns the string name of the BruschettaResult.
@@ -37,8 +38,8 @@
  public:
   enum class State {
     kInstallStarted,
-    kDlcInstall,
-    kFirmwareDownload,
+    kToolsDlcInstall,
+    kFirmwareDlcInstall,
     kBootDiskDownload,
     kPflashDownload,
     kOpenFiles,
diff --git a/chrome/browser/ash/bruschetta/bruschetta_installer_impl.cc b/chrome/browser/ash/bruschetta/bruschetta_installer_impl.cc
index 6737385..0aff278 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_installer_impl.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_installer_impl.cc
@@ -71,7 +71,6 @@
     )");
 
 std::unique_ptr<BruschettaInstallerImpl::Fds> OpenFdsBlocking(
-    base::FilePath firmware_path,
     base::FilePath boot_disk_path,
     base::FilePath pflash_path,
     base::FilePath profile_path);
@@ -79,9 +78,8 @@
 }  // namespace
 
 struct BruschettaInstallerImpl::Fds {
-  base::ScopedFD firmware;
   base::ScopedFD boot_disk;
-  base::ScopedFD pflash;
+  absl::optional<base::ScopedFD> pflash;
 };
 
 BruschettaInstallerImpl::BruschettaInstallerImpl(
@@ -144,8 +142,8 @@
 }
 
 void BruschettaInstallerImpl::InstallToolsDlc() {
-  VLOG(2) << "Installing DLC";
-  NotifyObserver(State::kDlcInstall);
+  VLOG(2) << "Installing tools DLC";
+  NotifyObserver(State::kToolsDlcInstall);
 
   dlcservice::InstallRequest request;
   request.set_id(kToolsDlc);
@@ -164,12 +162,41 @@
 
   if (install_result.error != dlcservice::kErrorNone) {
     install_running_ = false;
-    Error(BruschettaInstallResult::kDlcInstallError);
+    Error(BruschettaInstallResult::kToolsDlcInstallError);
     LOG(ERROR) << "Failed to install tools dlc: " << install_result.error;
     return;
   }
 
-  DownloadFirmware();
+  InstallFirmwareDlc();
+}
+
+void BruschettaInstallerImpl::InstallFirmwareDlc() {
+  VLOG(2) << "Installing firmware DLC";
+  NotifyObserver(State::kFirmwareDlcInstall);
+
+  dlcservice::InstallRequest request;
+  request.set_id(kUefiDlc);
+  ash::DlcserviceClient::Get()->Install(
+      request,
+      base::BindOnce(&BruschettaInstallerImpl::OnFirmwareDlcInstalled,
+                     weak_ptr_factory_.GetWeakPtr()),
+      base::DoNothing());
+}
+
+void BruschettaInstallerImpl::OnFirmwareDlcInstalled(
+    const ash::DlcserviceClient::InstallResult& install_result) {
+  if (MaybeClose()) {
+    return;
+  }
+
+  if (install_result.error != dlcservice::kErrorNone) {
+    install_running_ = false;
+    Error(BruschettaInstallResult::kFirmwareDlcInstallError);
+    LOG(ERROR) << "Failed to install firmware dlc: " << install_result.error;
+    return;
+  }
+
+  DownloadBootDisk();
 }
 
 void BruschettaInstallerImpl::StartDownload(GURL url,
@@ -238,43 +265,6 @@
   std::move(download_callback_).Run(completion_info);
 }
 
-void BruschettaInstallerImpl::DownloadFirmware() {
-  VLOG(2) << "Downloading firmware";
-  // We need to generate the download GUID before notifying because the tests
-  // need it to set the response.
-  download_guid_ = base::GUID::GenerateRandomV4();
-  NotifyObserver(State::kFirmwareDownload);
-
-  const std::string* url =
-      config_.FindDict(prefs::kPolicyUefiKey)->FindString(prefs::kPolicyURLKey);
-  StartDownload(GURL(*url),
-                base::BindOnce(&BruschettaInstallerImpl::OnFirmwareDownloaded,
-                               weak_ptr_factory_.GetWeakPtr()));
-}
-
-void BruschettaInstallerImpl::OnFirmwareDownloaded(
-    const download::CompletionInfo& completion_info) {
-  if (MaybeClose()) {
-    return;
-  }
-
-  const std::string* expected_hash = config_.FindDict(prefs::kPolicyUefiKey)
-                                         ->FindString(prefs::kPolicyHashKey);
-  if (!base::EqualsCaseInsensitiveASCII(completion_info.hash256,
-                                        *expected_hash)) {
-    install_running_ = false;
-    Error(BruschettaInstallResult::kInvalidFirmware);
-    LOG(ERROR) << "Downloaded firmware image has incorrect hash";
-    LOG(ERROR) << "Actual   " << completion_info.hash256;
-    LOG(ERROR) << "Expected " << *expected_hash;
-    return;
-  }
-
-  firmware_path_ = completion_info.path;
-
-  DownloadBootDisk();
-}
-
 void BruschettaInstallerImpl::DownloadBootDisk() {
   VLOG(2) << "Downloading boot disk";
   // We need to generate the download GUID before notifying because the tests
@@ -319,8 +309,15 @@
   download_guid_ = base::GUID::GenerateRandomV4();
   NotifyObserver(State::kPflashDownload);
 
-  const std::string* url = config_.FindDict(prefs::kPolicyPflashKey)
-                               ->FindString(prefs::kPolicyURLKey);
+  const base::Value::Dict* pflash = config_.FindDict(prefs::kPolicyPflashKey);
+  if (!pflash) {
+    VLOG(2) << "No pflash file set, skipping to OpenFds";
+
+    OpenFds();
+    return;
+  }
+
+  const std::string* url = pflash->FindString(prefs::kPolicyURLKey);
   StartDownload(GURL(*url),
                 base::BindOnce(&BruschettaInstallerImpl::OnPflashDownloaded,
                                weak_ptr_factory_.GetWeakPtr()));
@@ -355,8 +352,8 @@
 
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE, {base::MayBlock()},
-      base::BindOnce(&OpenFdsBlocking, firmware_path_, boot_disk_path_,
-                     pflash_path_, profile_->GetPath()),
+      base::BindOnce(&OpenFdsBlocking, boot_disk_path_, pflash_path_,
+                     profile_->GetPath()),
       base::BindOnce(&BruschettaInstallerImpl::OnOpenFds,
                      weak_ptr_factory_.GetWeakPtr()));
 }
@@ -364,38 +361,33 @@
 namespace {
 
 std::unique_ptr<BruschettaInstallerImpl::Fds> OpenFdsBlocking(
-    base::FilePath firmware_path,
     base::FilePath boot_disk_path,
     base::FilePath pflash_path,
     base::FilePath profile_path) {
-  auto firmware_dest_path = profile_path.Append(kBiosPath);
-  VLOG(2) << "Copying " << firmware_path << " -> " << firmware_dest_path;
-  if (!base::CopyFile(firmware_path, firmware_dest_path)) {
-    PLOG(ERROR) << "Failed to move firmware image to destination";
-    return nullptr;
-  }
-
-  base::File firmware(firmware_dest_path,
-                      base::File::FLAG_OPEN | base::File::FLAG_READ);
-  if (!firmware.IsValid()) {
-    PLOG(ERROR) << "Failed to open firmware";
-    return nullptr;
-  }
   base::File boot_disk(boot_disk_path,
                        base::File::FLAG_OPEN | base::File::FLAG_READ);
   if (!boot_disk.IsValid()) {
     PLOG(ERROR) << "Failed to open boot disk";
     return nullptr;
   }
-  base::File pflash(pflash_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
-  if (!pflash.IsValid()) {
-    PLOG(ERROR) << "Failed to open pflash";
-    return nullptr;
+
+  absl::optional<base::ScopedFD> pflash_fd;
+  if (pflash_path.empty()) {
+    pflash_fd = absl::nullopt;
+  } else {
+    base::File pflash(pflash_path,
+                      base::File::FLAG_OPEN | base::File::FLAG_READ);
+    if (!pflash.IsValid()) {
+      PLOG(ERROR) << "Failed to open pflash";
+      return nullptr;
+    }
+    pflash_fd = base::ScopedFD(pflash.TakePlatformFile());
   }
+
   BruschettaInstallerImpl::Fds fds{
-      .firmware = base::ScopedFD(firmware.TakePlatformFile()),
       .boot_disk = base::ScopedFD(boot_disk.TakePlatformFile()),
-      .pflash = base::ScopedFD(pflash.TakePlatformFile())};
+      .pflash = std::move(pflash_fd),
+  };
   return std::make_unique<BruschettaInstallerImpl::Fds>(std::move(fds));
 }
 }  // namespace
@@ -466,6 +458,12 @@
   VLOG(2) << "Installing pflash file for VM";
   NotifyObserver(State::kInstallPflash);
 
+  if (!fds_->pflash.has_value()) {
+    VLOG(2) << "No pflash file expected, skipping to StartVm";
+    StartVm();
+    return;
+  }
+
   auto* client = ash::ConciergeClient::Get();
   DCHECK(client) << "This code requires a ConciergeClient";
 
@@ -478,7 +476,7 @@
   request.set_vm_name(vm_name_);
 
   client->InstallPflash(
-      std::move(fds_->pflash), request,
+      std::move(*fds_->pflash), request,
       base::BindOnce(&BruschettaInstallerImpl::OnInstallPflash,
                      weak_ptr_factory_.GetWeakPtr()));
 }
@@ -533,6 +531,7 @@
   request.set_owner_id(std::move(user_hash));
   request.set_vm_username(vm_username);
   request.mutable_vm()->set_tools_dlc_id(kToolsDlc);
+  request.mutable_vm()->set_bios_dlc_id(kUefiDlc);
   request.set_start_termina(false);
   request.set_vtpm_proxy(launch_policy.vtpm_enabled);
 
@@ -547,18 +546,14 @@
 
   request.set_timeout(240);
 
-  // fds and request.fds must have the same order.
-  std::vector<base::ScopedFD> fds;
-  request.add_fds(vm_tools::concierge::StartVmRequest::BIOS);
-  fds.push_back(std::move(fds_->firmware));
   request.add_fds(vm_tools::concierge::StartVmRequest::STORAGE);
-  fds.push_back(std::move(fds_->boot_disk));
-  fds_.reset();
 
-  client->StartVmWithFds(
-      std::move(fds), request,
+  client->StartVmWithFd(
+      std::move(fds_->boot_disk), request,
       base::BindOnce(&BruschettaInstallerImpl::OnStartVm,
                      weak_ptr_factory_.GetWeakPtr(), launch_policy));
+
+  fds_.reset();
 }
 
 void BruschettaInstallerImpl::OnStartVm(
diff --git a/chrome/browser/ash/bruschetta/bruschetta_installer_impl.h b/chrome/browser/ash/bruschetta/bruschetta_installer_impl.h
index 77e439d..a03c33b 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_installer_impl.h
+++ b/chrome/browser/ash/bruschetta/bruschetta_installer_impl.h
@@ -56,8 +56,9 @@
   void InstallToolsDlc();
   void OnToolsDlcInstalled(
       const ash::DlcserviceClient::InstallResult& install_result);
-  void DownloadFirmware();
-  void OnFirmwareDownloaded(const download::CompletionInfo& completion_info);
+  void InstallFirmwareDlc();
+  void OnFirmwareDlcInstalled(
+      const ash::DlcserviceClient::InstallResult& install_result);
   void DownloadBootDisk();
   void OnBootDiskDownloaded(const download::CompletionInfo& completion_info);
   void DownloadPflash();
@@ -87,7 +88,6 @@
   base::GUID download_guid_;
   DownloadCallback download_callback_;
 
-  base::FilePath firmware_path_;
   base::FilePath boot_disk_path_;
   base::FilePath pflash_path_;
   std::string disk_path_;
diff --git a/chrome/browser/ash/bruschetta/bruschetta_installer_impl_unittest.cc b/chrome/browser/ash/bruschetta/bruschetta_installer_impl_unittest.cc
index 2736145794..2fe1a51 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_installer_impl_unittest.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_installer_impl_unittest.cc
@@ -45,7 +45,11 @@
 using testing::Sequence;
 
 // Total number of stopping points in ::ExpectStopOnStepN
-constexpr int kMaxSteps = 26;
+constexpr int kMaxSteps = 24;
+
+// Total number of stopping points in ::ExpectStopOnStepN when we don't install
+// a pflash file.
+constexpr int kMaxStepsNoPflash = kMaxSteps - 7;
 
 const char kVmName[] = "vm-name";
 const char kVmConfigId[] = "test-config-id";
@@ -85,22 +89,23 @@
     image.Set(prefs::kPolicyHashKey, kVmConfigHash);
     base::Value::List oem_strings;
     oem_strings.Append("OEM string");
+
     base::Value::Dict config;
-    config.Set(prefs::kPolicyEnabledKey,
-               static_cast<int>(prefs::PolicyEnabledState::INSTALL_ALLOWED));
-    config.Set(prefs::kPolicyNameKey, kVmConfigName);
-    config.Set(prefs::kPolicyVTPMKey, vtpm.Clone());
-    config.Set(prefs::kPolicyImageKey, image.Clone());
-    config.Set(prefs::kPolicyUefiKey, image.Clone());
-    config.Set(prefs::kPolicyPflashKey, image.Clone());
-    config.Set(prefs::kPolicyOEMStringsKey, oem_strings.Clone());
-    prefs_installable_.Set(kVmConfigId, config.Clone());
 
     config.Set(prefs::kPolicyEnabledKey,
                static_cast<int>(prefs::PolicyEnabledState::RUN_ALLOWED));
     config.Set(prefs::kPolicyNameKey, kVmConfigName);
     config.Set(prefs::kPolicyVTPMKey, vtpm.Clone());
-    prefs_not_installable_.Set(kVmConfigId, std::move(config));
+    config.Set(prefs::kPolicyOEMStringsKey, oem_strings.Clone());
+    prefs_not_installable_.Set(kVmConfigId, config.Clone());
+
+    config.Set(prefs::kPolicyEnabledKey,
+               static_cast<int>(prefs::PolicyEnabledState::INSTALL_ALLOWED));
+    config.Set(prefs::kPolicyImageKey, image.Clone());
+    prefs_installable_no_pflash_.Set(kVmConfigId, config.Clone());
+
+    config.Set(prefs::kPolicyPflashKey, image.Clone());
+    prefs_installable_.Set(kVmConfigId, config.Clone());
   }
 
   void SetUp() override {
@@ -255,7 +260,7 @@
   // Generate expectations and actions for a test that runs the install and
   // stops at the nth point where stopping is possible, returning true if the
   // stop is due to an error and false if the stop is a cancel. Passing in
-  // kMaxSteps means letting the install run to completion. If out_reuslt is
+  // kMaxSteps means letting the install run to completion. If out_result is
   // passed in, will set it to the expected result (as reported to the observer
   // + metrics).
   //
@@ -263,7 +268,8 @@
   // things.
   bool ExpectStopOnStepN(int n,
                          Sequence seq = {},
-                         BruschettaInstallResult* out_result = nullptr) {
+                         BruschettaInstallResult* out_result = nullptr,
+                         bool use_pflash = true) {
     // Policy check step
     {
       if (out_result) {
@@ -279,18 +285,24 @@
         return true;
       }
 
-      expectation.WillOnce(
-          InvokeWithoutArgs(PrefsCallback(prefs_installable_)));
+      if (use_pflash) {
+        expectation.WillOnce(
+            InvokeWithoutArgs(PrefsCallback(prefs_installable_)));
+      } else {
+        expectation.WillOnce(
+            InvokeWithoutArgs(PrefsCallback(prefs_installable_no_pflash_)));
+      }
     }
 
-    // DLC install step
+    // Tools DLC install step
     {
       if (out_result) {
-        *out_result = BruschettaInstallResult::kDlcInstallError;
+        *out_result = BruschettaInstallResult::kToolsDlcInstallError;
       }
       auto& expectation =
-          EXPECT_CALL(observer_,
-                      StateChanged(BruschettaInstaller::State::kDlcInstall))
+          EXPECT_CALL(
+              observer_,
+              StateChanged(BruschettaInstaller::State::kToolsDlcInstall))
               .Times(1)
               .InSequence(seq);
 
@@ -307,15 +319,15 @@
           InvokeWithoutArgs(DlcCallback(dlcservice::kErrorNone)));
     }
 
-    // Firmware image download step
+    // UEFI DLC install step
     {
       if (out_result) {
-        *out_result = BruschettaInstallResult::kDownloadError;
+        *out_result = BruschettaInstallResult::kFirmwareDlcInstallError;
       }
       auto& expectation =
           EXPECT_CALL(
               observer_,
-              StateChanged(BruschettaInstaller::State::kFirmwareDownload))
+              StateChanged(BruschettaInstaller::State::kFirmwareDlcInstall))
               .Times(1)
               .InSequence(seq);
 
@@ -324,22 +336,12 @@
         return false;
       }
       if (!n--) {
-        MakeErrorPoint(expectation, seq, DownloadErrorCallback(true));
-        return true;
-      }
-      if (!n--) {
-        MakeErrorPoint(expectation, seq, DownloadErrorCallback(false));
-        return true;
-      }
-      if (out_result) {
-        *out_result = BruschettaInstallResult::kInvalidFirmware;
-      }
-      if (!n--) {
-        MakeErrorPoint(expectation, seq, DownloadBadHashCallback());
+        MakeErrorPoint(expectation, seq, DlcCallback("Install Error"));
         return true;
       }
 
-      expectation.WillOnce(InvokeWithoutArgs(DownloadSuccessCallback()));
+      expectation.WillOnce(
+          InvokeWithoutArgs(DlcCallback(dlcservice::kErrorNone)));
     }
 
     // Boot disk download step
@@ -388,27 +390,29 @@
               .Times(1)
               .InSequence(seq);
 
-      if (!n--) {
-        expectation.WillOnce(CancelCallback());
-        return false;
-      }
-      if (!n--) {
-        MakeErrorPoint(expectation, seq, DownloadErrorCallback(true));
-        return true;
-      }
-      if (!n--) {
-        MakeErrorPoint(expectation, seq, DownloadErrorCallback(false));
-        return true;
-      }
-      if (out_result) {
-        *out_result = BruschettaInstallResult::kInvalidPflash;
-      }
-      if (!n--) {
-        MakeErrorPoint(expectation, seq, DownloadBadHashCallback());
-        return true;
-      }
+      if (use_pflash) {
+        if (!n--) {
+          expectation.WillOnce(CancelCallback());
+          return false;
+        }
+        if (!n--) {
+          MakeErrorPoint(expectation, seq, DownloadErrorCallback(true));
+          return true;
+        }
+        if (!n--) {
+          MakeErrorPoint(expectation, seq, DownloadErrorCallback(false));
+          return true;
+        }
+        if (out_result) {
+          *out_result = BruschettaInstallResult::kInvalidPflash;
+        }
+        if (!n--) {
+          MakeErrorPoint(expectation, seq, DownloadBadHashCallback());
+          return true;
+        }
 
-      expectation.WillOnce(InvokeWithoutArgs(DownloadSuccessCallback()));
+        expectation.WillOnce(InvokeWithoutArgs(DownloadSuccessCallback()));
+      }
     }
 
     // Open files step
@@ -470,20 +474,23 @@
               .Times(1)
               .InSequence(seq);
 
-      if (!n--) {
-        expectation.WillOnce(CancelCallback());
-        return false;
-      }
-      if (!n--) {
-        MakeErrorPoint(expectation, seq, InstallPflashCallback(absl::nullopt));
-        return true;
-      }
-      if (!n--) {
-        MakeErrorPoint(expectation, seq, InstallPflashCallback(false));
-        return true;
-      }
+      if (use_pflash) {
+        if (!n--) {
+          expectation.WillOnce(CancelCallback());
+          return false;
+        }
+        if (!n--) {
+          MakeErrorPoint(expectation, seq,
+                         InstallPflashCallback(absl::nullopt));
+          return true;
+        }
+        if (!n--) {
+          MakeErrorPoint(expectation, seq, InstallPflashCallback(false));
+          return true;
+        }
 
-      expectation.WillOnce(InvokeWithoutArgs(InstallPflashCallback(true)));
+        expectation.WillOnce(InvokeWithoutArgs(InstallPflashCallback(true)));
+      }
     }
 
     // Start VM step
@@ -541,7 +548,8 @@
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
   base::RunLoop run_loop_, run_loop_2_;
 
-  base::Value::Dict prefs_installable_, prefs_not_installable_;
+  base::Value::Dict prefs_installable_no_pflash_, prefs_installable_,
+      prefs_not_installable_;
 
   TestingProfile profile_;
   std::unique_ptr<BruschettaInstaller> installer_;
@@ -589,6 +597,17 @@
   EXPECT_FALSE(installer_);
 }
 
+TEST_F(BruschettaInstallerTest, InstallSuccessNoPflash) {
+  ExpectStopOnStepN(kMaxStepsNoPflash, {}, nullptr, false);
+
+  installer_->Install(kVmName, kVmConfigId);
+  run_loop_.Run();
+
+  histogram_tester_.ExpectBucketCount(kInstallResultMetric,
+                                      BruschettaInstallResult::kSuccess, 1);
+  EXPECT_FALSE(installer_);
+}
+
 TEST_F(BruschettaInstallerTest, TwoInstalls) {
   ExpectStopOnStepN(kMaxSteps);
 
@@ -629,6 +648,29 @@
   EXPECT_FALSE(installer_);
 }
 
+TEST_P(BruschettaInstallerTest, StopDuringInstallNoPflash) {
+  if (GetParam() > kMaxStepsNoPflash) {
+    GTEST_SKIP();
+  }
+
+  BruschettaInstallResult expected_result;
+  bool is_error = ExpectStopOnStepN(GetParam(), {}, &expected_result, false);
+
+  installer_->Install(kVmName, kVmConfigId);
+  run_loop_.Run();
+
+  if (is_error) {
+    // Installer should remain open in error state, tell it to close.
+    EXPECT_TRUE(installer_);
+    installer_->Cancel();
+    run_loop_2_.Run();
+
+    histogram_tester_.ExpectBucketCount(kInstallResultMetric, expected_result,
+                                        1);
+  }
+  EXPECT_FALSE(installer_);
+}
+
 TEST_P(BruschettaInstallerTest, ErrorAndRetry) {
   Sequence seq;
 
diff --git a/chrome/browser/ash/bruschetta/bruschetta_launcher.cc b/chrome/browser/ash/bruschetta/bruschetta_launcher.cc
index 85a41401..1a5eea8 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_launcher.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_launcher.cc
@@ -29,11 +29,6 @@
 
 namespace bruschetta {
 
-struct BruschettaLauncher::Files {
-  base::ScopedFD firmware;
-  absl::optional<base::ScopedFD> pflash;
-};
-
 namespace {
 
 // TODO(b/233289313): Once we have an installer and multiple Bruschettas this
@@ -42,47 +37,6 @@
 // people following the instructions will have (base64 encoded "bru").
 const char kDiskName[] = "YnJ1.img";
 
-const char kOldBiosPath[] = "Downloads/bios";
-
-// We currently support three different paths here, for backwards compatibility.
-// 1) A firmware image at kOldBiosPath with flash data embedded in the firmware
-// 2) A firmware image at kBiosPath with flash data at kPflashPath
-// 3) A firmware image at kBiosPath, with flash data handled by concierge
-//
-// TODO(b/265096855): Remove support for options 1&2 once they're no longer in
-// use.
-std::unique_ptr<BruschettaLauncher::Files> OpenFdsBlocking(
-    base::FilePath profile_path) {
-  base::File firmware(profile_path.Append(kBiosPath),
-                      base::File::FLAG_OPEN | base::File::FLAG_READ);
-  if (!firmware.IsValid()) {
-    firmware = base::File(profile_path.Append(kOldBiosPath),
-                          base::File::FLAG_OPEN | base::File::FLAG_READ);
-    if (!firmware.IsValid()) {
-      PLOG(ERROR) << "Failed to open firmware";
-      return nullptr;
-    }
-    BruschettaLauncher::Files files = {
-        .firmware = base::ScopedFD(firmware.TakePlatformFile()),
-        .pflash = absl::nullopt,
-    };
-    return std::make_unique<BruschettaLauncher::Files>(std::move(files));
-  }
-
-  base::File pflash(profile_path.Append(kPflashPath),
-                    base::File::FLAG_OPEN | base::File::FLAG_READ);
-
-  BruschettaLauncher::Files files = {
-      .firmware = base::ScopedFD(firmware.TakePlatformFile()),
-      .pflash = absl::nullopt,
-  };
-  if (pflash.IsValid()) {
-    files.pflash = base::ScopedFD(pflash.TakePlatformFile());
-  }
-
-  return std::make_unique<BruschettaLauncher::Files>(std::move(files));
-}
-
 }  // namespace
 
 BruschettaLauncher::BruschettaLauncher(std::string vm_name, Profile* profile)
@@ -98,7 +52,7 @@
   }
   callbacks_.AddUnsafe(std::move(callback));
   if (!launch_in_progress) {
-    EnsureDlcInstalled();
+    EnsureToolsDlcInstalled();
     // If we're not complete after 4 minutes time out the entire launch.
     base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
         FROM_HERE,
@@ -108,40 +62,49 @@
   }
 }
 
-void BruschettaLauncher::EnsureDlcInstalled() {
+void BruschettaLauncher::EnsureToolsDlcInstalled() {
   dlcservice::InstallRequest request;
   request.set_id(kToolsDlc);
   ash::DlcserviceClient::Get()->Install(
       request,
-      base::BindOnce(&BruschettaLauncher::OnMountDlc,
+      base::BindOnce(&BruschettaLauncher::OnMountToolsDlc,
                      weak_factory_.GetWeakPtr()),
       base::DoNothing());
 }
 
-void BruschettaLauncher::OnMountDlc(
+void BruschettaLauncher::OnMountToolsDlc(
     const ash::DlcserviceClient::InstallResult& install_result) {
   if (install_result.error != dlcservice::kErrorNone) {
-    LOG(ERROR) << "Error installing DLC: " << install_result.error;
+    LOG(ERROR) << "Error installing tools DLC: " << install_result.error;
     Finish(BruschettaResult::kDlcInstallError);
     return;
   }
 
-  // TODO(b/264495837, b/264495396): Eventually we should stop storing these
-  // files in the user's Downloads directory.
-  base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE, base::MayBlock(),
-      base::BindOnce(&OpenFdsBlocking, profile_->GetPath()),
-      base::BindOnce(&BruschettaLauncher::StartVm, weak_factory_.GetWeakPtr()));
+  EnsureFirmwareDlcInstalled();
 }
 
-void BruschettaLauncher::StartVm(
-    std::unique_ptr<BruschettaLauncher::Files> files) {
-  if (!files) {
-    LOG(ERROR) << "Error opening BIOS or pflash files";
-    Finish(BruschettaResult::kBiosNotAccessible);
+void BruschettaLauncher::EnsureFirmwareDlcInstalled() {
+  dlcservice::InstallRequest request;
+  request.set_id(kUefiDlc);
+  ash::DlcserviceClient::Get()->Install(
+      request,
+      base::BindOnce(&BruschettaLauncher::OnMountFirmwareDlc,
+                     weak_factory_.GetWeakPtr()),
+      base::DoNothing());
+}
+
+void BruschettaLauncher::OnMountFirmwareDlc(
+    const ash::DlcserviceClient::InstallResult& install_result) {
+  if (install_result.error != dlcservice::kErrorNone) {
+    LOG(ERROR) << "Error installing firmware DLC: " << install_result.error;
+    Finish(BruschettaResult::kDlcInstallError);
     return;
   }
 
+  StartVm();
+}
+
+void BruschettaLauncher::StartVm() {
   auto* client = ash::ConciergeClient::Get();
   if (!client) {
     LOG(ERROR) << "Error connecting to concierge. Client is NULL.";
@@ -170,33 +133,23 @@
   vm_tools::concierge::StartVmRequest request;
   request.set_start_termina(false);
   request.set_name(vm_name_);
-  *request.mutable_vm()->mutable_tools_dlc_id() = kToolsDlc;
-  *request.mutable_owner_id() = user_hash;
+  request.mutable_vm()->set_tools_dlc_id(kToolsDlc);
+  request.mutable_vm()->set_bios_dlc_id(kUefiDlc);
+  request.set_owner_id(user_hash);
   request.set_vm_username(vm_username);
   request.set_start_termina(false);
   request.set_timeout(240);
   request.set_vtpm_proxy(launch_policy.vtpm_enabled);
 
-  // fds and request.fds must have the same order.
-  std::vector<base::ScopedFD> fds;
-  request.add_fds(vm_tools::concierge::StartVmRequest::BIOS);
-  fds.push_back(std::move(files->firmware));
-  if (files->pflash) {
-    request.add_fds(vm_tools::concierge::StartVmRequest::PFLASH);
-    fds.push_back(std::move(*files->pflash));
-  }
-  files.reset();
-
   auto* disk = request.mutable_disks()->Add();
   *disk->mutable_path() =
       base::StrCat({"/run/daemon-store/crosvm/", user_hash, "/", kDiskName});
   disk->set_writable(true);
   disk->set_do_mount(false);
 
-  client->StartVmWithFds(
-      std::move(fds), request,
-      base::BindOnce(&BruschettaLauncher::OnStartVm, weak_factory_.GetWeakPtr(),
-                     launch_policy));
+  client->StartVm(request,
+                  base::BindOnce(&BruschettaLauncher::OnStartVm,
+                                 weak_factory_.GetWeakPtr(), launch_policy));
 }
 
 void BruschettaLauncher::OnStartVm(
diff --git a/chrome/browser/ash/bruschetta/bruschetta_launcher.h b/chrome/browser/ash/bruschetta/bruschetta_launcher.h
index 864d26a..8ad0826 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_launcher.h
+++ b/chrome/browser/ash/bruschetta/bruschetta_launcher.h
@@ -23,8 +23,6 @@
 // Launches Bruschetta. One instance per VM.
 class BruschettaLauncher {
  public:
-  struct Files;
-
   BruschettaLauncher(std::string vm_name, Profile* profile);
   virtual ~BruschettaLauncher();
   BruschettaLauncher(const BruschettaLauncher&) = delete;
@@ -40,14 +38,17 @@
   base::WeakPtr<BruschettaLauncher> GetWeakPtr();
 
  private:
-  void StartVm(std::unique_ptr<Files> files);
+  void StartVm();
   void OnStartVm(RunningVmPolicy launch_policy,
                  absl::optional<vm_tools::concierge::StartVmResponse> response);
 
-  base::File MaybeOpenBios();
+  void EnsureToolsDlcInstalled();
+  void OnMountToolsDlc(
+      const ash::DlcserviceClient::InstallResult& install_result);
 
-  void EnsureDlcInstalled();
-  void OnMountDlc(const ash::DlcserviceClient::InstallResult& install_result);
+  void EnsureFirmwareDlcInstalled();
+  void OnMountFirmwareDlc(
+      const ash::DlcserviceClient::InstallResult& install_result);
 
   void OnContainerRunning(guest_os::GuestInfo info);
 
diff --git a/chrome/browser/ash/bruschetta/bruschetta_launcher_unittest.cc b/chrome/browser/ash/bruschetta/bruschetta_launcher_unittest.cc
index f30800e..eafe3181 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_launcher_unittest.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_launcher_unittest.cc
@@ -55,7 +55,6 @@
 
     // We set up all our mocks to succeed, then failing tests explicitly break
     // the one thing they want to check the failure mode of.
-    ASSERT_TRUE(CreateTestFiles());
     vm_tools::concierge::StartVmResponse response;
     response.set_success(true);
     response.set_status(vm_tools::concierge::VmStatus::VM_STATUS_RUNNING);
@@ -79,18 +78,6 @@
         });
   }
 
-  bool CreateTestFiles() {
-    bios_path_ = profile_.GetPath().Append(kBiosPath);
-    base::File::Error error;
-    bool result =
-        base::CreateDirectoryAndGetError(bios_path_.DirName(), &error);
-    if (!result) {
-      LOG(ERROR) << "Error creating downloads folder: " << error;
-      return false;
-    }
-    return base::WriteFile(bios_path_, "");
-  }
-
   void SetupPrefs() {
     BruschettaService::GetForProfile(&profile_)->RegisterInPrefs(
         MakeBruschettaId(kTestVmName), kTestVmConfig);
@@ -127,15 +114,15 @@
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
   base::RunLoop run_loop_;
   TestingProfile profile_;
-  base::FilePath bios_path_;
   std::unique_ptr<BruschettaLauncher> launcher_;
   base::HistogramTester histogram_tester_{};
 };
 
 // Try to launch, but DLC service returns an error.
-TEST_F(BruschettaLauncherTest, LaunchDlcFailure) {
+TEST_F(BruschettaLauncherTest, LaunchToolsDlcFailure) {
   BruschettaResult result;
-  FakeDlcserviceClient()->set_install_error("Error installing");
+  FakeDlcserviceClient()->set_install_errors(base::circular_deque(
+      {std::string("Error installing"), std::string(dlcservice::kErrorNone)}));
 
   launcher_->EnsureRunning(StoreResultThenQuitRunLoop(&result));
   run_loop_.Run();
@@ -149,17 +136,18 @@
                    .contains(kTestVmName));
 }
 
-// Try to launch, but BIOS file doesn't exist.
-TEST_F(BruschettaLauncherTest, LaunchBiosNotAccessible) {
+// Try to launch, but DLC service returns an error.
+TEST_F(BruschettaLauncherTest, LaunchFirmwareDlcFailure) {
   BruschettaResult result;
-  ASSERT_TRUE(base::DeleteFile(bios_path_));
+  FakeDlcserviceClient()->set_install_errors(base::circular_deque(
+      {std::string(dlcservice::kErrorNone), std::string("Error installing")}));
 
   launcher_->EnsureRunning(StoreResultThenQuitRunLoop(&result));
   run_loop_.Run();
 
-  ASSERT_EQ(result, BruschettaResult::kBiosNotAccessible);
+  ASSERT_EQ(result, BruschettaResult::kDlcInstallError);
   histogram_tester_.ExpectUniqueSample(kLaunchHistogram,
-                                       BruschettaResult::kBiosNotAccessible, 1);
+                                       BruschettaResult::kDlcInstallError, 1);
 
   ASSERT_FALSE(BruschettaService::GetForProfile(&profile_)
                    ->GetRunningVmsForTesting()
diff --git a/chrome/browser/ash/bruschetta/bruschetta_policy_handler.cc b/chrome/browser/ash/bruschetta/bruschetta_policy_handler.cc
index 869ce8f3..ea616b8 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_policy_handler.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_policy_handler.cc
@@ -24,14 +24,12 @@
 #if defined(ARCH_CPU_X86_64)
 const char kPolicyImageKeyArchSpecific[] = "installer_image_x86_64";
 const char kPolicyPflashKeyArchSpecific[] = "uefi_pflash_x86_64";
-const char kPolicyUefiKeyArchSpecific[] = "uefi_image_x86_64";
 
 constexpr policy::PolicyMap::MessageType kUninstallableErrorLevel =
     policy::PolicyMap::MessageType::kError;
 #else
 const char kPolicyImageKeyArchSpecific[] = "";
 const char kPolicyPflashKeyArchSpecific[] = "";
-const char kPolicyUefiKeyArchSpecific[] = "";
 
 constexpr policy::PolicyMap::MessageType kUninstallableErrorLevel =
     policy::PolicyMap::MessageType::kInfo;
@@ -133,14 +131,6 @@
       }
     }
 
-    const auto* uefi_image = config.FindDict(kPolicyUefiKeyArchSpecific);
-    if (uefi_image) {
-      if (!CheckDownloadableObject(errors, id, kPolicyUefiKeyArchSpecific,
-                                   *uefi_image)) {
-        valid_config = false;
-      }
-    }
-
     const auto* pflash = config.FindDict(kPolicyPflashKeyArchSpecific);
     if (pflash) {
       if (!CheckDownloadableObject(errors, id, kPolicyPflashKeyArchSpecific,
@@ -151,7 +141,7 @@
 
     if (EnabledStrToEnum(*config.FindString(prefs::kPolicyEnabledKey)) ==
         prefs::PolicyEnabledState::INSTALL_ALLOWED) {
-      if (!installer_image || !uefi_image) {
+      if (!installer_image) {
         // This is an error on x86_64, since that's currently our *only*
         // supported architecture so this definitely indicates a
         // misconfiguration, but we also leave an informational level message
@@ -161,7 +151,7 @@
                          policy::PolicyErrorPath{id}, kUninstallableErrorLevel);
       }
 
-      if (!installer_image || !uefi_image || !valid_config) {
+      if (!installer_image || !valid_config) {
         downgraded_by_error_.insert(id);
       }
     }
@@ -217,13 +207,6 @@
     }
 
     {
-      const auto* uefi_image = config.FindDict(kPolicyUefiKeyArchSpecific);
-      if (uefi_image && installable) {
-        pref_config.Set(prefs::kPolicyUefiKey, uefi_image->Clone());
-      }
-    }
-
-    {
       const auto* pflash = config.FindDict(kPolicyPflashKeyArchSpecific);
       if (pflash && installable) {
         pref_config.Set(prefs::kPolicyPflashKey, pflash->Clone());
diff --git a/chrome/browser/ash/bruschetta/bruschetta_pref_names.cc b/chrome/browser/ash/bruschetta/bruschetta_pref_names.cc
index 16b0062..7d671a5 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_pref_names.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_pref_names.cc
@@ -16,7 +16,6 @@
 const char kPolicyEnabledKey[] = "enabled_state";
 const char kPolicyImageKey[] = "installer_image";
 const char kPolicyPflashKey[] = "uefi_pflash";
-const char kPolicyUefiKey[] = "uefi_image";
 const char kPolicyURLKey[] = "url";
 const char kPolicyHashKey[] = "hash";
 const char kPolicyVTPMKey[] = "vtpm";
diff --git a/chrome/browser/ash/bruschetta/bruschetta_pref_names.h b/chrome/browser/ash/bruschetta/bruschetta_pref_names.h
index 0a12db2..a021601 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_pref_names.h
+++ b/chrome/browser/ash/bruschetta/bruschetta_pref_names.h
@@ -18,7 +18,6 @@
 extern const char kPolicyEnabledKey[];
 extern const char kPolicyImageKey[];
 extern const char kPolicyPflashKey[];
-extern const char kPolicyUefiKey[];
 extern const char kPolicyURLKey[];
 extern const char kPolicyHashKey[];
 extern const char kPolicyVTPMKey[];
diff --git a/chrome/browser/ash/bruschetta/bruschetta_service.cc b/chrome/browser/ash/bruschetta/bruschetta_service.cc
index 60cea7c8..7bd750c 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_service.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_service.cc
@@ -300,20 +300,38 @@
     return;
   }
   ash::DlcserviceClient::Get()->Uninstall(
-      kToolsDlc, base::BindOnce(&BruschettaService::OnUninstallDlc,
+      kToolsDlc, base::BindOnce(&BruschettaService::OnUninstallToolsDlc,
                                 weak_ptr_factory_.GetWeakPtr(),
                                 std::move(callback), std::move(guest_id)));
 }
 
-void BruschettaService::OnUninstallDlc(base::OnceCallback<void(bool)> callback,
-                                       guest_os::GuestId guest_id,
-                                       const std::string& result) {
-  if (result != dlcservice::kErrorNone &&
-      result != dlcservice::kErrorInvalidDlc) {
-    LOG(ERROR) << "Error removing DLC. Error: " << result;
+void BruschettaService::OnUninstallToolsDlc(
+    base::OnceCallback<void(bool)> callback,
+    guest_os::GuestId guest_id,
+    const std::string& result) {
+  ash::DlcserviceClient::Get()->Uninstall(
+      kUefiDlc,
+      base::BindOnce(&BruschettaService::OnUninstallAllDlcs,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+                     std::move(guest_id), result));
+}
+
+void BruschettaService::OnUninstallAllDlcs(
+    base::OnceCallback<void(bool)> callback,
+    guest_os::GuestId guest_id,
+    const std::string& tools_result,
+    const std::string& firmware_result) {
+  if ((tools_result != dlcservice::kErrorNone &&
+       tools_result != dlcservice::kErrorInvalidDlc) ||
+      (firmware_result != dlcservice::kErrorNone &&
+       firmware_result != dlcservice::kErrorInvalidDlc)) {
+    LOG(ERROR) << "Error removing bruschetta DLCs";
+    LOG(ERROR) << kToolsDlc << ": " << tools_result;
+    LOG(ERROR) << kUefiDlc << ": " << firmware_result;
     std::move(callback).Run(false);
     return;
   }
+
   profile_->GetPrefs()->SetBoolean(bruschetta::prefs::kBruschettaInstalled,
                                    false);
 
diff --git a/chrome/browser/ash/bruschetta/bruschetta_service.h b/chrome/browser/ash/bruschetta/bruschetta_service.h
index 8b8d324..241cd7b 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_service.h
+++ b/chrome/browser/ash/bruschetta/bruschetta_service.h
@@ -97,9 +97,13 @@
   void OnRemoveVm(base::OnceCallback<void(bool)> callback,
                   guest_os::GuestId guest_id,
                   guest_os::GuestOsRemover::Result result);
-  void OnUninstallDlc(base::OnceCallback<void(bool)> callback,
-                      guest_os::GuestId guest_id,
-                      const std::string& result);
+  void OnUninstallToolsDlc(base::OnceCallback<void(bool)> callback,
+                           guest_os::GuestId guest_id,
+                           const std::string& result);
+  void OnUninstallAllDlcs(base::OnceCallback<void(bool)> callback,
+                          guest_os::GuestId guest_id,
+                          const std::string& tools_result,
+                          const std::string& firmware_result);
 
   base::flat_map<std::string, VmRegistration> runnable_vms_;
   base::flat_map<std::string, RunningVmPolicy> running_vms_;
diff --git a/chrome/browser/ash/bruschetta/bruschetta_util.cc b/chrome/browser/ash/bruschetta/bruschetta_util.cc
index 04b26cc..83dfc43 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_util.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_util.cc
@@ -34,13 +34,11 @@
 }  // namespace
 
 const char kToolsDlc[] = "termina-tools-dlc";
+const char kUefiDlc[] = "edk2-ovmf-dlc";
 
 const char kBruschettaVmName[] = "bru";
 const char kBruschettaDisplayName[] = "Bruschetta";
 
-const char kBiosPath[] = "Downloads/CROSVM_CODE.fd";
-const char kPflashPath[] = "Downloads/CROSVM_VARS.google.fd";
-
 const char kBruschettaPolicyId[] = "glinux-latest";
 
 const char* BruschettaResultString(const BruschettaResult res) {
@@ -51,7 +49,6 @@
     ENTRY(kUnknown);
     ENTRY(kSuccess);
     ENTRY(kDlcInstallError);
-    ENTRY(kBiosNotAccessible);
     ENTRY(kStartVmFailed);
     ENTRY(kTimeout);
     ENTRY(kForbiddenByPolicy);
diff --git a/chrome/browser/ash/bruschetta/bruschetta_util.h b/chrome/browser/ash/bruschetta/bruschetta_util.h
index 6c983498a..aff87cf7 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_util.h
+++ b/chrome/browser/ash/bruschetta/bruschetta_util.h
@@ -15,13 +15,11 @@
 namespace bruschetta {
 
 extern const char kToolsDlc[];
+extern const char kUefiDlc[];
 
 extern const char kBruschettaVmName[];
 extern const char kBruschettaDisplayName[];
 
-extern const char kBiosPath[];
-extern const char kPflashPath[];
-
 extern const char kBruschettaPolicyId[];
 
 // These values are persisted to logs. Entries should not be renumbered and
@@ -30,7 +28,7 @@
   kUnknown = 0,
   kSuccess = 1,
   kDlcInstallError = 2,
-  kBiosNotAccessible = 3,
+  // Deprecated: kBiosNotAccessible = 3
   kStartVmFailed = 4,
   kTimeout = 5,
   kForbiddenByPolicy = 6,
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc b/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc
index 351c6e16..857c41cf 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc
+++ b/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc
@@ -24,6 +24,8 @@
 #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/common/chrome_constants.h"
+#include "chrome/test/base/scoped_testing_local_state.h"
+#include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/user_manager/fake_user_manager.h"
@@ -232,14 +234,6 @@
     fake_user_manager_ = new ash::FakeChromeUserManager;
     scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
         base::WrapUnique(fake_user_manager_));
-    fake_user_manager_->CreateLocalState();
-
-    auto* local_state_simple =
-        static_cast<TestingPrefServiceSimple*>(local_state());
-    BrowserDataMigratorImpl::RegisterLocalStatePrefs(
-        local_state_simple->registry());
-    crosapi::browser_util::RegisterLocalStatePrefs(
-        local_state_simple->registry());
   }
 
   void AddRegularUser(const std::string& email) {
@@ -259,6 +253,8 @@
 
  private:
   content::BrowserTaskEnvironment task_environment_;
+  ScopedTestingLocalState scoped_local_state_{
+      TestingBrowserProcess::GetGlobal()};
   TestingProfile testing_profile_;
   ash::FakeChromeUserManager* fake_user_manager_ = nullptr;
   std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
diff --git a/chrome/browser/ash/crosapi/crosapi_util.cc b/chrome/browser/ash/crosapi/crosapi_util.cc
index 3ad8197..3a93d5c 100644
--- a/chrome/browser/ash/crosapi/crosapi_util.cc
+++ b/chrome/browser/ash/crosapi/crosapi_util.cc
@@ -109,6 +109,7 @@
 #include "chromeos/crosapi/mojom/probe_service.mojom.h"
 #include "chromeos/crosapi/mojom/remoting.mojom.h"
 #include "chromeos/crosapi/mojom/screen_manager.mojom.h"
+#include "chromeos/crosapi/mojom/select_file.mojom.h"
 #include "chromeos/crosapi/mojom/sharesheet.mojom.h"
 #include "chromeos/crosapi/mojom/smart_reader.mojom.h"
 #include "chromeos/crosapi/mojom/speech_recognition.mojom.h"
@@ -124,6 +125,7 @@
 #include "chromeos/crosapi/mojom/video_capture.mojom.h"
 #include "chromeos/crosapi/mojom/video_conference.mojom.h"
 #include "chromeos/crosapi/mojom/virtual_keyboard.mojom.h"
+#include "chromeos/crosapi/mojom/volume_manager.mojom.h"
 #include "chromeos/crosapi/mojom/vpn_extension_observer.mojom.h"
 #include "chromeos/crosapi/mojom/vpn_service.mojom.h"
 #include "chromeos/crosapi/mojom/wallpaper.mojom.h"
@@ -277,6 +279,7 @@
     MakeInterfaceVersionEntry<crosapi::mojom::AudioService>(),
     MakeInterfaceVersionEntry<crosapi::mojom::Authentication>(),
     MakeInterfaceVersionEntry<crosapi::mojom::Automation>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::AutomationFactory>(),
     MakeInterfaceVersionEntry<crosapi::mojom::AccountManager>(),
     MakeInterfaceVersionEntry<crosapi::mojom::AppPublisher>(),
     MakeInterfaceVersionEntry<crosapi::mojom::AppServiceProxy>(),
@@ -350,6 +353,7 @@
     MakeInterfaceVersionEntry<crosapi::mojom::ResourceManager>(),
     MakeInterfaceVersionEntry<crosapi::mojom::ScreenManager>(),
     MakeInterfaceVersionEntry<crosapi::mojom::SearchControllerRegistry>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::SelectFile>(),
     MakeInterfaceVersionEntry<crosapi::mojom::Sharesheet>(),
     MakeInterfaceVersionEntry<crosapi::mojom::SmartReaderClient>(),
     MakeInterfaceVersionEntry<crosapi::mojom::SpeechRecognition>(),
@@ -365,6 +369,7 @@
     MakeInterfaceVersionEntry<crosapi::mojom::VideoCaptureDeviceFactory>(),
     MakeInterfaceVersionEntry<crosapi::mojom::VideoConferenceManager>(),
     MakeInterfaceVersionEntry<crosapi::mojom::VirtualKeyboard>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::VolumeManager>(),
     MakeInterfaceVersionEntry<crosapi::mojom::VpnExtensionObserver>(),
     MakeInterfaceVersionEntry<crosapi::mojom::VpnService>(),
     MakeInterfaceVersionEntry<crosapi::mojom::Wallpaper>(),
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest.cc b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
index 029576c4c..52abf15 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
@@ -1578,12 +1578,8 @@
     ::testing::Values(
         TestCase("transferFromDriveToDownloads")
             .FeatureIds({"screenplay-9e3628b5-86db-481f-8623-f13eac08d61a"}),
-// TODO(crbug.com/1425820), TODO(crbug.com/1428909): Re-enable this test.
-#if !defined(LEAK_SANITIZER) || !BUILDFLAG(IS_CHROMEOS) || \
-    !defined(ADDRESS_SANITIZER)
         TestCase("transferOfficeFileFromDriveToDownloads")
             .FeatureIds({"screenplay-9e3628b5-86db-481f-8623-f13eac08d61a"}),
-#endif
         TestCase("transferFromDownloadsToMyFiles")
             .FeatureIds({"screenplay-9e3628b5-86db-481f-8623-f13eac08d61a"}),
         TestCase("transferFromDownloadsToMyFilesMove")
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
index 03aaa08..feb0445 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
@@ -3136,9 +3136,9 @@
     web_contents = swa_web_contents_[*app_id];
 
     absl::optional<bool> leftClick = value.FindBool("leftClick");
-    ASSERT_TRUE(leftClick);
-    auto button = leftClick ? blink::WebMouseEvent::Button::kLeft
-                            : blink::WebMouseEvent::Button::kRight;
+    ASSERT_TRUE(leftClick.has_value());
+    auto button = leftClick.value() ? blink::WebMouseEvent::Button::kLeft
+                                    : blink::WebMouseEvent::Button::kRight;
     SimulateMouseClickAt(web_contents, 0 /* modifiers */, button,
                          gfx::Point(*click_x, *click_y));
     return;
diff --git a/chrome/browser/ash/file_manager/file_tasks.cc b/chrome/browser/ash/file_manager/file_tasks.cc
index 941fcc3..e1b3b82 100644
--- a/chrome/browser/ash/file_manager/file_tasks.cc
+++ b/chrome/browser/ash/file_manager/file_tasks.cc
@@ -109,7 +109,6 @@
     "open-web-drive-office-powerpoint";
 const char kActionIdOpenInOffice[] = "open-in-office";
 const char kActionIdOpenWeb[] = "OPEN_WEB";
-const char kODFSExtensionId[] = "gnnndjlaomemikopnjhhnoombakkkkdg";
 
 // Searches for the installed extension in order of preference.
 std::string GetODFSExtensionId(Profile* profile) {
@@ -124,8 +123,8 @@
     const auto& extension_id = provider_id.GetExtensionId();
 
     // App from official internal build.
-    if (extension_id == kODFSExtensionId) {
-      return kODFSExtensionId;
+    if (extension_id == extension_misc::kODFSExtensionId) {
+      return extension_misc::kODFSExtensionId;
     }
 
     // App built manually from internal repo.
diff --git a/chrome/browser/ash/file_manager/file_tasks.h b/chrome/browser/ash/file_manager/file_tasks.h
index d0eab61..c1df7ddc 100644
--- a/chrome/browser/ash/file_manager/file_tasks.h
+++ b/chrome/browser/ash/file_manager/file_tasks.h
@@ -131,8 +131,6 @@
 extern const char kActionIdOpenInOffice[];
 extern const char kActionIdOpenWeb[];
 
-extern const char kODFSExtensionId[];
-
 // Checks which extension is installed and return the latest one installed or ""
 // if none is installed
 std::string GetODFSExtensionId(Profile* profile);
diff --git a/chrome/browser/ash/file_manager/file_tasks_browsertest.cc b/chrome/browser/ash/file_manager/file_tasks_browsertest.cc
index 699ae79..e386a5d5 100644
--- a/chrome/browser/ash/file_manager/file_tasks_browsertest.cc
+++ b/chrome/browser/ash/file_manager/file_tasks_browsertest.cc
@@ -61,6 +61,7 @@
 #include "chrome/browser/web_applications/web_app_registry_update.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
 #include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/mixin_based_in_process_browser_test.h"
@@ -1413,9 +1414,10 @@
     // `FakeProvidedFileSystemOneDrive`. The use of `base::Unretained()` is safe
     // because the class will exist for the duration of the test.
     service_->RegisterProvider(FakeExtensionProviderOneDrive::Create(
-        kODFSExtensionId, test_path_within_odfs_, test_file_name_));
+        extension_misc::kODFSExtensionId, test_path_within_odfs_,
+        test_file_name_));
     provider_id_ = ash::file_system_provider::ProviderId::CreateFromExtensionId(
-        kODFSExtensionId);
+        extension_misc::kODFSExtensionId);
     ash::file_system_provider::MountOptions options(file_system_id_, "ODFS");
     EXPECT_EQ(base::File::FILE_OK,
               service_->MountFileSystem(provider_id_, options));
diff --git a/chrome/browser/ash/input_method/input_method_settings.cc b/chrome/browser/ash/input_method/input_method_settings.cc
index 0fe913e..0fbf285e 100644
--- a/chrome/browser/ash/input_method/input_method_settings.cc
+++ b/chrome/browser/ash/input_method/input_method_settings.cc
@@ -9,6 +9,7 @@
 #include "base/containers/fixed_flat_set.h"
 #include "base/feature_list.h"
 #include "base/no_destructor.h"
+#include "base/strings/string_piece.h"
 #include "chrome/browser/ash/input_method/autocorrect_enums.h"
 #include "chrome/browser/ash/input_method/autocorrect_prefs.h"
 #include "chrome/common/pref_names.h"
@@ -154,6 +155,14 @@
   return engine_id == "zh-hant-t-i0-und";
 }
 
+bool IsVietnameseTelexEngine(base::StringPiece engine_id) {
+  return engine_id == "vkd_vi_telex";
+}
+
+bool IsVietnameseVniEngine(base::StringPiece engine_id) {
+  return engine_id == "vkd_vi_vni";
+}
+
 mojom::LatinSettingsPtr CreateLatinSettings(
     const base::Value::Dict& input_method_specific_pref,
     const PrefService& prefs,
@@ -506,6 +515,14 @@
     return mojom::InputMethodSettings::NewZhuyinSettings(
         CreateZhuyinSettings(input_method_specific_pref));
   }
+  if (IsVietnameseTelexEngine(engine_id)) {
+    return mojom::InputMethodSettings::NewVietnameseTelexSettings(
+        mojom::VietnameseTelexSettings::New());
+  }
+  if (IsVietnameseVniEngine(engine_id)) {
+    return mojom::InputMethodSettings::NewVietnameseVniSettings(
+        mojom::VietnameseVniSettings::New());
+  }
   // TODO(b/232341104): Add the code to send the Japanese settings to
   // the engine if the engine_id is nacl_mozc_jp or nacl_mozc_us.
   // This will do the inverse of ConvertConfigToJapaneseSettings.
diff --git a/chrome/browser/ash/input_method/input_method_settings_unittest.cc b/chrome/browser/ash/input_method/input_method_settings_unittest.cc
index 6dd7ed7..fb83d1bd 100644
--- a/chrome/browser/ash/input_method/input_method_settings_unittest.cc
+++ b/chrome/browser/ash/input_method/input_method_settings_unittest.cc
@@ -31,6 +31,9 @@
 
 constexpr char kJapaneseEngineId[] = "nacl_mozc_jp";
 
+constexpr char kVietnameseVniEngineId[] = "vkd_vi_vni";
+constexpr char kVietnameseTelexEngineId[] = "vkd_vi_telex";
+
 // This should be kept in sync with the values on the settings page's
 // InputMethodOptions. This should match
 // https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.js;l=71-88;drc=6c88edbfe6096489ccac66b3ef5c84d479892181.
@@ -745,6 +748,27 @@
   EXPECT_EQ(zhuyin_settings.page_size, 10u);
 }
 
+TEST(CreateSettingsFromPrefsTest, CreateVietnameseVniSettings) {
+  base::Value::Dict dict;
+  TestingPrefServiceSimple prefs;
+  RegisterTestingPrefs(prefs, dict);
+
+  const auto settings = CreateSettingsFromPrefs(prefs, kVietnameseVniEngineId);
+
+  ASSERT_TRUE(settings->is_vietnamese_vni_settings());
+}
+
+TEST(CreateSettingsFromPrefsTest, CreateVietnameseTelexSettings) {
+  base::Value::Dict dict;
+  TestingPrefServiceSimple prefs;
+  RegisterTestingPrefs(prefs, dict);
+
+  const auto settings =
+      CreateSettingsFromPrefs(prefs, kVietnameseTelexEngineId);
+
+  ASSERT_TRUE(settings->is_vietnamese_telex_settings());
+}
+
 TEST(CreateSettingsFromPrefsTest, CreateZhuyinSettings) {
   base::Value::Dict dict;
   dict.SetByDottedPath(base::StrCat({kZhuyinEngineId, ".zhuyinKeyboardLayout"}),
diff --git a/chrome/browser/ash/login/saml/password_sync_token_login_checker_unittest.cc b/chrome/browser/ash/login/saml/password_sync_token_login_checker_unittest.cc
index 118a24ac..431384d 100644
--- a/chrome/browser/ash/login/saml/password_sync_token_login_checker_unittest.cc
+++ b/chrome/browser/ash/login/saml/password_sync_token_login_checker_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/time/default_clock.h"
 #include "chrome/browser/ash/login/saml/password_sync_token_checkers_collection.h"
 #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
+#include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "components/user_manager/user_names.h"
@@ -24,22 +25,6 @@
 
 constexpr base::TimeDelta kSamlTokenDelay = base::Seconds(60);
 
-class FakeUserManagerWithLocalState : public FakeChromeUserManager {
- public:
-  FakeUserManagerWithLocalState()
-      : test_local_state_(std::make_unique<TestingPrefServiceSimple>()) {
-    RegisterPrefs(test_local_state_->registry());
-  }
-  ~FakeUserManagerWithLocalState() override = default;
-
-  PrefService* GetLocalState() const override {
-    return test_local_state_.get();
-  }
-
- private:
-  std::unique_ptr<TestingPrefServiceSimple> test_local_state_;
-};
-
 }  // namespace
 
 class PasswordSyncTokenLoginCheckerTest : public testing::Test {
@@ -57,15 +42,16 @@
       base::test::TaskEnvironment::MainThreadType::UI,
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
 
+  ScopedTestingLocalState scoped_local_state_;
   std::unique_ptr<net::BackoffEntry> sync_token_retry_backoff_;
   FakeChromeUserManager* user_manager_ = nullptr;
   std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
   std::unique_ptr<PasswordSyncTokenLoginChecker> checker_;
 };
 
-PasswordSyncTokenLoginCheckerTest::PasswordSyncTokenLoginCheckerTest() {
-  std::unique_ptr<FakeChromeUserManager> fake_user_manager =
-      std::make_unique<FakeUserManagerWithLocalState>();
+PasswordSyncTokenLoginCheckerTest::PasswordSyncTokenLoginCheckerTest()
+    : scoped_local_state_(TestingBrowserProcess::GetGlobal()) {
+  auto fake_user_manager = std::make_unique<FakeChromeUserManager>();
   scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
       std::move(fake_user_manager));
 
diff --git a/chrome/browser/ash/login/test/local_state_mixin.cc b/chrome/browser/ash/login/test/local_state_mixin.cc
index bfc70af..8c30390 100644
--- a/chrome/browser/ash/login/test/local_state_mixin.cc
+++ b/chrome/browser/ash/login/test/local_state_mixin.cc
@@ -28,8 +28,8 @@
     // be updated, and do ephemeral user checks.
     // Given that user manager does not exist yet (by design), create a
     // temporary fake user manager instance.
-    auto user_manager = std::make_unique<user_manager::FakeUserManager>();
-    user_manager->set_local_state(g_browser_process->local_state());
+    auto user_manager = std::make_unique<user_manager::FakeUserManager>(
+        g_browser_process->local_state());
     user_manager::ScopedUserManager scoper(std::move(user_manager));
     delegate_->SetUpLocalStateBase();
   }
diff --git a/chrome/browser/ash/login/users/chrome_user_manager.cc b/chrome/browser/ash/login/users/chrome_user_manager.cc
index c410668a..3781c41 100644
--- a/chrome/browser/ash/login/users/chrome_user_manager.cc
+++ b/chrome/browser/ash/login/users/chrome_user_manager.cc
@@ -34,9 +34,11 @@
 
 ChromeUserManager::ChromeUserManager(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-    : UserManagerBase(std::move(task_runner)) {}
+    : UserManagerBase(
+          std::move(task_runner),
+          g_browser_process ? g_browser_process->local_state() : nullptr) {}
 
-ChromeUserManager::~ChromeUserManager() {}
+ChromeUserManager::~ChromeUserManager() = default;
 
 // static
 void ChromeUserManager::RegisterPrefs(PrefRegistrySimple* registry) {
diff --git a/chrome/browser/ash/login/users/chrome_user_manager_impl.cc b/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
index b4724af..cbe74c5e 100644
--- a/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
@@ -687,10 +687,6 @@
   return g_browser_process->GetApplicationLocale();
 }
 
-PrefService* ChromeUserManagerImpl::GetLocalState() const {
-  return g_browser_process ? g_browser_process->local_state() : nullptr;
-}
-
 bool ChromeUserManagerImpl::IsEnterpriseManaged() const {
   policy::BrowserPolicyConnectorAsh* connector =
       g_browser_process->platform_part()->browser_policy_connector_ash();
diff --git a/chrome/browser/ash/login/users/chrome_user_manager_impl.h b/chrome/browser/ash/login/users/chrome_user_manager_impl.h
index db56361..7a71779 100644
--- a/chrome/browser/ash/login/users/chrome_user_manager_impl.h
+++ b/chrome/browser/ash/login/users/chrome_user_manager_impl.h
@@ -34,7 +34,6 @@
 #include "components/user_manager/user.h"
 
 class PrefRegistrySimple;
-class PrefService;
 
 namespace gfx {
 class ImageSkia;
@@ -143,7 +142,6 @@
 
  protected:
   const std::string& GetApplicationLocale() const override;
-  PrefService* GetLocalState() const override;
   void LoadDeviceLocalAccounts(std::set<AccountId>* users_set) override;
   void NotifyOnLogin() override;
   void NotifyUserAddedToSession(const user_manager::User* added_user,
diff --git a/chrome/browser/ash/login/users/fake_chrome_user_manager.cc b/chrome/browser/ash/login/users/fake_chrome_user_manager.cc
index 5ac2e59..b54adf9 100644
--- a/chrome/browser/ash/login/users/fake_chrome_user_manager.cc
+++ b/chrome/browser/ash/login/users/fake_chrome_user_manager.cc
@@ -662,11 +662,6 @@
   return true;
 }
 
-void FakeChromeUserManager::CreateLocalState() {
-  local_state_ = std::make_unique<TestingPrefServiceSimple>();
-  ChromeUserManager::RegisterPrefs(local_state_->registry());
-}
-
 void FakeChromeUserManager::SimulateUserProfileLoad(
     const AccountId& account_id) {
   for (auto* user : users_) {
@@ -677,13 +672,6 @@
   }
 }
 
-PrefService* FakeChromeUserManager::GetLocalState() const {
-  if (local_state_.get()) {
-    return local_state_.get();
-  }
-  return g_browser_process ? g_browser_process->local_state() : nullptr;
-}
-
 void FakeChromeUserManager::SetIsCurrentUserNew(bool is_new) {
   NOTREACHED();
 }
diff --git a/chrome/browser/ash/login/users/fake_chrome_user_manager.h b/chrome/browser/ash/login/users/fake_chrome_user_manager.h
index 8b25174..b6cead5 100644
--- a/chrome/browser/ash/login/users/fake_chrome_user_manager.h
+++ b/chrome/browser/ash/login/users/fake_chrome_user_manager.h
@@ -68,10 +68,6 @@
       user_manager::UserType user_type,
       TestingProfile* profile);
 
-  // Creates the instance returned by `GetLocalState()` (which returns nullptr
-  // by default).
-  void CreateLocalState();
-
   // Sets the user profile created flag to simulate finishing user
   // profile loading. Note this does not create a profile.
   void SimulateUserProfileLoad(const AccountId& account_id);
@@ -134,7 +130,6 @@
   bool IsGaiaUserAllowed(const user_manager::User& user) const override;
   bool IsUserAllowed(const user_manager::User& user) const override;
   bool IsEphemeralAccountId(const AccountId& account_id) const override;
-  PrefService* GetLocalState() const override;
   const AccountId& GetGuestAccountId() const override;
   bool IsFirstExecAfterBoot() const override;
   void AsyncRemoveCryptohome(const AccountId& account_id) const override;
@@ -250,8 +245,6 @@
 
   using FlowMap = std::map<AccountId, UserFlow*>;
 
-  std::unique_ptr<TestingPrefServiceSimple> local_state_;
-
   // Specific flows by user e-mail.
   // Keys should be canonicalized before access.
   FlowMap specific_flows_;
diff --git a/chrome/browser/ash/net/dns_over_https/templates_uri_resolver_impl_unittest.cc b/chrome/browser/ash/net/dns_over_https/templates_uri_resolver_impl_unittest.cc
index 9c9a5f9..42992379 100644
--- a/chrome/browser/ash/net/dns_over_https/templates_uri_resolver_impl_unittest.cc
+++ b/chrome/browser/ash/net/dns_over_https/templates_uri_resolver_impl_unittest.cc
@@ -95,8 +95,7 @@
         prefs::kDnsOverHttpsTemplatesWithIdentifiers, "");
     pref_service_.registry()->RegisterStringPref(prefs::kDnsOverHttpsSalt, "");
 
-    fake_user_manager_ = new user_manager::FakeUserManager();
-    fake_user_manager_->set_local_state(&pref_service_);
+    fake_user_manager_ = new user_manager::FakeUserManager(&pref_service_);
     scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
         base::WrapUnique(fake_user_manager_));
 
diff --git a/chrome/browser/ash/net/secure_dns_manager.cc b/chrome/browser/ash/net/secure_dns_manager.cc
index b9b30d73..a5b2ded 100644
--- a/chrome/browser/ash/net/secure_dns_manager.cc
+++ b/chrome/browser/ash/net/secure_dns_manager.cc
@@ -62,6 +62,11 @@
 }
 
 void SecureDnsManager::LoadProviders() {
+  // Note: Check whether each provider is enabled *after* filtering based on
+  // country code so that if we are doing experimentation via Finch for a
+  // regional provider, the experiment groups will be less likely to include
+  // users from other regions unnecessarily (since a client will be included in
+  // the experiment if the provider feature flag is checked).
   const net::DohProviderEntry::List local_providers =
       chrome_browser_net::secure_dns::SelectEnabledProviders(
           chrome_browser_net::secure_dns::ProvidersForCountry(
diff --git a/chrome/browser/ash/ownership/owner_key_loader_unittest.cc b/chrome/browser/ash/ownership/owner_key_loader_unittest.cc
index 9ac9129..60e8cadc 100644
--- a/chrome/browser/ash/ownership/owner_key_loader_unittest.cc
+++ b/chrome/browser/ash/ownership/owner_key_loader_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/ash/policy/core/device_policy_builder.h"
 #include "chrome/browser/ash/settings/device_settings_service.h"
 #include "chrome/browser/net/fake_nss_service.h"
+#include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/ownership/mock_owner_key_util.h"
@@ -48,8 +49,6 @@
     scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
         std::move(fake_user_manager));
 
-    user_manager_->CreateLocalState();
-
     owner_key_util_ = base::MakeRefCounted<ownership::MockOwnerKeyUtil>();
 
     device_settings_service_.SetSessionManager(&session_manager_client_,
@@ -83,6 +82,8 @@
   }
 
   content::BrowserTaskEnvironment task_environment_;
+  ScopedTestingLocalState scoped_local_state_{
+      TestingBrowserProcess::GetGlobal()};
 
   std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
   ash::FakeChromeUserManager* user_manager_ = nullptr;
diff --git a/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc b/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc
index 7b86d28..dd232a9 100644
--- a/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc
+++ b/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc
@@ -57,6 +57,7 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/chrome_unit_test_suite.h"
+#include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "chromeos/ash/components/audio/cras_audio_handler.h"
@@ -837,10 +838,6 @@
         crash_dumps_dir_override_(chrome::DIR_CRASH_DUMPS) {
     scoped_stub_install_attributes_.Get()->SetCloudManaged("managed.com",
                                                            "device_id");
-    auto* user_manager = GetFakeChromeUserManager();
-    user_manager->CreateLocalState();
-    TestingPrefServiceSimple* local_state =
-        static_cast<TestingPrefServiceSimple*>(user_manager->GetLocalState());
 
     // Ensure mojo is started, otherwise browser context keyed services that
     // rely on mojo will explode.
@@ -884,15 +881,9 @@
 
     // DiskMountManager takes ownership of the MockDiskMountManager.
     DiskMountManager::InitializeForTesting(mock_disk_mount_manager.release());
-    TestingDeviceStatusCollector::RegisterPrefs(local_state->registry());
     TestingDeviceStatusCollector::RegisterProfilePrefs(
         profile_pref_service_.registry());
 
-    // Set up a fake local state for KioskAppManager and KioskCryptohomeRemover.
-    TestingBrowserProcess::GetGlobal()->SetLocalState(local_state);
-    ash::KioskAppManager::RegisterLocalStatePrefs(local_state->registry());
-    ash::KioskCryptohomeRemover::RegisterPrefs(local_state->registry());
-
     // Use FakeUpdateEngineClient.
     update_engine_client_ = ash::UpdateEngineClient::InitializeFakeForTest();
 
@@ -929,7 +920,6 @@
     ash::UpdateEngineClient::Shutdown();
     ash::cros_healthd::FakeCrosHealthd::Shutdown();
     ash::FakeSpacedClient::Shutdown();
-    TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
 
     // Finish pending tasks.
     content::RunAllTasksUntilIdle();
@@ -1179,6 +1169,8 @@
   // unit test setup and make a TestingBrowserProcess. Must be first member.
   TestingBrowserProcessInitializer initializer_;
   content::BrowserTaskEnvironment task_environment_;
+  ScopedTestingLocalState scoped_local_state_{
+      TestingBrowserProcess::GetGlobal()};
 
   ChromeContentClient content_client_;
   ChromeContentBrowserClient browser_content_client_;
diff --git a/chrome/browser/ash/web_applications/camera_app/chrome_camera_app_ui_delegate.cc b/chrome/browser/ash/web_applications/camera_app/chrome_camera_app_ui_delegate.cc
index 8c8a1198..1b79518 100644
--- a/chrome/browser/ash/web_applications/camera_app/chrome_camera_app_ui_delegate.cc
+++ b/chrome/browser/ash/web_applications/camera_app/chrome_camera_app_ui_delegate.cc
@@ -29,6 +29,8 @@
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h"
+#include "chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.h"
 #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
@@ -275,6 +277,14 @@
   MaybeTriggerSurvey();
 }
 
+ash::HoldingSpaceClient* ChromeCameraAppUIDelegate::GetHoldingSpaceClient() {
+  ash::HoldingSpaceKeyedService* holding_space_keyed_service =
+      ash::HoldingSpaceKeyedServiceFactory::GetInstance()->GetService(
+          Profile::FromWebUI(web_ui_));
+  CHECK(holding_space_keyed_service);
+  return holding_space_keyed_service->client();
+}
+
 void ChromeCameraAppUIDelegate::SetLaunchDirectory() {
   Profile* profile = Profile::FromWebUI(web_ui_);
   content::WebContents* web_contents = web_ui_->GetWebContents();
diff --git a/chrome/browser/ash/web_applications/camera_app/chrome_camera_app_ui_delegate.h b/chrome/browser/ash/web_applications/camera_app/chrome_camera_app_ui_delegate.h
index 15069ba7..83e79658 100644
--- a/chrome/browser/ash/web_applications/camera_app/chrome_camera_app_ui_delegate.h
+++ b/chrome/browser/ash/web_applications/camera_app/chrome_camera_app_ui_delegate.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "ash/public/cpp/holding_space/holding_space_client.h"
 #include "ash/webui/camera_app_ui/camera_app_ui_delegate.h"
 #include "base/files/file_path_watcher.h"
 #include "base/functional/callback.h"
@@ -125,6 +126,7 @@
   ~ChromeCameraAppUIDelegate() override;
 
   // ash::CameraAppUIDelegate
+  ash::HoldingSpaceClient* GetHoldingSpaceClient() override;
   void SetLaunchDirectory() override;
   void PopulateLoadTimeData(content::WebUIDataSource* source) override;
   bool IsMetricsAndCrashReportingEnabled() override;
@@ -140,10 +142,10 @@
                                monitor_callback) override;
   void StopStorageMonitor() override;
   void OpenStorageManagement() override;
+  base::FilePath GetFilePathByName(const std::string& name) override;
 
  private:
   base::FilePath GetMyFilesFolder();
-  base::FilePath GetFilePathByName(const std::string& name);
   void OnFileMonitorInitialized(std::unique_ptr<FileMonitor> file_monitor);
   void MonitorFileDeletionOnFileThread(
       FileMonitor* file_monitor,
diff --git a/chrome/browser/ash/web_applications/help_app/help_app_integration_browsertest.cc b/chrome/browser/ash/web_applications/help_app/help_app_integration_browsertest.cc
index 103889f..92a646f 100644
--- a/chrome/browser/ash/web_applications/help_app/help_app_integration_browsertest.cc
+++ b/chrome/browser/ash/web_applications/help_app/help_app_integration_browsertest.cc
@@ -46,10 +46,8 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/services/app_service/public/cpp/app_launch_util.h"
-#include "components/services/app_service/public/cpp/features.h"
 #include "components/supervised_user/core/common/pref_names.h"
 #include "components/supervised_user/core/common/supervised_user_constants.h"
 #include "components/user_manager/user_names.h"
@@ -90,28 +88,6 @@
 
 using HelpAppAllProfilesIntegrationTest = HelpAppIntegrationTest;
 
-class HelpAppIntegrationDarkLightModeEnabledTest
-    : public HelpAppIntegrationTest {
- public:
-  HelpAppIntegrationDarkLightModeEnabledTest() {
-    feature_list_.InitAndEnableFeature(chromeos::features::kDarkLightMode);
-  }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-};
-
-class HelpAppIntegrationDarkLightModeDisabledTest
-    : public HelpAppIntegrationTest {
- public:
-  HelpAppIntegrationDarkLightModeDisabledTest() {
-    feature_list_.InitAndDisableFeature(chromeos::features::kDarkLightMode);
-  }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-};
-
 content::WebContents* GetActiveWebContents() {
   return chrome::FindLastActive()->tab_strip_model()->GetActiveWebContents();
 }
@@ -200,7 +176,7 @@
   EXPECT_EQ(1, user_action_tester.GetActionCount("Discover.Help.TabClicked"));
 }
 
-IN_PROC_BROWSER_TEST_P(HelpAppIntegrationDarkLightModeEnabledTest,
+IN_PROC_BROWSER_TEST_P(HelpAppIntegrationTest,
                        HasCorrectThemeAndBackgroundColor) {
   WaitForTestSystemAppInstall();
   web_app::AppId app_id =
@@ -215,20 +191,6 @@
             gfx::kGoogleGrey900);
 }
 
-IN_PROC_BROWSER_TEST_P(HelpAppIntegrationDarkLightModeDisabledTest,
-                       HasCorrectThemeAndBackgroundColor) {
-  WaitForTestSystemAppInstall();
-  web_app::AppId app_id =
-      *GetManager().GetAppIdForSystemApp(SystemWebAppType::HELP);
-  web_app::WebAppRegistrar& registrar =
-      web_app::WebAppProvider::GetForTest(profile())->registrar_unsafe();
-
-  EXPECT_EQ(registrar.GetAppThemeColor(app_id), SK_ColorWHITE);
-  EXPECT_EQ(registrar.GetAppBackgroundColor(app_id), SK_ColorWHITE);
-  EXPECT_EQ(registrar.GetAppDarkModeThemeColor(app_id), absl::nullopt);
-  EXPECT_EQ(registrar.GetAppDarkModeBackgroundColor(app_id), absl::nullopt);
-}
-
 IN_PROC_BROWSER_TEST_P(HelpAppAllProfilesIntegrationTest, HelpAppV2ShowHelp) {
   WaitForTestSystemAppInstall();
 
@@ -839,12 +801,6 @@
 INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_REGULAR_PROFILE_P(
     HelpAppIntegrationTest);
 
-INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_REGULAR_PROFILE_P(
-    HelpAppIntegrationDarkLightModeEnabledTest);
-
-INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_REGULAR_PROFILE_P(
-    HelpAppIntegrationDarkLightModeDisabledTest);
-
 INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_ALL_PROFILE_TYPES_P(
     HelpAppAllProfilesIntegrationTest);
 
diff --git a/chrome/browser/ash/web_applications/help_app/help_app_untrusted_ui_config.cc b/chrome/browser/ash/web_applications/help_app/help_app_untrusted_ui_config.cc
index 7962258..a26c989b 100644
--- a/chrome/browser/ash/web_applications/help_app/help_app_untrusted_ui_config.cc
+++ b/chrome/browser/ash/web_applications/help_app/help_app_untrusted_ui_config.cc
@@ -77,8 +77,7 @@
                         "device-help-content-id"));
 
   // Add any features that have been enabled.
-  source->AddBoolean("colorThemes",
-                     chromeos::features::IsDarkLightModeEnabled());
+  source->AddBoolean("colorThemes", true);
   source->AddBoolean("HelpAppReleaseNotes", true);
   source->AddBoolean(
       "HelpAppLauncherSearch",
diff --git a/chrome/browser/ash/web_applications/help_app/help_app_web_app_info.cc b/chrome/browser/ash/web_applications/help_app/help_app_web_app_info.cc
index bb93256..9e9ab7a 100644
--- a/chrome/browser/ash/web_applications/help_app/help_app_web_app_info.cc
+++ b/chrome/browser/ash/web_applications/help_app/help_app_web_app_info.cc
@@ -6,7 +6,6 @@
 
 #include <memory>
 
-#include "ash/constants/ash_features.h"
 #include "ash/webui/grit/ash_help_app_resources.h"
 #include "ash/webui/help_app_ui/url_constants.h"
 #include "chrome/browser/ash/web_applications/system_web_app_install_utils.h"
@@ -14,7 +13,6 @@
 #include "chrome/browser/web_applications/web_app_constants.h"
 #include "chrome/browser/web_applications/web_app_install_info.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/chromeos/styles/cros_styles.h"
@@ -44,17 +42,12 @@
       },
       *info);
 
-  if (chromeos::features::IsDarkLightModeEnabled()) {
-    info->theme_color = cros_styles::ResolveColor(
-        cros_styles::ColorName::kBgColor, /*is_dark_mode=*/false);
-    info->dark_mode_theme_color = cros_styles::ResolveColor(
-        cros_styles::ColorName::kBgColor, /*is_dark_mode=*/true);
-    info->background_color = info->theme_color;
-    info->dark_mode_background_color = info->dark_mode_theme_color;
-  } else {
-    info->theme_color = 0xffffffff;
-    info->background_color = 0xffffffff;
-  }
+  info->theme_color = cros_styles::ResolveColor(
+      cros_styles::ColorName::kBgColor, /*is_dark_mode=*/false);
+  info->dark_mode_theme_color = cros_styles::ResolveColor(
+      cros_styles::ColorName::kBgColor, /*is_dark_mode=*/true);
+  info->background_color = info->theme_color;
+  info->dark_mode_background_color = info->dark_mode_theme_color;
 
   info->display_mode = blink::mojom::DisplayMode::kStandalone;
   info->user_display_mode = web_app::mojom::UserDisplayMode::kStandalone;
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index 80ec7b81..312da85 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -1242,12 +1242,6 @@
       chromeos::printing::printing_manager::mojom::PrintingMetadataProvider,
       ash::printing::printing_manager::PrintManagementUI>(map);
 
-  RegisterWebUIControllerInterfaceBinder<cros::mojom::CameraAppDeviceProvider,
-                                         ash::CameraAppUI>(map);
-
-  RegisterWebUIControllerInterfaceBinder<
-      ash::camera_app::mojom::CameraAppHelper, ash::CameraAppUI>(map);
-
   RegisterWebUIControllerInterfaceBinder<
       ash::help_app::mojom::PageHandlerFactory, ash::HelpAppUI>(map);
 
@@ -1502,6 +1496,10 @@
     registry.ForWebUI<ash::FaceMLAppUI>()
         .Add<ash::mojom::face_ml_app::PageHandlerFactory>();
   }
+  registry.ForWebUI<ash::CameraAppUI>()
+      .Add<color_change_listener::mojom::PageHandler>()
+      .Add<cros::mojom::CameraAppDeviceProvider>()
+      .Add<ash::camera_app::mojom::CameraAppHelper>();
   registry.ForWebUI<ash::ColorInternalsUI>()
       .Add<color_change_listener::mojom::PageHandler>()
       .Add<ash::color_internals::mojom::WallpaperColorsHandler>();
diff --git a/chrome/browser/extensions/api/mdns/mdns_api.cc b/chrome/browser/extensions/api/mdns/mdns_api.cc
index 124c96d..ec201ff 100644
--- a/chrome/browser/extensions/api/mdns/mdns_api.cc
+++ b/chrome/browser/extensions/api/mdns/mdns_api.cc
@@ -12,7 +12,6 @@
 #include "base/values.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/common/extensions/api/mdns.h"
-#include "components/version_info/channel.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
@@ -20,27 +19,12 @@
 #include "extensions/browser/extension_function.h"
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/extension_registry.h"
-#include "extensions/common/features/feature_channel.h"
 #include "extensions/common/mojom/event_dispatcher.mojom.h"
 
 namespace extensions {
 
 namespace mdns = api::mdns;
 
-namespace {
-
-// Allowlisted mDNS service types.
-const char kCastServiceType[] = "_googlecast._tcp.local";
-const char kPrivetServiceType[] = "_privet._tcp.local";
-const char kTestServiceType[] = "_testing._tcp.local";
-
-bool IsServiceTypeAllowlisted(const std::string& service_type) {
-  return service_type == kCastServiceType ||
-         service_type == kPrivetServiceType || service_type == kTestServiceType;
-}
-
-}  // namespace
-
 using DnsSdRegistry = media_router::DnsSdRegistry;
 
 MDnsAPI::MDnsAPI(content::BrowserContext* context)
@@ -197,21 +181,12 @@
       .GetEventListenersByName(mdns::OnServiceList::kEventName);
 }
 
-bool MDnsAPI::IsMDnsAllowed(const std::string& extension_id,
-                            const std::string& service_type) const {
+bool MDnsAPI::IsMDnsAllowed(const std::string& extension_id) const {
   const extensions::Extension* extension =
       ExtensionRegistry::Get(browser_context_)
           ->enabled_extensions()
           .GetByID(extension_id);
-  if (!extension) {
-    return false;
-  }
-
-  if (GetCurrentChannel() == version_info::Channel::DEV &&
-      extension->is_extension()) {
-    return true;
-  }
-  return extension->is_platform_app() || IsServiceTypeAllowlisted(service_type);
+  return extension;
 }
 
 void MDnsAPI::GetValidOnServiceListListeners(
@@ -233,9 +208,8 @@
       continue;
     }
 
-    // Don't listen for services associated only with disabled extensions
-    // or non-allowlisted, non-platform-app extensions.
-    if (!IsMDnsAllowed(listener->extension_id(), *service_type)) {
+    // Don't listen for services associated only with disabled extensions.
+    if (!IsMDnsAllowed(listener->extension_id())) {
       continue;
     }
 
diff --git a/chrome/browser/extensions/api/mdns/mdns_api.h b/chrome/browser/extensions/api/mdns/mdns_api.h
index 1b26e4b..d3ac1382 100644
--- a/chrome/browser/extensions/api/mdns/mdns_api.h
+++ b/chrome/browser/extensions/api/mdns/mdns_api.h
@@ -91,9 +91,8 @@
                       const std::string& message);
 
   // Returns true if an extension or platform app |extension_id| is allowed to
-  // listen to mDNS events for |service_type|.
-  virtual bool IsMDnsAllowed(const std::string& extension_id,
-                             const std::string& service_type) const;
+  // listen to mDNS events.
+  virtual bool IsMDnsAllowed(const std::string& extension_id) const;
 
   // Finds all all the valid listeners of the mdns.onServiceList event and
   // filters them by service type if |service_type_filter| is non-empty.
diff --git a/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc b/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc
index 859b71c..aa23da34 100644
--- a/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc
+++ b/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc
@@ -25,7 +25,6 @@
 #include "extensions/browser/event_router_factory.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
-#include "extensions/common/features/feature_channel.h"
 #include "extensions/common/manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -66,9 +65,7 @@
   explicit MockedMDnsAPI(content::BrowserContext* context) : MDnsAPI(context) {}
 
  public:
-  MOCK_CONST_METHOD2(IsMDnsAllowed,
-                     bool(const std::string& extension_id,
-                          const std::string& service_type));
+  MOCK_CONST_METHOD1(IsMDnsAllowed, bool(const std::string& extension_id));
 
   MOCK_METHOD0(GetEventListeners,
                const extensions::EventListenerMap::ListenerList&());
@@ -255,17 +252,13 @@
   void SetUp() override {
     MDnsAPITest::SetUp();
     mdns_api_ = static_cast<MockedMDnsAPI*>(MDnsAPI::Get(browser_context()));
-    EXPECT_CALL(*mdns_api_, IsMDnsAllowed(_, _)).WillRepeatedly(Return(true));
+    EXPECT_CALL(*mdns_api_, IsMDnsAllowed(_)).WillRepeatedly(Return(true));
   }
 
  protected:
   raw_ptr<MockedMDnsAPI> mdns_api_;
 };
 
-class MDnsAPIExtensionTest
-    : public MDnsAPITest,
-      public testing::WithParamInterface<version_info::Channel> {};
-
 TEST_F(MDnsAPIDiscoveryTest, ServiceListenersAddedAndRemoved) {
   EventRouterFactory::GetInstance()->SetTestingFactory(
       browser_context(), base::BindRepeating(&MockEventRouterFactoryFunction));
@@ -341,90 +334,4 @@
   dns_sd_registry()->DispatchMDnsEvent("_testing._tcp.local", services);
 }
 
-TEST_P(MDnsAPIExtensionTest, ExtensionRespectsAllowlist) {
-  const bool is_dev = GetParam() == version_info::Channel::DEV;
-  extensions::ScopedCurrentChannel channel_override(GetParam());
-
-  scoped_refptr<extensions::Extension> extension =
-      CreateExtension("Dinosaur networker", false, kExtId);
-  ExtensionRegistry::Get(browser_context())->AddEnabled(extension);
-  ASSERT_EQ(Manifest::TYPE_EXTENSION, extension->GetType());
-  auto param = mojom::EventListenerParam::NewExtensionId(kExtId);
-
-  // There is a allowlist of mdns service types extensions may access, which
-  // includes "_testing._tcp.local" and excludes "_trex._tcp.local"
-  {
-    base::Value::Dict filter;
-    filter.Set(kEventFilterServiceTypeKey, "_trex._tcp.local");
-
-    ASSERT_TRUE(dns_sd_registry());
-    // Test that the extension is not able to listen to a non-allowlisted
-    // service, unless we are on dev channel.
-    EXPECT_CALL(*dns_sd_registry(), RegisterDnsSdListener("_trex._tcp.local"))
-        .Times(is_dev ? 1 : 0);
-    EventRouter::Get(browser_context())
-        ->AddFilteredEventListener(api::mdns::OnServiceList::kEventName,
-                                   render_process_host(), param.Clone(),
-                                   absl::nullopt, filter, false);
-
-    EXPECT_CALL(*dns_sd_registry(), UnregisterDnsSdListener("_trex._tcp.local"))
-        .Times(is_dev ? 1 : 0);
-    EventRouter::Get(browser_context())
-        ->RemoveFilteredEventListener(api::mdns::OnServiceList::kEventName,
-                                      render_process_host(), param.Clone(),
-                                      absl::nullopt, filter, false);
-  }
-  {
-    base::Value::Dict filter;
-    filter.Set(kEventFilterServiceTypeKey, "_testing._tcp.local");
-
-    ASSERT_TRUE(dns_sd_registry());
-    // Test that the extension is able to listen to a allowlisted service
-    EXPECT_CALL(*dns_sd_registry(),
-                RegisterDnsSdListener("_testing._tcp.local"));
-    EventRouter::Get(browser_context())
-        ->AddFilteredEventListener(api::mdns::OnServiceList::kEventName,
-                                   render_process_host(), param.Clone(),
-                                   absl::nullopt, filter, false);
-
-    EXPECT_CALL(*dns_sd_registry(),
-                UnregisterDnsSdListener("_testing._tcp.local"));
-    EventRouter::Get(browser_context())
-        ->RemoveFilteredEventListener(api::mdns::OnServiceList::kEventName,
-                                      render_process_host(), param.Clone(),
-                                      absl::nullopt, filter, false);
-  }
-}
-
-INSTANTIATE_TEST_SUITE_P(Channels,
-                         MDnsAPIExtensionTest,
-                         testing::Values(version_info::Channel::DEV,
-                                         version_info::Channel::STABLE));
-
-TEST_F(MDnsAPITest, PlatformAppsNotSubjectToAllowlist) {
-  scoped_refptr<extensions::Extension> extension =
-      CreateExtension("Dinosaur networker", true, kExtId);
-  ExtensionRegistry::Get(browser_context())->AddEnabled(extension);
-  ASSERT_TRUE(extension->is_platform_app());
-  auto param = mojom::EventListenerParam::NewExtensionId(kExtId);
-
-  base::Value::Dict filter;
-  filter.Set(kEventFilterServiceTypeKey, "_trex._tcp.local");
-
-  ASSERT_TRUE(dns_sd_registry());
-  // Test that the extension is able to listen to a non-allowlisted service
-  EXPECT_CALL(*dns_sd_registry(), RegisterDnsSdListener("_trex._tcp.local"));
-
-  EventRouter::Get(browser_context())
-      ->AddFilteredEventListener(api::mdns::OnServiceList::kEventName,
-                                 render_process_host(), param.Clone(),
-                                 absl::nullopt, filter, false);
-
-  EXPECT_CALL(*dns_sd_registry(), UnregisterDnsSdListener("_trex._tcp.local"));
-  EventRouter::Get(browser_context())
-      ->RemoveFilteredEventListener(api::mdns::OnServiceList::kEventName,
-                                    render_process_host(), param.Clone(),
-                                    absl::nullopt, filter, false);
-}
-
 }  // namespace extensions
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 6b84d53..be7ea23 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2088,6 +2088,11 @@
     "expiry_milestone": 116
   },
   {
+    "name": "enable-cros-diacritics-on-physical-keyboard-longpress-on-by-default",
+    "owners": ["jopalmer", "essential-inputs-team@google.com" ],
+    "expiry_milestone": 120
+  },
+  {
     "name": "enable-cros-first-party-vietnamese-input",
     "owners": ["jhtin", "essential-inputs-team@google.com" ],
     "expiry_milestone": 122
@@ -6187,7 +6192,7 @@
   {
     "name": "prefer-constant-frame-rate",
     "owners": [ "chromeos-camera-eng@google.com" ],
-    "expiry_milestone": 110
+    "expiry_milestone": 130
   },
   {
     "name": "prefer-dcheck",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index dfaf769..858a74b 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -5862,6 +5862,13 @@
     "Enable diacritics and other varient character selection on physical "
     "keyboard longpress.";
 
+const char kDiacriticsOnPhysicalKeyboardLongpressDefaultOnName[] =
+    "Enable diacritics and variant character selection on PK longpress by "
+    "default.";
+const char kDiacriticsOnPhysicalKeyboardLongpressDefaultOnDescription[] =
+    "Enable diacritics and other varient character selection on physical "
+    "keyboard longpress by default.";
+
 const char kHoldingSpacePredictabilityName[] =
     "Enable holding space predictability";
 const char kHoldingSpacePredictabilityDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 7d0d5d8..eb0fdb4 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -3371,6 +3371,9 @@
 extern const char kDiacriticsOnPhysicalKeyboardLongpressName[];
 extern const char kDiacriticsOnPhysicalKeyboardLongpressDescription[];
 
+extern const char kDiacriticsOnPhysicalKeyboardLongpressDefaultOnName[];
+extern const char kDiacriticsOnPhysicalKeyboardLongpressDefaultOnDescription[];
+
 extern const char kHoldingSpacePredictabilityName[];
 extern const char kHoldingSpacePredictabilityDescription[];
 
diff --git a/chrome/browser/privacy/secure_dns_bridge.cc b/chrome/browser/privacy/secure_dns_bridge.cc
index 06ead483..b979a58 100644
--- a/chrome/browser/privacy/secure_dns_bridge.cc
+++ b/chrome/browser/privacy/secure_dns_bridge.cc
@@ -43,9 +43,13 @@
 namespace {
 
 net::DohProviderEntry::List GetFilteredProviders() {
-  return secure_dns::ProvidersForCountry(
-      secure_dns::SelectEnabledProviders(net::DohProviderEntry::GetList()),
-      country_codes::GetCurrentCountryID());
+  // Note: Check whether each provider is enabled *after* filtering based on
+  // country code so that if we are doing experimentation via Finch for a
+  // regional provider, the experiment groups will be less likely to include
+  // users from other regions unnecessarily (since a client will be included in
+  // the experiment if the provider feature flag is checked).
+  return secure_dns::SelectEnabledProviders(secure_dns::ProvidersForCountry(
+      net::DohProviderEntry::GetList(), country_codes::GetCurrentCountryID()));
 }
 
 // Runs a DNS probe according to the configuration in |overrides|,
diff --git a/chrome/browser/resources/app_home/app_item.html b/chrome/browser/resources/app_home/app_item.html
index a4a118c6..3a5eae75 100644
--- a/chrome/browser/resources/app_home/app_item.html
+++ b/chrome/browser/resources/app_home/app_item.html
@@ -86,7 +86,7 @@
       class="dropdown-item label-first"
       on-click="onOpenInWindowItemClick_"
       hidden="[[!isOpenInWindowHidden_(appInfo)]]"
-      checked="{{appInfo.openInWindow}}">
+      checked="{{appInfo.openInWindow}}" noink>
     $i18n{appWindowOpenLabel}
   </cr-checkbox>
   <cr-checkbox
@@ -95,7 +95,7 @@
       on-click="onLaunchOnStartupItemClick_"
       hidden="[[isLaunchOnStartupHidden_(appInfo)]]"
       checked="[[isLaunchOnStartUp_(appInfo)]]"
-      disabled="[[isLaunchOnStartupDisabled_(appInfo)]]">
+      disabled="[[isLaunchOnStartupDisabled_(appInfo)]]" noink>
     $i18n{appLaunchAtStartupLabel}
   </cr-checkbox>
   <button id="createShortcut"
diff --git a/chrome/browser/resources/chromeos/drive_internals.html b/chrome/browser/resources/chromeos/drive_internals.html
index d2bf89e..0da717b 100644
--- a/chrome/browser/resources/chromeos/drive_internals.html
+++ b/chrome/browser/resources/chromeos/drive_internals.html
@@ -193,6 +193,14 @@
           <th>Pinning Files</th>
           <td id="bulk-pinning-syncing-files">?</td>
         </tr>
+        <tr>
+          <th>Time Spent Listing</th>
+          <td id="bulk-pinning-time-spent-listing-items">?</td>
+        </tr>
+        <tr>
+          <th>Time Spent Pinning</th>
+          <td id="bulk-pinning-time-spent-pinning-files">?</td>
+        </tr>
       </table>
     </section>
 
diff --git a/chrome/browser/resources/chromeos/drive_internals.js b/chrome/browser/resources/chromeos/drive_internals.js
index 44303f6c..b55a58b 100644
--- a/chrome/browser/resources/chromeos/drive_internals.js
+++ b/chrome/browser/resources/chromeos/drive_internals.js
@@ -126,6 +126,10 @@
   $('bulk-pinning-listed-shortcuts').innerText = progress.listed_shortcuts;
   $('bulk-pinning-active-queries').innerText = progress.active_queries;
   $('bulk-pinning-max-active-queries').innerText = progress.max_active_queries;
+  $('bulk-pinning-time-spent-listing-items').innerText =
+      progress.time_spent_listing_items;
+  $('bulk-pinning-time-spent-pinning-files').innerText =
+      progress.time_spent_pinning_files;
 }
 
 function updateStartupArguments(args) {
diff --git a/chrome/browser/resources/chromeos/emoji_picker/BUILD.gn b/chrome/browser/resources/chromeos/emoji_picker/BUILD.gn
index c34b76ee..9971a85 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/BUILD.gn
+++ b/chrome/browser/resources/chromeos/emoji_picker/BUILD.gn
@@ -234,6 +234,8 @@
     "generic_error_dark.svg",
     "generic_error.svg",
     "index.html",
+    "network_error_dark.svg",
+    "network_error.svg",
     "no_results_dark.svg",
     "no_results.svg",
   ]
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_error.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_error.html
index 4aba1a23..c416ad677 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_error.html
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_error.html
@@ -17,6 +17,7 @@
     font-weight: 500;
     line-height: 22px;
     margin: 8px 0;
+    color: var(--cros-text-color-secondary);
   }
 
   .try-again-button {
@@ -45,8 +46,12 @@
     </picture>
   </template>
   <template is="dom-if" if="[[isGifInNetworkErrorState(status)]]">
-    <iron-icon id="no-internet-icon" icon="emoji_picker_v2:cloud_off">
-    </iron-icon>
+    <picture>
+      <source
+        srcset="network_error_dark.svg"
+        media="(prefers-color-scheme: dark)">
+      <img src="network_error.svg">
+    </picture>
   </template>
   <span class="error-text">[[getErrorMessage(status)]]</span>
   <a class="try-again-button" onclick="[[onClickTryAgain]]">Try again</a>
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html
index de0ff69..c264733 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html
@@ -236,6 +236,33 @@
   .category-gap {
     height: 16px;
   }
+
+
+  #list-container.error-only {
+    flex: 1;
+  }
+
+  #list-container.error-only>:not(#groups) {
+    display: none;
+  }
+
+  #list-container.error-only>#groups {
+    display: block;
+    flex-grow: 0;
+    margin: auto;
+  }
+
+  #list-container.error-only>#groups> :not(emoji-error) {
+    display: none;
+  }
+
+  #list-container.error-only emoji-error {
+    display: block;
+  }
+
+  #list-container.no-gif emoji-group[category="gif"] {
+    display: none;
+  }
 </style>
 
 <div class="sr-only" aria-live="polite">
@@ -255,7 +282,7 @@
     gif-support$="[[gifSupport]]">
   </emoji-search>
 
-<div id="list-container">
+<div id="list-container" class$="[[computeListContainerClass(category, status)]]">
   <div class="sr-only" role="heading" aria-level="1">Emoji Group Buttons</div>
   <div class="side-padding">
     <div id="tabs" on-scroll="onGroupsScroll">
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
index f3b1780..04e1033 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
@@ -1108,7 +1108,7 @@
    */
   private isCategoryHistoryEmpty(category: CategoryEnum) {
     return this.incognito ||
-        this.categoriesHistory[category]?.data?.history?.length == 0;
+        (this.categoriesHistory[category]?.data?.history?.length ?? 0) === 0;
   }
 
   /**
@@ -1429,6 +1429,19 @@
     }
     return new Date(stored);
   }
+
+  private computeListContainerClass(category: CategoryEnum, status: Status): string {
+    // Only displays emoji-error if there is no internet connection and we are in GIF category.
+    if (category === CategoryEnum.GIF && status !== Status.kHttpOk) {
+      return 'error-only';
+    }
+    // Do not display GIF emoji groups if there is no internet connection and we are in non-GIF
+    // category.
+    if (category !== CategoryEnum.GIF && status !== Status.kHttpOk) {
+      return 'no-gif';
+    }
+    return '';
+  }
 }
 
 declare global {
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker_api_proxy.ts b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker_api_proxy.ts
index 72bf391..ef9989f 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker_api_proxy.ts
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker_api_proxy.ts
@@ -77,12 +77,30 @@
   /** @override */
   getFeaturedGifs(pos?: string):
       Promise<{status: Status, featuredGifs: TenorGifResponse}> {
+    if (!navigator.onLine) {
+      return Promise.resolve({
+        status: Status.kNetError,
+        featuredGifs: {
+          next: '',
+          results: [],
+        },
+      });
+    }
     return this.handler.getFeaturedGifs(pos || null);
   }
 
   /** @override */
   searchGifs(query: string, pos?: string):
       Promise<{status: Status, searchGifs: TenorGifResponse}> {
+    if (!navigator.onLine) {
+      return Promise.resolve({
+        status: Status.kNetError,
+        searchGifs: {
+          next: '',
+          results: [],
+        },
+      });
+    }
     return this.handler.searchGifs(query, pos || null);
   }
 
diff --git a/chrome/browser/resources/chromeos/emoji_picker/icons.html b/chrome/browser/resources/chromeos/emoji_picker/icons.html
index e223e33..c38c3dc 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/icons.html
+++ b/chrome/browser/resources/chromeos/emoji_picker/icons.html
@@ -33,6 +33,5 @@
     <svg id="emoji_emoticons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" mlns="http://www.w3.org/2000/svg"><path d="M4.857 11.398c-.384 0-.708-.132-.972-.396a1.3 1.3 0 0 1-.396-.954c0-.384.132-.702.396-.954.264-.264.588-.396.972-.396.372 0 .69.132.954.396.264.252.396.57.396.954a1.3 1.3 0 0 1-.396.954 1.3 1.3 0 0 1-.954.396Zm0 6.75c-.384 0-.708-.132-.972-.396a1.321 1.321 0 0 1-.396-.972c0-.36.132-.672.396-.936s.588-.396.972-.396c.372 0 .69.132.954.396s.396.576.396.936c0 .384-.132.708-.396.972a1.3 1.3 0 0 1-.954.396ZM8.326 13.288v-1.656h5.904v1.656H8.326ZM17.166 20.488l-1.44-1.008c.504-.624.96-1.314 1.368-2.07.42-.768.744-1.584.972-2.448.24-.876.36-1.782.36-2.718 0-.936-.12-1.836-.36-2.7a10.772 10.772 0 0 0-.972-2.466 12.38 12.38 0 0 0-1.368-2.07L17.166 4c.48.54.966 1.23 1.458 2.07.492.84.9 1.782 1.224 2.826.336 1.032.504 2.148.504 3.348 0 .9-.096 1.758-.288 2.574-.192.804-.444 1.56-.756 2.268a12.69 12.69 0 0 1-1.044 1.926 12.42 12.42 0 0 1-1.098 1.476Z"></svg>
     <svg id="emoji_gif" width="24" height="24" xmlns="http://www.w3.org/2000/svg"><path d="M12 17V7h2v10h-2Zm-8.543 0c-.428 0-.778-.132-1.05-.396C2.136 16.34 2 16 2 15.584V8.416c0-.417.136-.757.407-1.021C2.68 7.132 3.03 7 3.457 7h5.086c.428 0 .778.132 1.05.396.271.264.407.604.407 1.02V9H4v6h4v-3h2v3.583c0 .417-.136.757-.407 1.021-.272.264-.622.396-1.05.396H3.457ZM16 17V7h7v2h-5v2.5h3v2h-3V17h-2Z"></svg>
     <svg id="emoji_symbols" width="24" height="24" xmlns="http://www.w3.org/2000/svg"><path d="M15.6 17.485c1.418-1.242 2.4-3.222 2.4-5.63C18 7.684 15.055 4.8 12 4.8c-3.054 0-6 2.884-6 7.055 0 2.408.982 4.388 2.4 5.63V20.4c-2.838-1.517-4.8-4.773-4.8-8.545C3.6 6.633 7.361 2.4 12 2.4c4.64 0 8.4 4.233 8.4 9.455 0 3.772-1.962 7.027-4.8 8.545v-2.915Z" /><path d="M1.2 18h7.2v2.4H1.2V18ZM15.6 18h7.2v2.4h-7.2V18Z"/></svg>
-    <svg id="cloud_off" xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewbox="0 0 48 48"><path fill-rule="evenodd" d="M42.89 40.49 7.2 4.8 4.8 7.2l8.187 8.187-.078.116C6.993 16.215 2.4 21.007 2.4 26.88c0 6.364 5.375 11.52 12 11.52H36l4.492 4.49 2.4-2.4ZM16.803 19.95h.748l13.824 13.824H14.4c-3.977 0-7.2-3.095-7.2-6.912 0-3.818 3.223-6.912 7.2-6.912h2.402Z" clip-rule="evenodd"/><path d="M43.151 35.333c1.523-1.631 2.449-3.786 2.449-6.149 0-4.767-3.782-8.64-8.614-9.121C35.896 14.118 30.504 9.6 24 9.6c-1.947 0-3.787.41-5.44 1.141l3.649 3.65a8.685 8.685 0 0 1 1.776-.183c4.64 0 8.4 3.61 8.4 8.064v2.286H36c2.65 0 4.8 2.064 4.8 4.608a4.47 4.47 0 0 1-1 2.815l3.351 3.352Z"/></svg>
   </defs>
 </iron-iconset-svg>
diff --git a/chrome/browser/resources/chromeos/emoji_picker/network_error.svg b/chrome/browser/resources/chromeos/emoji_picker/network_error.svg
new file mode 100644
index 0000000..7f10560
--- /dev/null
+++ b/chrome/browser/resources/chromeos/emoji_picker/network_error.svg
@@ -0,0 +1,16 @@
+<svg width="200" height="72" viewBox="0 0 200 72" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M69.9043 55.1479L68.5888 51.3154C68.349 50.617 67.5873 50.2447 66.8875 50.484L63.0474 51.7969C62.3475 52.0362 61.9746 52.7963 62.2143 53.4947L63.5298 57.3272C63.7696 58.0256 64.5312 58.3979 65.2311 58.1586L69.0712 56.8457C69.771 56.6064 70.144 55.8463 69.9043 55.1479Z" fill="#4285F4"/>
+<path d="M50.3433 30.8118C49.8983 30.6909 49.4409 30.6213 48.98 30.6044L47.511 30.3799C46.2916 30.1791 45.1856 29.5463 44.3959 28.5975C43.2541 27.2982 42.4975 25.7029 40.6468 25.3219C39.9276 25.1721 39.1817 25.213 38.4833 25.4403C37.7848 25.6677 37.1583 26.0737 36.6659 26.6179C36.6148 26.6723 36.5637 26.7335 36.516 26.7913C36.1412 27.2691 35.8746 27.8221 35.7344 28.4125C35.5943 29.0029 35.5839 29.6165 35.7041 30.2113C35.8242 30.806 36.072 31.3677 36.4305 31.8578C36.7889 32.3478 37.2495 32.7545 37.7804 33.05C38.4246 33.4106 39.1437 33.6691 39.8015 33.965C41.0034 34.4897 41.9482 35.4681 42.4293 36.6861L42.9712 38.0671C43.2363 39.0793 43.7637 40.0041 44.5003 40.7486C45.2368 41.4931 46.1567 42.031 47.1675 42.3084C48.1783 42.5858 49.2445 42.5929 50.2589 42.329C51.2734 42.065 52.2003 41.5393 52.9468 40.8047C53.6932 40.0701 54.2328 39.1524 54.5115 38.1438C54.7901 37.1352 54.7979 36.0712 54.534 35.0586C54.2702 34.046 53.7441 33.1206 53.0085 32.3751C52.2729 31.6297 51.3537 31.0906 50.3433 30.8118V30.8118Z" stroke="#E8EAED" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M187.529 30.893C188.894 30.893 190 29.7889 190 28.427C190 27.065 188.894 25.9609 187.529 25.9609C186.164 25.9609 185.058 27.065 185.058 28.427C185.058 29.7889 186.164 30.893 187.529 30.893Z" fill="#E8EAED"/>
+<path d="M156.811 51.2131C157.635 51.2131 158.303 50.546 158.303 49.7232C158.303 48.9004 157.635 48.2334 156.811 48.2334C155.986 48.2334 155.318 48.9004 155.318 49.7232C155.318 50.546 155.986 51.2131 156.811 51.2131Z" fill="#4285F4"/>
+<path d="M12.0867 23.1221C13.2391 23.1221 14.1734 22.1897 14.1734 21.0395C14.1734 19.8894 13.2391 18.957 12.0867 18.957C10.9342 18.957 10 19.8894 10 21.0395C10 22.1897 10.9342 23.1221 12.0867 23.1221Z" fill="#4285F4"/>
+<path d="M132.918 45.788L129.169 48.271C128.869 48.4658 128.627 48.7366 128.466 49.0558C128.306 49.375 128.233 49.731 128.256 50.0874L128.529 54.5807C128.55 54.933 128.664 55.2734 128.859 55.5677C129.054 55.8621 129.323 56.1 129.64 56.2576L133.678 58.2509C133.995 58.4092 134.347 58.4816 134.7 58.4607C135.053 58.4398 135.394 58.3264 135.689 58.1318L139.438 55.6488C139.733 55.4536 139.971 55.1847 140.129 54.869C140.287 54.5532 140.359 54.2017 140.338 53.8494L140.066 49.3527C140.043 49.0006 139.929 48.6605 139.734 48.3662C139.539 48.072 139.27 47.8339 138.954 47.6758L134.929 45.6655C134.613 45.508 134.26 45.4363 133.907 45.4578C133.554 45.4793 133.213 45.5932 132.918 45.788V45.788Z" stroke="#E8EAED" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M22.9887 39.3359H16.3563C16.2858 39.3369 16.2168 39.3563 16.1562 39.3922C16.0956 39.4282 16.0456 39.4794 16.0111 39.5407C15.9766 39.602 15.9588 39.6713 15.9596 39.7416C15.9603 39.8119 15.9796 39.8808 16.0154 39.9414L19.3283 45.666C19.3638 45.7244 19.4138 45.7727 19.4735 45.8063C19.5332 45.8398 19.6006 45.8574 19.6691 45.8574C19.7376 45.8574 19.8049 45.8398 19.8646 45.8063C19.9243 45.7727 19.9743 45.7244 20.0099 45.666L23.3261 39.9346C23.3602 39.8745 23.3781 39.8066 23.3782 39.7375C23.3783 39.6684 23.3605 39.6005 23.3265 39.5403C23.2926 39.4801 23.2437 39.4297 23.1845 39.3939C23.1253 39.3581 23.0579 39.3381 22.9887 39.3359V39.3359Z" fill="#D2E3FC"/>
+<path d="M152.622 33.614C152.55 33.6861 152.494 33.773 152.458 33.8687C152.422 33.9644 152.408 34.0667 152.416 34.1685C152.424 34.2703 152.453 34.3692 152.503 34.4584C152.553 34.5476 152.621 34.6251 152.704 34.6854C153.765 35.4773 155.076 35.8629 156.398 35.7722C157.72 35.6816 158.965 35.1206 159.908 34.1913C160.85 33.262 161.428 32.026 161.535 30.7079C161.642 29.3899 161.272 28.0772 160.492 27.0084C160.432 26.9255 160.355 26.8565 160.266 26.806C160.177 26.7555 160.078 26.7247 159.977 26.7157C159.875 26.7066 159.772 26.7196 159.676 26.7537C159.579 26.7877 159.491 26.8421 159.418 26.9131L152.622 33.614Z" fill="#D2E3FC"/>
+<path d="M129.265 27.4068L125.247 23.3931C118.578 16.7385 109.534 13 100.104 13C90.6736 13 81.6296 16.7385 74.9612 23.3931L70.9428 27.4068C70.635 27.7139 70.3908 28.0784 70.2242 28.4797C70.0576 28.8809 69.9719 29.311 69.9719 29.7453C69.9719 30.1797 70.0576 30.6097 70.2242 31.011C70.3908 31.4122 70.635 31.7768 70.9428 32.0838L77.8479 38.9785C77.9407 38.8423 78.0456 38.7148 78.1615 38.5976L81.1846 35.5805C86.2019 30.5747 93.0059 27.7625 100.1 27.7625C107.195 27.7625 113.999 30.5747 119.016 35.5805L122.039 38.5976C122.155 38.7148 122.26 38.8423 122.353 38.9785L129.258 32.0838C129.566 31.7772 129.811 31.413 129.978 31.012C130.145 30.611 130.232 30.1811 130.232 29.7467C130.233 29.3124 130.148 28.8822 129.982 28.4807C129.816 28.0792 129.572 27.7143 129.265 27.4068Z" fill="#D2E3FC"/>
+<path d="M119.023 35.5806C114.006 30.5748 107.202 27.7627 100.107 27.7627C93.013 27.7627 86.2089 30.5748 81.1917 35.5806L78.1685 38.5977C78.0527 38.715 77.9477 38.8425 77.855 38.9787L87.2618 48.3871L88.0457 47.6047C89.6284 46.023 91.5081 44.7681 93.5772 43.9119C95.6462 43.0557 97.8642 42.615 100.104 42.615C102.344 42.615 104.562 43.0557 106.631 43.9119C108.7 44.7681 110.58 46.023 112.162 47.6047L112.946 48.3871L122.36 38.9923C122.267 38.8561 122.162 38.7286 122.046 38.6113L119.023 35.5806Z" fill="#8AB4F8"/>
+<path d="M102.449 58.85L112.947 48.3736L112.163 47.5913C110.58 46.0095 108.7 44.7546 106.631 43.8984C104.562 43.0423 102.344 42.6016 100.104 42.6016C97.8644 42.6016 95.6464 43.0423 93.5774 43.8984C91.5083 44.7546 89.6286 46.0095 88.0459 47.5913L87.262 48.3736L97.7594 58.85C98.3813 59.4707 99.2248 59.8193 100.104 59.8193C100.984 59.8193 101.827 59.4707 102.449 58.85Z" fill="#4285F4"/>
+<circle cx="163.5" cy="26.5" r="5.5" stroke="#4285F4" stroke-linecap="round" stroke-dasharray="2 2"/>
+<line x1="1.5" y1="-1.5" x2="67.7929" y2="-1.5" transform="matrix(0.734803 0.67828 -0.734803 0.67828 72.0833 9)" stroke="white" stroke-width="3" stroke-linecap="round"/>
+<line x1="1.5" y1="-1.5" x2="67.7929" y2="-1.5" transform="matrix(0.734803 0.67828 -0.734803 0.67828 71 12)" stroke="#4285F4" stroke-width="3" stroke-linecap="round"/>
+</svg>
diff --git a/chrome/browser/resources/chromeos/emoji_picker/network_error_dark.svg b/chrome/browser/resources/chromeos/emoji_picker/network_error_dark.svg
new file mode 100644
index 0000000..21d930b
--- /dev/null
+++ b/chrome/browser/resources/chromeos/emoji_picker/network_error_dark.svg
@@ -0,0 +1,16 @@
+<svg width="200" height="72" viewBox="0 0 200 72" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M69.9043 55.1479L68.5888 51.3154C68.349 50.617 67.5873 50.2447 66.8875 50.484L63.0474 51.7969C62.3475 52.0362 61.9746 52.7963 62.2143 53.4947L63.5298 57.3272C63.7696 58.0256 64.5312 58.3979 65.2311 58.1586L69.0712 56.8457C69.771 56.6064 70.144 55.8463 69.9043 55.1479Z" fill="#669DF6"/>
+<path d="M50.3433 30.8118C49.8983 30.6909 49.4409 30.6213 48.98 30.6044L47.5111 30.3799C46.2916 30.1791 45.1856 29.5463 44.3959 28.5975C43.2542 27.2982 42.4975 25.7029 40.6468 25.3219C39.9277 25.1721 39.1818 25.213 38.4833 25.4403C37.7849 25.6677 37.1583 26.0737 36.666 26.6179C36.6149 26.6723 36.5638 26.7335 36.516 26.7913C36.1413 27.2691 35.8746 27.8221 35.7345 28.4125C35.5943 29.0029 35.584 29.6165 35.7041 30.2113C35.8243 30.806 36.0721 31.3677 36.4305 31.8578C36.789 32.3478 37.2495 32.7545 37.7805 33.05C38.4247 33.4106 39.1438 33.6691 39.8016 33.965C41.0035 34.4897 41.9483 35.4681 42.4294 36.6861L42.9713 38.0671C43.2364 39.0793 43.7637 40.0041 44.5003 40.7486C45.2369 41.4931 46.1568 42.031 47.1676 42.3084C48.1784 42.5858 49.2446 42.5929 50.259 42.329C51.2734 42.065 52.2004 41.5393 52.9468 40.8047C53.6933 40.0701 54.2329 39.1524 54.5115 38.1438C54.7901 37.1352 54.7979 36.0712 54.5341 35.0586C54.2703 34.046 53.7442 33.1206 53.0086 32.3751C52.273 31.6297 51.3538 31.0906 50.3433 30.8118V30.8118Z" stroke="#5F6368" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M187.529 30.893C188.894 30.893 190 29.7889 190 28.427C190 27.065 188.894 25.9609 187.529 25.9609C186.164 25.9609 185.058 27.065 185.058 28.427C185.058 29.7889 186.164 30.893 187.529 30.893Z" fill="#5F6368"/>
+<path d="M156.811 51.2131C157.635 51.2131 158.303 50.546 158.303 49.7232C158.303 48.9004 157.635 48.2334 156.811 48.2334C155.986 48.2334 155.318 48.9004 155.318 49.7232C155.318 50.546 155.986 51.2131 156.811 51.2131Z" fill="#669DF6"/>
+<path d="M12.0867 23.1221C13.2391 23.1221 14.1734 22.1897 14.1734 21.0395C14.1734 19.8894 13.2391 18.957 12.0867 18.957C10.9342 18.957 10 19.8894 10 21.0395C10 22.1897 10.9342 23.1221 12.0867 23.1221Z" fill="#669DF6"/>
+<path d="M132.918 45.788L129.169 48.271C128.869 48.4658 128.627 48.7366 128.466 49.0558C128.306 49.375 128.233 49.731 128.256 50.0874L128.529 54.5807C128.55 54.933 128.664 55.2734 128.859 55.5677C129.054 55.8621 129.323 56.1 129.64 56.2576L133.678 58.2509C133.995 58.4092 134.347 58.4816 134.7 58.4607C135.053 58.4398 135.394 58.3264 135.689 58.1318L139.438 55.6488C139.733 55.4536 139.971 55.1847 140.129 54.869C140.287 54.5532 140.359 54.2017 140.338 53.8494L140.066 49.3527C140.043 49.0006 139.929 48.6605 139.734 48.3662C139.539 48.072 139.27 47.8339 138.954 47.6758L134.929 45.6655C134.613 45.508 134.26 45.4363 133.907 45.4578C133.554 45.4793 133.213 45.5932 132.918 45.788V45.788Z" stroke="#5F6368" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M22.9887 39.3359H16.3562C16.2857 39.3369 16.2167 39.3563 16.1562 39.3922C16.0956 39.4282 16.0455 39.4794 16.011 39.5407C15.9765 39.602 15.9587 39.6713 15.9595 39.7416C15.9603 39.8119 15.9795 39.8808 16.0154 39.9414L19.3282 45.666C19.3637 45.7244 19.4138 45.7727 19.4735 45.8063C19.5332 45.8398 19.6005 45.8574 19.669 45.8574C19.7375 45.8574 19.8049 45.8398 19.8645 45.8063C19.9242 45.7727 19.9743 45.7244 20.0098 45.666L23.3261 39.9346C23.3601 39.8745 23.3781 39.8066 23.3781 39.7375C23.3782 39.6684 23.3604 39.6005 23.3265 39.5403C23.2925 39.4801 23.2436 39.4297 23.1844 39.3939C23.1253 39.3581 23.0578 39.3381 22.9887 39.3359V39.3359Z" fill="#8AB4F8" fill-opacity="0.4"/>
+<path d="M152.622 33.614C152.55 33.6861 152.494 33.773 152.458 33.8687C152.422 33.9644 152.408 34.0667 152.416 34.1685C152.424 34.2703 152.453 34.3692 152.503 34.4584C152.553 34.5476 152.621 34.6251 152.704 34.6854C153.765 35.4773 155.076 35.8629 156.398 35.7722C157.72 35.6816 158.965 35.1206 159.908 34.1913C160.85 33.262 161.428 32.026 161.535 30.7079C161.642 29.3899 161.272 28.0772 160.492 27.0084C160.432 26.9255 160.355 26.8565 160.266 26.806C160.177 26.7555 160.078 26.7247 159.977 26.7157C159.875 26.7066 159.772 26.7196 159.676 26.7537C159.579 26.7877 159.491 26.8421 159.418 26.9131L152.622 33.614Z" fill="#8AB4F8" fill-opacity="0.4"/>
+<path d="M129.265 27.4068L125.247 23.3931C118.578 16.7385 109.534 13 100.104 13C90.6737 13 81.6296 16.7385 74.9612 23.3931L70.9429 27.4068C70.6351 27.7139 70.3909 28.0784 70.2243 28.4797C70.0577 28.8809 69.9719 29.311 69.9719 29.7453C69.9719 30.1797 70.0577 30.6097 70.2243 31.011C70.3909 31.4122 70.6351 31.7768 70.9429 32.0838L77.848 38.9785C77.9408 38.8423 78.0457 38.7148 78.1616 38.5976L81.1847 35.5805C86.202 30.5747 93.006 27.7625 100.101 27.7625C107.195 27.7625 113.999 30.5747 119.016 35.5805L122.039 38.5976C122.155 38.7148 122.26 38.8423 122.353 38.9785L129.258 32.0838C129.566 31.7772 129.811 31.413 129.978 31.012C130.145 30.611 130.232 30.1811 130.232 29.7467C130.233 29.3124 130.148 28.8822 129.982 28.4807C129.816 28.0792 129.572 27.7143 129.265 27.4068Z" fill="#8AB4F8" fill-opacity="0.4"/>
+<path d="M119.023 35.5806C114.006 30.5748 107.202 27.7627 100.107 27.7627C93.013 27.7627 86.2089 30.5748 81.1917 35.5806L78.1685 38.5977C78.0527 38.715 77.9477 38.8425 77.855 38.9787L87.2618 48.3871L88.0457 47.6047C89.6284 46.023 91.5081 44.7681 93.5772 43.9119C95.6462 43.0557 97.8642 42.615 100.104 42.615C102.344 42.615 104.562 43.0557 106.631 43.9119C108.7 44.7681 110.58 46.023 112.162 47.6047L112.946 48.3871L122.36 38.9923C122.267 38.8561 122.162 38.7286 122.046 38.6113L119.023 35.5806Z" fill="#1A73E8" fill-opacity="0.4"/>
+<path d="M102.449 58.85L112.947 48.3736L112.163 47.5913C110.58 46.0095 108.7 44.7546 106.631 43.8984C104.562 43.0423 102.344 42.6016 100.104 42.6016C97.8644 42.6016 95.6464 43.0423 93.5774 43.8984C91.5083 44.7546 89.6286 46.0095 88.0459 47.5913L87.262 48.3736L97.7594 58.85C98.3813 59.4707 99.2248 59.8193 100.104 59.8193C100.984 59.8193 101.827 59.4707 102.449 58.85Z" fill="#669DF6"/>
+<circle cx="163.5" cy="26.5" r="5.5" stroke="#669DF6" stroke-linecap="round" stroke-dasharray="2 2"/>
+<line x1="1.5" y1="-1.5" x2="67.7929" y2="-1.5" transform="matrix(0.734803 0.67828 -0.734803 0.67828 72.0834 9)" stroke="#323336" stroke-width="3" stroke-linecap="round"/>
+<line x1="1.5" y1="-1.5" x2="67.7929" y2="-1.5" transform="matrix(0.734803 0.67828 -0.734803 0.67828 71 12)" stroke="#669DF6" stroke-width="3" stroke-linecap="round"/>
+</svg>
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox.html b/chrome/browser/resources/new_tab_page/realbox/realbox.html
index 8cd5a298..506d83a9 100644
--- a/chrome/browser/resources/new_tab_page/realbox/realbox.html
+++ b/chrome/browser/resources/new_tab_page/realbox/realbox.html
@@ -206,7 +206,7 @@
     on-keydown="onInputWrapperKeydown_">
   <input id="input" type="search" autocomplete="off" spellcheck="false"
       aria-live="[[inputAriaLive_]]" role="combobox"
-      aria-expanded="[[matchesAreVisible]]" aria-controls="matches"
+      aria-expanded="[[dropdownIsVisible]]" aria-controls="matches"
       placeholder="$i18n{searchBoxHint}" on-copy="onInputCutCopy_"
       on-cut="onInputCutCopy_" on-focus="onInputFocus_" on-input="onInputInput_"
       on-keydown="onInputKeydown_" on-keyup="onInputKeyup_"
@@ -229,6 +229,6 @@
       has-secondary-side="{{hasSecondarySide}}"
       on-match-focusin="onMatchFocusin_" on-match-click="onMatchClick_"
       on-match-remove="onMatchRemove_" on-header-focusin="onHeaderFocusin_"
-      hidden$="[[!matchesAreVisible]]">
+      hidden$="[[!dropdownIsVisible]]">
   </cr-realbox-dropdown>
 </div>
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox.ts b/chrome/browser/resources/new_tab_page/realbox/realbox.ts
index d59b1bf0..8299aea 100644
--- a/chrome/browser/resources/new_tab_page/realbox/realbox.ts
+++ b/chrome/browser/resources/new_tab_page/realbox/realbox.ts
@@ -5,7 +5,7 @@
 import 'chrome://resources/cr_components/omnibox/realbox_dropdown.js';
 import 'chrome://resources/cr_components/omnibox/realbox_icon.js';
 
-import {AutocompleteMatch, AutocompleteResult, NavigationPredictor, PageCallbackRouter, PageHandlerInterface} from 'chrome://resources/cr_components/omnibox/omnibox.mojom-webui.js';
+import {AutocompleteMatch, AutocompleteResult, NavigationPredictor, PageCallbackRouter, PageHandlerInterface, SideType} from 'chrome://resources/cr_components/omnibox/omnibox.mojom-webui.js';
 import {RealboxBrowserProxy} from 'chrome://resources/cr_components/omnibox/realbox_browser_proxy.js';
 import {RealboxDropdownElement} from 'chrome://resources/cr_components/omnibox/realbox_dropdown.js';
 import {RealboxIconElement} from 'chrome://resources/cr_components/omnibox/realbox_icon.js';
@@ -70,6 +70,13 @@
         reflectToAttribute: true,
       },
 
+      /** Whether the cr-realbox-dropdown should be visible. */
+      dropdownIsVisible: {
+        type: Boolean,
+        value: false,
+        reflectToAttribute: true,
+      },
+
       /**
        * Whether the secondary side was at any point available to be shown.
        */
@@ -92,13 +99,6 @@
         reflectToAttribute: true,
       },
 
-      /** Whether matches are currently visible. */
-      matchesAreVisible: {
-        type: Boolean,
-        value: false,
-        reflectToAttribute: true,
-      },
-
       /** Whether the realbox should match the searchbox. */
       matchSearchbox: {
         type: Boolean,
@@ -218,10 +218,10 @@
   }
 
   canShowSecondarySide: boolean;
+  dropdownIsVisible: boolean;
   hadSecondarySide: boolean;
   hasSecondarySide: boolean;
   isDark: boolean;
-  matchesAreVisible: boolean;
   matchSearchbox: boolean;
   realboxLensSearchEnabled: boolean;
   singleColoredIcons: boolean;
@@ -288,7 +288,13 @@
 
     this.result_ = result;
     const hasMatches = result?.matches?.length > 0;
-    this.matchesAreVisible = hasMatches;
+    const hasPrimaryMatches = result?.matches?.some(match => {
+      const sideType =
+          result.suggestionGroupsMap[match.suggestionGroupId]?.sideType ||
+          SideType.kDefaultPrimary;
+      return sideType === SideType.kDefaultPrimary;
+    });
+    this.dropdownIsVisible = hasPrimaryMatches;
 
     this.$.input.focus();
 
@@ -444,7 +450,7 @@
 
     // Query for zero-prefix matches if user is tabbing into an empty input and
     // matches are not visible.
-    if (!this.$.input.value && !this.matchesAreVisible) {
+    if (!this.$.input.value && !this.dropdownIsVisible) {
       this.queryAutocomplete_('');
     }
   }
@@ -456,7 +462,7 @@
 
     // Query for zero-prefix matches when the main (generally left) mouse button
     // is pressed on an empty input and matches are not visible.
-    if (!this.$.input.value && !this.matchesAreVisible) {
+    if (!this.$.input.value && !this.dropdownIsVisible) {
       this.queryAutocomplete_('');
     }
   }
@@ -475,7 +481,7 @@
         this.updateInput_({text: '', inline: ''});
         this.clearAutocompleteMatches_();
       } else {
-        this.matchesAreVisible = false;
+        this.dropdownIsVisible = false;
 
         // Stop autocomplete but leave (potentially stale) results and continue
         // listening for key presses. These stale results should never be shown.
@@ -507,7 +513,7 @@
     }
 
     // ArrowUp/ArrowDown query autocomplete when matches are not visible.
-    if (!this.matchesAreVisible) {
+    if (!this.dropdownIsVisible) {
       if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
         const inputValue = this.$.input.value;
         if (inputValue.trim() || !inputValue) {
@@ -642,7 +648,7 @@
   }
 
   private onLensSearchClick_() {
-    this.matchesAreVisible = false;
+    this.dropdownIsVisible = false;
     this.dispatchEvent(new Event('open-lens-search'));
   }
 
@@ -661,7 +667,7 @@
    * Clears the autocomplete result on the page and on the autocomplete backend.
    */
   private clearAutocompleteMatches_() {
-    this.matchesAreVisible = false;
+    this.dropdownIsVisible = false;
     this.result_ = null;
     this.$.matches.unselect();
     this.pageHandler_.stopAutocomplete(/*clearResult=*/ true);
@@ -678,7 +684,7 @@
     const delta =
         mojoTimeDelta(window.performance.now() - this.lastInputFocusTime_);
     this.pageHandler_.openAutocompleteMatch(
-        matchIndex, match.destinationUrl, this.matchesAreVisible, delta,
+        matchIndex, match.destinationUrl, this.dropdownIsVisible, delta,
         (e as MouseEvent).button || 0, e.altKey, e.ctrlKey, e.metaKey,
         e.shiftKey);
     e.preventDefault();
diff --git a/chrome/browser/resources/password_manager/passwords_importer.html b/chrome/browser/resources/password_manager/passwords_importer.html
index 534e631..f9b7ed3 100644
--- a/chrome/browser/resources/password_manager/passwords_importer.html
+++ b/chrome/browser/resources/password_manager/passwords_importer.html
@@ -9,11 +9,90 @@
     margin-bottom: var(--cr-form-field-bottom-spacing);
     margin-top: 2px; /* Needed to avoid outline cropping */
   }
+
+  .bold-text {
+    /* This class is issued directly in the following translated strings:
+      'importPasswordsSuccessTip', 'importPasswordsDeleteFileOption',
+      'importPasswordsBadFormatError'. */
+    font-weight: bold;
+  }
+
+  cr-dialog {
+    max-height: 70vh;
+  }
+
+  .flex {
+    display: flex;
+  }
+
+  iron-icon,
+  site-favicon {
+    height: 16px;
+    padding-inline-end: 10px;
+  }
+
+  .failed-row {
+    margin-inline-start: 20px;
+    padding-block: 8px;
+  }
+
+  /* Select all except the first of the class. */
+  .failed-row ~ .failed-row {
+    border-top: 1px solid var(--cr-separator-color);
+  }
+
+  .url-username-group {
+    display: grid;
+    grid-template-columns: fit-content(50%) 1fr;
+    width: 100%;
+  }
+
+  .website:not(:empty) {
+    margin-inline-end: 16px;
+  }
+
+  .error-status {
+    color: var(--error-color);
+    padding-inline-start: 26px;
+  }
+
+  #successIcon {
+    fill: var(--cr-checked-color);
+  }
+
+  .error-icon {
+    margin-block: auto;
+    --iron-icon-fill-color: var(--error-color);
+  }
+
+  #failuresSummary {
+    color: var(--cr-primary-text-color);
+    padding: 8px 0;
+  }
+
+  #failuresTitleRow {
+    margin-block: 16px 8px;
+  }
+
+  #tipBox {
+    align-items: center;
+    background: var(--google-grey-50);
+    border: 1px solid var(--cr-separator-color);
+    border-radius: 4px;
+    margin-top: 16px;
+    padding: 8px;
+  }
+
+  @media (prefers-color-scheme: dark) {
+    #tipBox {
+      background: var(--google-grey-900);
+    }
+  }
 </style>
 
-<cr-link-row id="linkRow" class="cr-row settings-cr-link-row"
+<cr-link-row id="linkRow" class="cr-row settings-cr-link-row" ariaShowLabel
     label="$i18n{importPasswords}" sub-label="[[bannerDescription_]]"
-    hide-icon$="[[showSelectFileButton_]]" ariaShowLabel
+    hide-icon$="[[shouldHideLinkRowIcon_(inProgress_, showSelectFileButton_)]]"
     ariaShowSublabel roleDescription="button" on-click="onBannerClick_">
   <template is="dom-if" if="[[showSelectFileButton_]]" restamp>
     <cr-button id="selectFileButton" on-click="onSelectFileClick_">
@@ -56,3 +135,56 @@
     </div>
   </cr-dialog>
 </template>
+
+<!-- SUCCESS dialog -->
+<template is="dom-if" if="[[isState_(dialogStateEnum_.SUCCESS, dialogState_)]]"
+    restamp>
+  <cr-dialog id="dialog" close-text="$i18n{close}" show-on-attach no-cancel>
+    <div slot="title" id="title">[[getSuccessDialogTitle_(results_)]]</div>
+    <div slot="body">
+      <div class="flex">
+        <iron-icon id="successIcon" icon="cr:check-circle"></iron-icon>
+        <div id="description">[[successDescription_]]</div>
+      </div>
+      <div id="tipBox" class="flex"
+          hidden="[[shouldHideTipBox_(results_)]]">
+         <iron-icon id="infoIcon" icon="cr:info-outline"></iron-icon>
+        <div id="successTip" inner-h-t-m-l="[[getSuccessTipHtml_(results_)]]">
+        </div>
+      </div>
+      <div hidden="[[shouldHideFailuresSummary_(results_)]]">
+        <div id="failuresTitleRow" class="flex-centered">
+          <iron-icon class="error-icon" icon="cr:warning"></iron-icon>
+          <div id="failuresSummary">[[failedImportsSummary_]]</div>
+        </div>
+        <template is="dom-repeat"
+            items="[[getFailedImportsWithKnownErrors_(results_)]]">
+          <div class="failed-row">
+            <div class="flex-centered">
+              <site-favicon domain="[[item.url]]" aria-hidden="true">
+              </site-favicon>
+              <div class="url-username-group">
+                <div class="website bold-text text-elide">[[item.url]]</div>
+                <div class="username text-elide">[[item.username]]</div>
+              </div>
+            </div>
+            <div class="error-status">
+              [[item.status]]
+              <!-- TODO(crbug/1432962): Fetch strings for each status. -->
+            </div>
+          </div>
+        </template>
+        <div class="failed-row" hidden="[[!showRowsWithUnknownErrorsSummary_]]">
+          <div class="error-status">[[rowsWithUnknownErrorsSummary_]]</div>
+        </div>
+      </div>
+    </div>
+    <div slot="button-container">
+      <cr-button id="closeButton" class="cancel-button"
+          on-click="onCloseClick_">
+        $i18n{close}
+      </cr-button>
+      <!-- TODO(crbug/1432962): Add "View passwords" button. -->
+    </div>
+  </cr-dialog>
+</template>
diff --git a/chrome/browser/resources/password_manager/passwords_importer.ts b/chrome/browser/resources/password_manager/passwords_importer.ts
index b4595ec2..4ebbb29 100644
--- a/chrome/browser/resources/password_manager/passwords_importer.ts
+++ b/chrome/browser/resources/password_manager/passwords_importer.ts
@@ -5,11 +5,14 @@
 import 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js';
 import 'chrome://resources/cr_elements/cr_button/cr_button.js';
 import 'chrome://resources/cr_elements/md_select.css.js';
+import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
 import 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js';
+import './site_favicon.js';
 
 import {CrLinkRowElement} from 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
-import {assert} from 'chrome://resources/js/assert_ts.js';
+import {assert, assertNotReached} from 'chrome://resources/js/assert_ts.js';
+import {PluralStringProxyImpl} from 'chrome://resources/js/plural_string_proxy.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {PasswordManagerImpl, PasswordManagerProxy} from './password_manager_proxy.js';
@@ -24,6 +27,7 @@
 enum DialogState {
   NO_DIALOG,
   STORE_PICKER,
+  SUCCESS,
 }
 
 const PasswordsImporterElementBase = I18nMixin(PolymerElement);
@@ -60,6 +64,16 @@
 
       selectedStoreOption_: String,
 
+      results_: Object,
+      successDescription_: String,
+      failedImportsSummary_: String,
+      rowsWithUnknownErrorsSummary_: String,
+
+      showRowsWithUnknownErrorsSummary_: {
+        type: Boolean,
+        value: false,
+      },
+
       showSelectFileButton_: {
         type: Boolean,
         computed: 'computeShowSelectFileButton_(isAccountStoreUser,' +
@@ -93,6 +107,11 @@
   private selectedStoreOption_: string;
   private showSelectFileButton_: boolean;
   private bannerDescription_: string;
+  private results_: chrome.passwordsPrivate.ImportResults|null = null;
+  private successDescription_: string;
+  private failedImportsSummary_: string;
+  private rowsWithUnknownErrorsSummary_: string;
+  private showRowsWithUnknownErrorsSummary_: boolean;
   private passwordManager_: PasswordManagerProxy =
       PasswordManagerImpl.getInstance();
 
@@ -170,12 +189,114 @@
     // Close the dialog while import is in progress or the user selects a file.
     this.closeDialog_();
 
-    await this.passwordManager_.importPasswords(destinationStore);
-
-    // TODO(crbug/1432962): Add handler for the results of importPasswords.
+    this.results_ =
+        await this.passwordManager_.importPasswords(destinationStore);
+    await this.processResults_();
     this.inProgress_ = false;
   }
 
+  private async processResults_() {
+    assert(this.results_);
+    switch (this.results_.status) {
+      case chrome.passwordsPrivate.ImportResultsStatus.SUCCESS:
+        await this.handleSuccess_();
+        return;
+      case chrome.passwordsPrivate.ImportResultsStatus.CONFLICTS:
+      case chrome.passwordsPrivate.ImportResultsStatus.IO_ERROR:
+      case chrome.passwordsPrivate.ImportResultsStatus.UNKNOWN_ERROR:
+      case chrome.passwordsPrivate.ImportResultsStatus.NUM_PASSWORDS_EXCEEDED:
+      case chrome.passwordsPrivate.ImportResultsStatus.BAD_FORMAT:
+      case chrome.passwordsPrivate.ImportResultsStatus.MAX_FILE_SIZE:
+      case chrome.passwordsPrivate.ImportResultsStatus.IMPORT_ALREADY_ACTIVE:
+        // TODO(crbug/1432962): Handle each status.
+        break;
+      case chrome.passwordsPrivate.ImportResultsStatus.DISMISSED:
+        // Dialog state should not change if a system file picker was dismissed.
+        break;
+      default:
+        assertNotReached();
+    }
+  }
+
+  private getFailedImportsWithKnownErrors_():
+      chrome.passwordsPrivate.ImportEntry[] {
+    assert(this.results_);
+    return this.results_.displayedEntries.filter(
+        (entry) => entry.status !==
+            chrome.passwordsPrivate.ImportEntryStatus.UNKNOWN_ERROR);
+  }
+
+  private async handleSuccess_() {
+    assert(this.results_);
+    if (this.results_.displayedEntries.length) {
+      const rowsWithUnknownErrorCount =
+          this.results_.displayedEntries
+              .filter(
+                  (entry) => entry.status ===
+                      chrome.passwordsPrivate.ImportEntryStatus.UNKNOWN_ERROR)
+              .length;
+      this.failedImportsSummary_ =
+          await PluralStringProxyImpl.getInstance().getPluralString(
+              'importPasswordsFailuresSummary',
+              this.results_.displayedEntries.length);
+      if (rowsWithUnknownErrorCount) {
+        this.rowsWithUnknownErrorsSummary_ =
+            await PluralStringProxyImpl.getInstance().getPluralString(
+                'importPasswordsBadRowsFormat', rowsWithUnknownErrorCount);
+        this.showRowsWithUnknownErrorsSummary_ = true;
+      }
+    }
+    if (this.passwordsSavedToAccount_) {
+      let descriptionText =
+          await PluralStringProxyImpl.getInstance().getPluralString(
+              'importPasswordsSuccessSummaryAccount',
+              this.results_.numberImported);
+      descriptionText =
+          descriptionText.replace('$1', this.i18n('localPasswordManager'));
+      this.successDescription_ =
+          descriptionText.replace('$2', this.accountEmail);
+    } else {
+      const descriptionText =
+          await PluralStringProxyImpl.getInstance().getPluralString(
+              'importPasswordsSuccessSummaryDevice',
+              this.results_.numberImported);
+      this.successDescription_ =
+          descriptionText.replace('$1', this.i18n('localPasswordManager'));
+    }
+
+    this.dialogState_ = DialogState.SUCCESS;
+  }
+
+  private getSuccessDialogTitle_(): string {
+    assert(this.results_);
+    return this.results_.displayedEntries.length ?
+        this.i18n('importPasswordsCompleteTitle') :
+        this.i18n('importPasswordsSuccessTitle');
+  }
+
+  private getSuccessTipHtml_(): TrustedHTML {
+    assert(this.results_);
+    return this.i18nAdvanced(
+        'importPasswordsSuccessTip',
+        {attrs: ['class'], substitutions: [this.results_.fileName]});
+  }
+
+  private shouldHideLinkRowIcon_(): boolean {
+    return this.inProgress_ || this.showSelectFileButton_;
+  }
+
+  private shouldHideTipBox_(): boolean {
+    // Tip box is only shown in "success" state if all passwords were imported.
+    // TODO(crbug/1432962): Also hide when import M2 is enabled.
+    assert(this.results_);
+    return !!this.results_.displayedEntries.length;
+  }
+
+  private shouldHideFailuresSummary_(): boolean {
+    assert(this.results_);
+    return !this.results_.displayedEntries.length;
+  }
+
   private getStoreOptionAccountText_(): string {
     assert(this.accountEmail);
     return this.i18n(
diff --git a/chrome/browser/resources/password_manager/shared_vars.css b/chrome/browser/resources/password_manager/shared_vars.css
index 7726dbc2..afd7a2d1 100644
--- a/chrome/browser/resources/password_manager/shared_vars.css
+++ b/chrome/browser/resources/password_manager/shared_vars.css
@@ -22,4 +22,12 @@
   --section-min-height: 48px;
   /* Spacing between a control (e.g. checkbox) and its label. */
   --two-line-section-min-height: 64px;
+
+  --error-color: var(--google-red-700);
+}
+
+@media (prefers-color-scheme: dark) {
+  html {
+    --error-color: var(--google-red-300);
+  }
 }
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.html b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.html
index 2c464513..c44bbedc 100644
--- a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.html
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.html
@@ -158,7 +158,7 @@
             on-change="onTranslateCheckboxChange_"
             hidden="[[!prefs.translate.enabled.value]]"
             disabled="[[disableTranslateCheckbox_(
-                detailLanguage_.state, languages.translateTarget)]]">
+                detailLanguage_.state, languages.translateTarget)]]" noink>
           $i18n{offerToTranslateThisLanguage}
         </cr-checkbox>
         <button class="dropdown-item" role="menuitem"
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/lock_screen_subpage.html b/chrome/browser/resources/settings/chromeos/os_people_page/lock_screen_subpage.html
index 73d40cd..8d3842b 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/lock_screen_subpage.html
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/lock_screen_subpage.html
@@ -46,6 +46,13 @@
     padding-inline-start: 16px;
     width: 100%;
   }
+
+  #recoveryWarning iron-icon[icon='cr:info-outline'] {
+    --iron-icon-width: 1rem;
+    --iron-icon-height: 1rem;
+    --iron-icon-fill-color: var(--cros-text-color-secondary);
+    margin-inline-end: 10px;
+  }
 </style>
 <div>
   <settings-toggle-button id="enableLockScreen"
@@ -145,6 +152,16 @@
         on-settings-boolean-control-change="onRecoveryChange_">
     </settings-toggle-button>
   </template>
+  <template is="dom-if" if="[[showRecoveryWarning_(cryptohomeRecoveryEnabled_,
+                                recovery_)]]">
+    <div id="recoveryWarning" class="settings-box">
+      <iron-icon icon="cr:info-outline"></iron-icon>
+      <localized-link
+        localized-string="$i18n{recoveryNotSupportedMessage}"
+        link-url="$i18nRaw{recoveryLearnMoreUrl}">
+      </localized-link>
+    </div>
+  </template>
   <template is="dom-if" if="[[showDisableRecoveryDialog_]]" restamp>
     <local-data-recovery-dialog id="localDataRecoveryDialog"
       auth-token="[[authToken]]"
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/lock_screen_subpage.ts b/chrome/browser/resources/settings/chromeos/os_people_page/lock_screen_subpage.ts
index a5b50f0..c2b5c3ca 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/lock_screen_subpage.ts
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/lock_screen_subpage.ts
@@ -159,6 +159,17 @@
       },
 
       /**
+       * True if cryptohome recovery feature is enabled.
+       */
+      cryptohomeRecoveryEnabled_: {
+        type: Boolean,
+        value() {
+          return loadTimeData.getBoolean('cryptohomeRecoveryEnabled');
+        },
+        readOnly: true,
+      },
+
+      /**
        * State of the recovery toggle. Is |null| iff recovery is not a
        * available.
        */
@@ -225,6 +236,7 @@
   private numFingerprintDescription_: string;
   private lockScreenNotificationsEnabled_: boolean;
   private lockScreenHideSensitiveNotificationSupported_: boolean;
+  private cryptohomeRecoveryEnabled_: boolean;
   private recovery_: chrome.settingsPrivate.PrefObject|null;
   private recoveryChangeInProcess_: boolean;
   private quickUnlockPinAutosubmitFeatureEnabled_: boolean;
@@ -423,6 +435,10 @@
     return selectedUnlockType === LockScreenUnlockType.PIN_PASSWORD;
   }
 
+  private showRecoveryWarning_(): boolean {
+    return this.cryptohomeRecoveryEnabled_ && this.recovery_ === null;
+  }
+
   private getSetupPinText_(hasPin: boolean): string {
     if (hasPin) {
       return this.i18n('lockScreenChangePinButton');
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.html b/chrome/browser/resources/settings/languages_page/languages_page.html
index d16da15..382f1e7 100644
--- a/chrome/browser/resources/settings/languages_page/languages_page.html
+++ b/chrome/browser/resources/settings/languages_page/languages_page.html
@@ -130,7 +130,7 @@
                 languages.prospectiveUILanguage)]]"
             on-change="onUiLanguageChange_"
             disabled="[[disableUiLanguageCheckbox_(
-                detailLanguage_, languages.prospectiveUILanguage)]]">
+                detailLanguage_, languages.prospectiveUILanguage)]]" noink>
           <span>
             $i18n{displayInThisLanguage}
           </span>
@@ -146,7 +146,7 @@
               on-change="onTranslateCheckboxChange_"
               hidden="[[!prefs.translate.enabled.value]]"
               disabled="[[disableTranslateCheckbox_(
-                  detailLanguage_, languages.translateTarget)]]">
+                  detailLanguage_, languages.translateTarget)]]" noink>
             $i18n{offerToTranslateInThisLanguage} </cr-checkbox>
           <hr hidden="[[!shouldShowDialogSeparator_(languages.enabled.*)]]">
         </template>
diff --git a/chrome/browser/storage/shared_storage_browsertest.cc b/chrome/browser/storage/shared_storage_browsertest.cc
index 15f3a81..5698beb 100644
--- a/chrome/browser/storage/shared_storage_browsertest.cc
+++ b/chrome/browser/storage/shared_storage_browsertest.cc
@@ -390,14 +390,9 @@
   }
 
   virtual bool ResolveSelectURLToConfig() const { return false; }
-  virtual bool BlinkStyleWorkletImplementation() const { return false; }
 
   std::string ExpectedSharedStorageDisabledMessage() {
-    if (BlinkStyleWorkletImplementation()) {
-      return "Error: " + content::GetSharedStorageDisabledMessage();
-    }
-
-    return content::GetSharedStorageDisabledMessage();
+    return "Error: " + content::GetSharedStorageDisabledMessage();
   }
 
  protected:
@@ -410,16 +405,9 @@
 
 class SharedStorageChromeBrowserTest
     : public SharedStorageChromeBrowserTestBase,
-      public testing::WithParamInterface<std::tuple<bool, bool>> {
+      public testing::WithParamInterface<bool> {
  public:
   SharedStorageChromeBrowserTest() {
-    shared_storage_feature_.InitWithFeaturesAndParameters(
-        /*enabled_features=*/
-        {{blink::features::kSharedStorageAPI,
-          {{"SharedStorageWorkletImplementationType",
-            BlinkStyleWorkletImplementation() ? "blink_style" : "legacy"}}}},
-        /*disabled_features=*/{});
-
     fenced_frame_api_change_feature_.InitWithFeatureState(
         blink::features::kFencedFramesAPIChanges, ResolveSelectURLToConfig());
 
@@ -427,16 +415,9 @@
   }
   ~SharedStorageChromeBrowserTest() override = default;
 
-  bool ResolveSelectURLToConfig() const override {
-    return std::get<0>(GetParam());
-  }
-
-  bool BlinkStyleWorkletImplementation() const override {
-    return std::get<1>(GetParam());
-  }
+  bool ResolveSelectURLToConfig() const override { return GetParam(); }
 
  private:
-  base::test::ScopedFeatureList shared_storage_feature_;
   base::test::ScopedFeatureList fenced_frame_api_change_feature_;
   base::test::ScopedFeatureList fenced_frame_feature_;
 };
@@ -444,20 +425,13 @@
 using SharedStorageChromeBrowserParams =
     std::tuple</*resolve_to_config=*/bool,
                /*enable_privacy_sandbox=*/bool,
-               /*allow_third_party_cookies=*/bool,
-               /*blink_style_worklet_implementation=*/bool>;
+               /*allow_third_party_cookies=*/bool>;
 
 class SharedStoragePrefBrowserTest
     : public SharedStorageChromeBrowserTestBase,
       public testing::WithParamInterface<SharedStorageChromeBrowserParams> {
  public:
   SharedStoragePrefBrowserTest() {
-    shared_storage_feature_.InitWithFeaturesAndParameters(
-        /*enabled_features=*/
-        {{blink::features::kSharedStorageAPI,
-          {{"SharedStorageWorkletImplementationType",
-            BlinkStyleWorkletImplementation() ? "blink_style" : "legacy"}}}},
-        /*disabled_features=*/{});
     fenced_frame_api_change_feature_.InitWithFeatureState(
         blink::features::kFencedFramesAPIChanges, ResolveSelectURLToConfig());
     fenced_frame_feature_.InitAndEnableFeature(blink::features::kFencedFrames);
@@ -468,9 +442,6 @@
   }
   bool EnablePrivacySandbox() const { return std::get<1>(GetParam()); }
   bool AllowThirdPartyCookies() const { return std::get<2>(GetParam()); }
-  bool BlinkStyleWorkletImplementation() const override {
-    return std::get<3>(GetParam());
-  }
 
   bool SuccessExpected() {
     return EnablePrivacySandbox() && AllowThirdPartyCookies();
@@ -588,7 +559,6 @@
   }
 
  private:
-  base::test::ScopedFeatureList shared_storage_feature_;
   base::test::ScopedFeatureList fenced_frame_api_change_feature_;
   base::test::ScopedFeatureList fenced_frame_feature_;
 };
@@ -596,18 +566,13 @@
 INSTANTIATE_TEST_SUITE_P(
     All,
     SharedStoragePrefBrowserTest,
-    testing::Combine(testing::Bool(),
-                     testing::Bool(),
-                     testing::Bool(),
-                     testing::Bool()),
+    testing::Combine(testing::Bool(), testing::Bool(), testing::Bool()),
     [](const testing::TestParamInfo<SharedStoragePrefBrowserTest::ParamType>&
            info) {
       return base::StrCat(
           {"ResolveSelectURLTo", std::get<0>(info.param) ? "Config" : "URN",
            "_PrivacySandbox", std::get<1>(info.param) ? "Enabled" : "Disabled",
-           "_3PCookies", std::get<2>(info.param) ? "Allowed" : "Blocked",
-           std::get<3>(info.param) ? "_BlinkStyle" : "_Legacy",
-           "WorkletImplementation"});
+           "_3PCookies", std::get<2>(info.param) ? "Allowed" : "Blocked"});
     });
 
 IN_PROC_BROWSER_TEST_P(SharedStoragePrefBrowserTest, AddModule) {
@@ -1819,43 +1784,6 @@
   histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
 }
 
-IN_PROC_BROWSER_TEST_P(SharedStorageChromeBrowserTest, Run_NotAPromiseError) {
-  // The blink-style worklet implementation doesn't consider this scenario as
-  // erroneous (i.e. the operation class's run() function isn't explicitly
-  // marked async). Since the legacy architecture will be removed soon and this
-  // is a minor behavior difference, we won't bother aligning the behaviors.
-  if (BlinkStyleWorkletImplementation()) {
-    return;
-  }
-
-  EXPECT_TRUE(content::NavigateToURL(
-      GetActiveWebContents(),
-      https_server()->GetURL(kSimpleTestHost, kSimplePagePath)));
-
-  GURL script_url = https_server()->GetURL(
-      kSimpleTestHost, "/shared_storage/erroneous_module3.js");
-  EXPECT_TRUE(content::ExecJs(
-      GetActiveWebContents(),
-      content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)));
-
-  EXPECT_TRUE(content::ExecJs(GetActiveWebContents(),
-                              R"(
-      sharedStorage.run(
-          'test-operation', {data: {}});
-    )"));
-
-  // Navigate away to record `kWorkletNumPerPageHistogram` histogram.
-  EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
-                                     GURL(url::kAboutBlankURL)));
-  WaitForHistograms({kTimingDocumentAddModuleHistogram, kErrorTypeHistogram,
-                     kWorkletNumPerPageHistogram});
-  histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
-  histogram_tester_.ExpectUniqueSample(
-      kErrorTypeHistogram,
-      blink::SharedStorageWorkletErrorType::kRunNonWebVisible, 1);
-  histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
-}
-
 IN_PROC_BROWSER_TEST_P(SharedStorageChromeBrowserTest, Run_ScriptError) {
   EXPECT_TRUE(content::NavigateToURL(
       GetActiveWebContents(),
@@ -2056,63 +1984,6 @@
   histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
 }
 
-IN_PROC_BROWSER_TEST_P(SharedStorageChromeBrowserTest,
-                       SelectUrl_NotAPromiseError) {
-  // The blink-style worklet implementation doesn't consider this scenario as
-  // erroneous (i.e. the operation class's run() function isn't explicitly
-  // marked async). Since the legacy architecture will be removed soon and this
-  // is a minor behavior difference, we won't bother aligning the behaviors.
-  if (BlinkStyleWorkletImplementation()) {
-    return;
-  }
-
-  EXPECT_TRUE(content::NavigateToURL(
-      GetActiveWebContents(),
-      https_server()->GetURL(kSimpleTestHost, kSimplePagePath)));
-
-  GURL script_url = https_server()->GetURL(
-      kSimpleTestHost, "/shared_storage/erroneous_module3.js");
-  EXPECT_TRUE(content::ExecJs(
-      GetActiveWebContents(),
-      content::JsReplace("sharedStorage.worklet.addModule($1)", script_url)));
-
-  EXPECT_TRUE(ExecJs(GetActiveWebContents(),
-                     content::JsReplace("window.resolveSelectURLToConfig = $1;",
-                                        ResolveSelectURLToConfig())));
-  EXPECT_TRUE(content::ExecJs(GetActiveWebContents(), R"(
-        (async function() {
-          window.select_url_result = await sharedStorage.selectURL(
-            'test-url-selection-operation',
-            [
-              {
-                url: "fenced_frames/title0.html"
-              }
-            ],
-            {
-              data: {},
-              resolveToConfig: resolveSelectURLToConfig
-            }
-          );
-          if (resolveSelectURLToConfig &&
-              !(select_url_result instanceof FencedFrameConfig)) {
-            throw new Error('selectURL() did not return a FencedFrameConfig.');
-          }
-          return window.select_url_result;
-        })()
-      )"));
-
-  // Navigate away to record `kWorkletNumPerPageHistogram` histogram.
-  EXPECT_TRUE(content::NavigateToURL(GetActiveWebContents(),
-                                     GURL(url::kAboutBlankURL)));
-  WaitForHistograms({kTimingDocumentAddModuleHistogram, kErrorTypeHistogram,
-                     kWorkletNumPerPageHistogram});
-  histogram_tester_.ExpectTotalCount(kTimingDocumentAddModuleHistogram, 1);
-  histogram_tester_.ExpectUniqueSample(
-      kErrorTypeHistogram,
-      blink::SharedStorageWorkletErrorType::kSelectURLNonWebVisible, 1);
-  histogram_tester_.ExpectUniqueSample(kWorkletNumPerPageHistogram, 1, 1);
-}
-
 IN_PROC_BROWSER_TEST_P(SharedStorageChromeBrowserTest, SelectUrl_ScriptError) {
   EXPECT_TRUE(content::NavigateToURL(
       GetActiveWebContents(),
@@ -2499,21 +2370,17 @@
             histogram_tester_.GetAllSamples(kTimingWorkletSetHistogram).size());
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    SharedStorageChromeBrowserTest,
-    testing::Combine(testing::Bool(), testing::Bool()),
-    [](const testing::TestParamInfo<SharedStorageChromeBrowserTest::ParamType>&
-           info) {
-      return base::StrCat({"ResolveSelectURLTo",
-                           std::get<0>(info.param) ? "Config" : "URN",
-                           std::get<1>(info.param) ? "_BlinkStyle" : "_Legacy",
-                           "WorkletImplementation"});
-    });
+INSTANTIATE_TEST_SUITE_P(All,
+                         SharedStorageChromeBrowserTest,
+                         testing::Bool(),
+                         [](const testing::TestParamInfo<
+                             SharedStorageChromeBrowserTest::ParamType>& info) {
+                           return base::StrCat({"ResolveSelectURLTo",
+                                                info.param ? "Config" : "URN"});
+                         });
 
 class SharedStorageFencedFrameChromeBrowserTest
-    : public SharedStorageChromeBrowserTestBase,
-      public testing::WithParamInterface<bool> {
+    : public SharedStorageChromeBrowserTestBase {
  public:
   SharedStorageFencedFrameChromeBrowserTest() {
     base::test::TaskEnvironment task_environment;
@@ -2521,9 +2388,7 @@
     shared_storage_feature_.InitWithFeaturesAndParameters(
         /*enabled_features=*/
         {{blink::features::kSharedStorageAPI,
-          {{"SharedStorageBitBudget", base::NumberToString(kBudgetAllowed)},
-           {"SharedStorageWorkletImplementationType",
-            BlinkStyleWorkletImplementation() ? "blink_style" : "legacy"}}}},
+          {{"SharedStorageBitBudget", base::NumberToString(kBudgetAllowed)}}}},
         /*disabled_features=*/{});
 
     fenced_frame_api_change_feature_.InitAndEnableFeature(
@@ -2536,8 +2401,6 @@
 
   bool ResolveSelectURLToConfig() const override { return true; }
 
-  bool BlinkStyleWorkletImplementation() const override { return GetParam(); }
-
   content::RenderFrameHost* SelectURLAndCreateFencedFrame(
       content::RenderFrameHost* render_frame_host,
       bool should_add_module = true,
@@ -2630,7 +2493,7 @@
   base::test::ScopedFeatureList fenced_frame_feature_;
 };
 
-IN_PROC_BROWSER_TEST_P(SharedStorageFencedFrameChromeBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageFencedFrameChromeBrowserTest,
                        FencedFrameNavigateTop_BudgetWithdrawal) {
   GURL main_url = https_server()->GetURL(kSimpleTestHost, kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(GetActiveWebContents(), main_url));
@@ -2678,7 +2541,7 @@
   EXPECT_EQ(2, histogram_tester_.GetTotalSum(kWorkletNumPerPageHistogram));
 }
 
-IN_PROC_BROWSER_TEST_P(
+IN_PROC_BROWSER_TEST_F(
     SharedStorageFencedFrameChromeBrowserTest,
     TwoFencedFrames_DifferentURNs_EachNavigateOnce_BudgetWithdrawalTwice) {
   GURL main_url = https_server()->GetURL(kSimpleTestHost, kSimplePagePath);
@@ -2750,14 +2613,4 @@
   EXPECT_EQ(3, histogram_tester_.GetTotalSum(kWorkletNumPerPageHistogram));
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    SharedStorageFencedFrameChromeBrowserTest,
-    testing::Bool(),
-    [](const testing::TestParamInfo<
-        SharedStorageFencedFrameChromeBrowserTest::ParamType>& info) {
-      return base::StrCat(
-          {info.param ? "BlinkStyle" : "Legacy", "WorkletImplementation"});
-    });
-
 }  // namespace storage
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 65d7e815..cf23b84b 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -81,6 +81,8 @@
     "autofill/risk_util.h",
     "autofill/test/test_autofill_bubble_handler.cc",
     "autofill/test/test_autofill_bubble_handler.h",
+    "autofill/ui_util.cc",
+    "autofill/ui_util.h",
     "blocked_content/blocked_window_params.cc",
     "blocked_content/blocked_window_params.h",
     "blocked_content/chrome_popup_navigation_delegate.cc",
diff --git a/chrome/browser/ui/autofill/edit_address_profile_dialog_controller.h b/chrome/browser/ui/autofill/edit_address_profile_dialog_controller.h
index 98b3eda..6f35b64c9 100644
--- a/chrome/browser/ui/autofill/edit_address_profile_dialog_controller.h
+++ b/chrome/browser/ui/autofill/edit_address_profile_dialog_controller.h
@@ -16,6 +16,7 @@
   virtual ~EditAddressProfileDialogController() = default;
 
   virtual std::u16string GetWindowTitle() const = 0;
+  virtual const std::u16string& GetFooterMessage() const = 0;
   virtual std::u16string GetOkButtonLabel() const = 0;
   virtual const AutofillProfile& GetProfileToEdit() const = 0;
   virtual bool GetIsValidatable() const = 0;
diff --git a/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.cc b/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.cc
index 48928eb..872f28d 100644
--- a/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.h"
+#include <string>
 
 #include "base/types/optional_util.h"
 #include "chrome/browser/ui/autofill/autofill_bubble_base.h"
@@ -33,6 +34,7 @@
 void EditAddressProfileDialogControllerImpl::OfferEdit(
     const AutofillProfile& profile,
     const AutofillProfile* original_profile,
+    const std::u16string& footer_message,
     AutofillClient::AddressProfileSavePromptCallback
         address_profile_save_prompt_callback,
     bool is_migration_to_account) {
@@ -45,6 +47,7 @@
   }
   address_profile_to_edit_ = profile;
   original_profile_ = base::OptionalFromPtr(original_profile);
+  footer_message_ = footer_message;
   address_profile_save_prompt_callback_ =
       std::move(address_profile_save_prompt_callback);
   is_migration_to_account_ = is_migration_to_account;
@@ -58,6 +61,11 @@
   return l10n_util::GetStringUTF16(IDS_AUTOFILL_EDIT_ADDRESS_DIALOG_TITLE);
 }
 
+const std::u16string& EditAddressProfileDialogControllerImpl::GetFooterMessage()
+    const {
+  return footer_message_;
+}
+
 std::u16string EditAddressProfileDialogControllerImpl::GetOkButtonLabel()
     const {
   return l10n_util::GetStringUTF16(
diff --git a/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.h b/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.h
index 1d9c4a54..e8e090b 100644
--- a/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.h
+++ b/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.h
@@ -37,12 +37,14 @@
   // re-open the original prompt in a correct state.
   void OfferEdit(const AutofillProfile& profile,
                  const AutofillProfile* original_profile,
+                 const std::u16string& footer_message,
                  AutofillClient::AddressProfileSavePromptCallback
                      address_profile_save_prompt_callback,
                  bool is_migration_to_account);
 
   // EditAddressProfileDialogController:
   std::u16string GetWindowTitle() const override;
+  const std::u16string& GetFooterMessage() const override;
   std::u16string GetOkButtonLabel() const override;
   const AutofillProfile& GetProfileToEdit() const override;
   bool GetIsValidatable() const override;
@@ -66,6 +68,9 @@
   // nullptr if no dialog is currently shown.
   raw_ptr<AutofillBubbleBase> dialog_view_ = nullptr;
 
+  // Editor's footnote message.
+  std::u16string footer_message_;
+
   // Callback to run once the user makes a decision with respect to saving the
   // address profile currently being edited.
   AutofillClient::AddressProfileSavePromptCallback
diff --git a/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl_browsertest.cc b/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl_browsertest.cc
index 555ffcb1..316f4bc 100644
--- a/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl_browsertest.cc
+++ b/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl_browsertest.cc
@@ -30,6 +30,7 @@
     DCHECK(controller);
     controller->OfferEdit(
         test::GetFullProfile(), /*original_profile=*/nullptr,
+        /*footer_message=*/u"",
         /*address_profile_save_prompt_callback=*/base::DoNothing(),
         /*is_migration=*/false);
   }
diff --git a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller.h b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller.h
index 5782701..a8e9a36 100644
--- a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller.h
+++ b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller.h
@@ -6,6 +6,9 @@
 #define CHROME_BROWSER_UI_AUTOFILL_SAVE_UPDATE_ADDRESS_PROFILE_BUBBLE_CONTROLLER_H_
 
 #include "components/autofill/core/browser/autofill_client.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/base/models/image_model.h"
+#include "ui/gfx/geometry/point.h"
 
 namespace autofill {
 
@@ -13,11 +16,21 @@
 // bubble.
 class SaveUpdateAddressProfileBubbleController {
  public:
+  struct HeaderImages {
+    ui::ImageModel light;
+    ui::ImageModel dark;
+  };
+
   virtual ~SaveUpdateAddressProfileBubbleController() = default;
 
   virtual std::u16string GetWindowTitle() const = 0;
+  virtual absl::optional<HeaderImages> GetHeaderImages() const = 0;
+  virtual std::u16string GetBodyText() const = 0;
+  virtual std::u16string GetAddressSummary() const = 0;
+  virtual std::u16string GetProfileEmail() const = 0;
+  virtual std::u16string GetProfilePhone() const = 0;
   virtual std::u16string GetOkButtonLabel() const = 0;
-  virtual absl::optional<std::u16string> GetFooterMessage() const = 0;
+  virtual std::u16string GetFooterMessage() const = 0;
   virtual const AutofillProfile& GetProfileToSave() const = 0;
   virtual const AutofillProfile* GetOriginalProfile() const = 0;
   virtual void OnUserDecision(
diff --git a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.cc b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.cc
index 3856654..3068631 100644
--- a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.cc
@@ -4,26 +4,119 @@
 
 #include "chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.h"
 
+#include <array>
+#include <string>
+#include <vector>
+
+#include "base/check.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/types/optional_util.h"
+#include "chrome/browser/autofill/personal_data_manager_factory.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/autofill/autofill_bubble_handler.h"
 #include "chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.h"
+#include "chrome/browser/ui/autofill/ui_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/grit/theme_resources.h"
+#include "components/autofill/content/browser/content_autofill_client.h"
+#include "components/autofill/core/browser/autofill_address_util.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/common/autofill_features.h"
+#include "components/signin/public/identity_manager/account_info.h"
 #include "components/strings/grit/components_strings.h"
+#include "skia/ext/image_operations.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/image_model.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/color/color_id.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/canvas_image_source.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_operations.h"
 
 namespace autofill {
 
+namespace {
+
+// CanvasImageSource that combines a background image with user's avatar,
+// the avatar is positioned and resized in terms of the background image DIPs,
+// it also is cropped in a circle.
+class MigrationHeaderImageSource : public gfx::CanvasImageSource {
+ public:
+  MigrationHeaderImageSource(const ui::ImageModel& image,
+                             const ui::ImageModel& avatar,
+                             const gfx::Point& avatar_position,
+                             size_t avatar_size)
+      : gfx::CanvasImageSource(image.Size()),
+        image_(image),
+        avatar_(avatar),
+        avatar_position_(avatar_position),
+        avatar_size_(avatar_size) {}
+
+  MigrationHeaderImageSource(const MigrationHeaderImageSource&) = delete;
+  MigrationHeaderImageSource& operator=(const MigrationHeaderImageSource&) =
+      delete;
+
+  ~MigrationHeaderImageSource() override = default;
+
+  // gfx::CanvasImageSource:
+  void Draw(gfx::Canvas* canvas) override;
+
+ private:
+  const ui::ImageModel image_;
+  const ui::ImageModel avatar_;
+  const gfx::Point avatar_position_;
+  const size_t avatar_size_;
+};
+
+void MigrationHeaderImageSource::Draw(gfx::Canvas* canvas) {
+  // Draw the background image first.
+  gfx::ImageSkia image = image_.GetImage().AsImageSkia();
+  canvas->DrawImageInt(image, 0, 0);
+
+  // Setting a clippath makes subsequent avatar drawing cropped in a circle.
+  SkPath avatar_bound = SkPath().addOval(
+      SkRect::MakeXYWH(avatar_position_.x(), avatar_position_.y(),
+                       /*w=*/avatar_size_, /*h=*/avatar_size_));
+  canvas->ClipPath(avatar_bound, /*do_anti_alias=*/true);
+
+  // Finally draw the avatar, above the background and cropped.
+  gfx::ImageSkia avatar = gfx::ImageSkiaOperations::CreateResizedImage(
+      avatar_.GetImage().AsImageSkia(),
+      skia::ImageOperations::ResizeMethod::RESIZE_BEST,
+      gfx::Size(avatar_size_, avatar_size_));
+  canvas->DrawImageInt(avatar, avatar_position_.x(), avatar_position_.y());
+}
+
+ui::ImageModel EmbedAvatar(int background_id,
+                           const ui::ImageModel& avatar,
+                           const gfx::Point& position,
+                           size_t size) {
+  return ui::ImageModel::FromImageSkia(
+      gfx::CanvasImageSource::MakeImageSkia<MigrationHeaderImageSource>(
+          ui::ImageModel::FromResourceId(background_id), avatar, position,
+          size));
+}
+
+}  // namespace
+
 SaveUpdateAddressProfileBubbleControllerImpl::
     SaveUpdateAddressProfileBubbleControllerImpl(
         content::WebContents* web_contents)
     : AutofillBubbleControllerBase(web_contents),
       content::WebContentsUserData<
-          SaveUpdateAddressProfileBubbleControllerImpl>(*web_contents) {}
+          SaveUpdateAddressProfileBubbleControllerImpl>(*web_contents),
+      app_locale_(g_browser_process->GetApplicationLocale()) {}
 
 SaveUpdateAddressProfileBubbleControllerImpl::
     ~SaveUpdateAddressProfileBubbleControllerImpl() {
@@ -83,6 +176,105 @@
   return l10n_util::GetStringUTF16(IDS_AUTOFILL_UPDATE_ADDRESS_PROMPT_TITLE);
 }
 
+absl::optional<SaveUpdateAddressProfileBubbleController::HeaderImages>
+SaveUpdateAddressProfileBubbleControllerImpl::GetHeaderImages() const {
+  if (is_migration_to_account_) {
+    absl::optional<AccountInfo> account =
+        GetPrimaryAccountInfoFromBrowserContext(
+            web_contents()->GetBrowserContext());
+    if (account) {
+      ui::ImageModel avatar = ui::ImageModel::FromImage(account->account_image);
+      // The position and size must match the implied one in the image,
+      // so these numbers are exclusively for ..._AVATAR50_X135_Y54.
+      static constexpr gfx::Point kAvatarPosition{135, 54};
+      static constexpr size_t kAvatarSize{50};
+      return HeaderImages{
+          .light = EmbedAvatar(IDR_MIGRATE_ADDRESS_AVATAR50_X135_Y54, avatar,
+                               kAvatarPosition, kAvatarSize),
+          .dark = EmbedAvatar(IDR_MIGRATE_ADDRESS_AVATAR50_X135_Y54_DARK,
+                              avatar, kAvatarPosition, kAvatarSize)};
+    }
+  } else if (IsSaveBubble()) {
+    return HeaderImages{
+        .light = ui::ImageModel::FromResourceId(IDR_SAVE_ADDRESS),
+        .dark = ui::ImageModel::FromResourceId(IDR_SAVE_ADDRESS_DARK)};
+  }
+
+  return absl::nullopt;
+}
+
+std::u16string SaveUpdateAddressProfileBubbleControllerImpl::GetBodyText()
+    const {
+  if (is_migration_to_account_) {
+    PersonalDataManager* pdm =
+        ContentAutofillClient::FromWebContents(web_contents())
+            ->GetPersonalDataManager();
+
+    absl::optional<AccountInfo> account =
+        GetPrimaryAccountInfoFromBrowserContext(
+            web_contents()->GetBrowserContext());
+
+    int string_id = pdm->IsSyncEnabledFor(syncer::ModelType::AUTOFILL_PROFILE)
+                        ? IDS_AUTOFILL_SYNCABLE_PROFILE_MIGRATION_PROMPT_NOTICE
+                        : IDS_AUTOFILL_LOCAL_PROFILE_MIGRATION_PROMPT_NOTICE;
+
+    return l10n_util::GetStringFUTF16(string_id,
+                                      base::UTF8ToUTF16(account->email));
+  }
+
+  return {};
+}
+
+std::u16string SaveUpdateAddressProfileBubbleControllerImpl::GetAddressSummary()
+    const {
+  if (!IsSaveBubble()) {
+    return {};
+  }
+  // Use a shorter version of the address summary for migration, it has
+  // a fixed set of fields and doesn't depend on libaddressinput.
+  if (is_migration_to_account_) {
+    static constexpr std::array fields = {
+        ServerFieldType::NAME_FULL_WITH_HONORIFIC_PREFIX,
+        ServerFieldType::ADDRESS_HOME_LINE1, ServerFieldType::EMAIL_ADDRESS,
+        ServerFieldType::PHONE_HOME_WHOLE_NUMBER};
+    std::vector<std::u16string> values;
+    for (ServerFieldType field : fields) {
+      std::u16string value = address_profile_.GetInfo(field, app_locale_);
+      if (!value.empty()) {
+        values.push_back(value);
+      }
+    }
+    if (values.empty()) {
+      return {};
+    }
+    return base::JoinString(values, u"\n");
+  }
+
+  return GetEnvelopeStyleAddress(address_profile_, app_locale_, true, true);
+}
+
+std::u16string SaveUpdateAddressProfileBubbleControllerImpl::GetProfileEmail()
+    const {
+  // Email is not shown as a separate field in the migration flow,
+  // it is included in the address summary, see GetAddressSummary().
+  if (is_migration_to_account_ || !IsSaveBubble()) {
+    return {};
+  }
+
+  return address_profile_.GetInfo(EMAIL_ADDRESS, app_locale_);
+}
+
+std::u16string SaveUpdateAddressProfileBubbleControllerImpl::GetProfilePhone()
+    const {
+  // Phone is not shown as a separate field in the migration flow,
+  // it is included in the address summary, see GetAddressSummary().
+  if (is_migration_to_account_ || !IsSaveBubble()) {
+    return {};
+  }
+
+  return address_profile_.GetInfo(PHONE_HOME_WHOLE_NUMBER, app_locale_);
+}
+
 std::u16string SaveUpdateAddressProfileBubbleControllerImpl::GetOkButtonLabel()
     const {
   return l10n_util::GetStringUTF16(
@@ -91,20 +283,23 @@
           : IDS_AUTOFILL_EDIT_ADDRESS_DIALOG_OK_BUTTON_LABEL_SAVE);
 }
 
-absl::optional<std::u16string>
-SaveUpdateAddressProfileBubbleControllerImpl::GetFooterMessage() const {
-  Profile* browser_profile =
-      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
+std::u16string SaveUpdateAddressProfileBubbleControllerImpl::GetFooterMessage()
+    const {
+  if (address_profile_.source() == AutofillProfile::Source::kAccount) {
+    absl::optional<AccountInfo> account =
+        GetPrimaryAccountInfoFromBrowserContext(
+            web_contents()->GetBrowserContext());
+    CHECK(account);
 
-  if (browser_profile &&
-      (address_profile_.source() == AutofillProfile::Source::kAccount ||
-       is_migration_to_account_)) {
-    return l10n_util::GetStringFUTF16(
-        IDS_AUTOFILL_EDIT_ACCOUNT_ADDRESS_SOURCE_NOTICE,
-        base::UTF8ToUTF16(browser_profile->GetProfileUserName()));
+    int string_id =
+        IsSaveBubble()
+            ? IDS_AUTOFILL_SAVE_IN_ACCOUNT_PROMPT_ADDRESS_SOURCE_NOTICE
+            : IDS_AUTOFILL_UPDATE_PROMPT_ACCOUNT_ADDRESS_SOURCE_NOTICE;
+    return l10n_util::GetStringFUTF16(string_id,
+                                      base::UTF8ToUTF16(account->email));
   }
 
-  return absl::nullopt;
+  return {};
 }
 
 const AutofillProfile&
@@ -130,6 +325,7 @@
   EditAddressProfileDialogControllerImpl* controller =
       EditAddressProfileDialogControllerImpl::FromWebContents(web_contents());
   controller->OfferEdit(address_profile_, GetOriginalProfile(),
+                        GetFooterMessage(),
                         std::move(address_profile_save_prompt_callback_),
                         is_migration_to_account_);
   HideBubble();
diff --git a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.h b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.h
index c0a0ec1..f5b33d38 100644
--- a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.h
+++ b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.h
@@ -45,8 +45,13 @@
 
   // SaveUpdateAddressProfileBubbleController:
   std::u16string GetWindowTitle() const override;
+  absl::optional<HeaderImages> GetHeaderImages() const override;
+  std::u16string GetBodyText() const override;
+  std::u16string GetAddressSummary() const override;
+  std::u16string GetProfileEmail() const override;
+  std::u16string GetProfilePhone() const override;
   std::u16string GetOkButtonLabel() const override;
-  absl::optional<std::u16string> GetFooterMessage() const override;
+  std::u16string GetFooterMessage() const override;
   const AutofillProfile& GetProfileToSave() const override;
   const AutofillProfile* GetOriginalProfile() const override;
   void OnUserDecision(
@@ -94,6 +99,8 @@
   // Whether the bubble prompts to save (migrate) the profile into account.
   bool is_migration_to_account_ = false;
 
+  std::string app_locale_;
+
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 };
 
diff --git a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl_unittest.cc
index a7bb7fd..2918557 100644
--- a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl_unittest.cc
@@ -4,15 +4,25 @@
 
 #include "chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.h"
 
+#include <string>
+
+#include "base/allocator/partition_allocator/pointers/raw_ptr.h"
 #include "base/functional/callback_helpers.h"
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/ui/autofill/ui_util.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
+#include "components/autofill/core/browser/autofill_address_util.h"
 #include "components/autofill/core/browser/autofill_client.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/common/autofill_features.h"
+#include "components/strings/grit/components_strings.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
 
 namespace autofill {
 
@@ -23,15 +33,22 @@
   void SetUp() override {
     BrowserWithTestWindowTest::SetUp();
     AddTab(browser(), GURL("about:blank"));
-    content::WebContents* web_contents =
-        browser()->tab_strip_model()->GetActiveWebContents();
     SaveUpdateAddressProfileBubbleControllerImpl::CreateForWebContents(
-        web_contents);
+        web_contents());
   }
 
   SaveUpdateAddressProfileBubbleControllerImpl* controller() {
     return SaveUpdateAddressProfileBubbleControllerImpl::FromWebContents(
-        browser()->tab_strip_model()->GetActiveWebContents());
+        web_contents());
+  }
+
+ protected:
+  base::raw_ptr<content::WebContents> web_contents() const {
+    return browser()->tab_strip_model()->GetActiveWebContents();
+  }
+
+  const std::string& app_locale() const {
+    return g_browser_process->GetApplicationLocale();
   }
 };
 
@@ -179,4 +196,131 @@
       /*address_profile_save_prompt_callback=*/base::DoNothing());
 }
 
+TEST_F(SaveUpdateAddressProfileBubbleControllerImplTest,
+       SavingNonAccountAddress) {
+  AutofillProfile profile = test::GetFullProfile();
+  AutofillProfile* original_profile = nullptr;
+  controller()->OfferSave(profile, original_profile, {}, base::DoNothing());
+
+  EXPECT_EQ(controller()->GetWindowTitle(),
+            l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_TITLE));
+  EXPECT_NE(controller()->GetHeaderImages(), absl::nullopt);
+  EXPECT_TRUE(controller()->GetBodyText().empty());
+  EXPECT_EQ(controller()->GetAddressSummary(),
+            GetEnvelopeStyleAddress(profile, app_locale(), true, true));
+  EXPECT_EQ(controller()->GetProfileEmail(),
+            profile.GetInfo(EMAIL_ADDRESS, app_locale()));
+  EXPECT_EQ(controller()->GetProfilePhone(),
+            profile.GetInfo(PHONE_HOME_WHOLE_NUMBER, app_locale()));
+  EXPECT_EQ(controller()->GetOkButtonLabel(),
+            l10n_util::GetStringUTF16(
+                IDS_AUTOFILL_EDIT_ADDRESS_DIALOG_OK_BUTTON_LABEL_SAVE));
+  EXPECT_TRUE(controller()->GetFooterMessage().empty());
+}
+
+TEST_F(SaveUpdateAddressProfileBubbleControllerImplTest,
+       UpdatingNonAccountAddress) {
+  AutofillProfile profile = test::GetFullProfile();
+  AutofillProfile original_profile = test::GetFullProfile();
+  controller()->OfferSave(profile, &original_profile, {}, base::DoNothing());
+
+  EXPECT_EQ(
+      controller()->GetWindowTitle(),
+      l10n_util::GetStringUTF16(IDS_AUTOFILL_UPDATE_ADDRESS_PROMPT_TITLE));
+  EXPECT_EQ(controller()->GetHeaderImages(), absl::nullopt);
+  EXPECT_TRUE(controller()->GetBodyText().empty());
+  EXPECT_TRUE(controller()->GetAddressSummary().empty());
+  EXPECT_TRUE(controller()->GetProfileEmail().empty());
+  EXPECT_TRUE(controller()->GetProfilePhone().empty());
+  EXPECT_EQ(controller()->GetOkButtonLabel(),
+            l10n_util::GetStringUTF16(
+                IDS_AUTOFILL_EDIT_ADDRESS_DIALOG_OK_BUTTON_LABEL_SAVE));
+  EXPECT_TRUE(controller()->GetFooterMessage().empty());
+}
+
+TEST_F(SaveUpdateAddressProfileBubbleControllerImplTest, SavingAccountAddress) {
+  AutofillProfile profile = test::GetFullProfile();
+  profile.set_source_for_testing(AutofillProfile::Source::kAccount);
+  AutofillProfile* original_profile = nullptr;
+  controller()->OfferSave(profile, original_profile, {}, base::DoNothing());
+  std::u16string email =
+      base::UTF8ToUTF16(GetPrimaryAccountInfoFromBrowserContext(
+                            web_contents()->GetBrowserContext())
+                            ->email);
+
+  EXPECT_EQ(controller()->GetWindowTitle(),
+            l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_TITLE));
+  EXPECT_NE(controller()->GetHeaderImages(), absl::nullopt);
+  EXPECT_TRUE(controller()->GetBodyText().empty());
+  EXPECT_EQ(controller()->GetAddressSummary(),
+            GetEnvelopeStyleAddress(profile, app_locale(), true, true));
+  EXPECT_EQ(controller()->GetProfileEmail(),
+            profile.GetInfo(EMAIL_ADDRESS, app_locale()));
+  EXPECT_EQ(controller()->GetProfilePhone(),
+            profile.GetInfo(PHONE_HOME_WHOLE_NUMBER, app_locale()));
+  EXPECT_EQ(controller()->GetOkButtonLabel(),
+            l10n_util::GetStringUTF16(
+                IDS_AUTOFILL_EDIT_ADDRESS_DIALOG_OK_BUTTON_LABEL_SAVE));
+  EXPECT_EQ(
+      controller()->GetFooterMessage(),
+      l10n_util::GetStringFUTF16(
+          IDS_AUTOFILL_SAVE_IN_ACCOUNT_PROMPT_ADDRESS_SOURCE_NOTICE, email));
+}
+
+TEST_F(SaveUpdateAddressProfileBubbleControllerImplTest,
+       UpdatingAccountAddress) {
+  AutofillProfile profile = test::GetFullProfile();
+  profile.set_source_for_testing(AutofillProfile::Source::kAccount);
+  AutofillProfile original_profile = test::GetFullProfile();
+  original_profile.set_source_for_testing(AutofillProfile::Source::kAccount);
+  controller()->OfferSave(profile, &original_profile, {}, base::DoNothing());
+  std::u16string email =
+      base::UTF8ToUTF16(GetPrimaryAccountInfoFromBrowserContext(
+                            web_contents()->GetBrowserContext())
+                            ->email);
+
+  EXPECT_EQ(
+      controller()->GetWindowTitle(),
+      l10n_util::GetStringUTF16(IDS_AUTOFILL_UPDATE_ADDRESS_PROMPT_TITLE));
+  EXPECT_EQ(controller()->GetHeaderImages(), absl::nullopt);
+  EXPECT_TRUE(controller()->GetBodyText().empty());
+  EXPECT_TRUE(controller()->GetAddressSummary().empty());
+  EXPECT_TRUE(controller()->GetProfileEmail().empty());
+  EXPECT_TRUE(controller()->GetProfilePhone().empty());
+  EXPECT_EQ(controller()->GetOkButtonLabel(),
+            l10n_util::GetStringUTF16(
+                IDS_AUTOFILL_EDIT_ADDRESS_DIALOG_OK_BUTTON_LABEL_SAVE));
+  EXPECT_EQ(
+      controller()->GetFooterMessage(),
+      l10n_util::GetStringFUTF16(
+          IDS_AUTOFILL_UPDATE_PROMPT_ACCOUNT_ADDRESS_SOURCE_NOTICE, email));
+}
+
+TEST_F(SaveUpdateAddressProfileBubbleControllerImplTest,
+       MigrateIntoAccountAddress) {
+  AutofillProfile profile = test::GetFullProfile();
+  AutofillProfile* original_profile = nullptr;
+  controller()->OfferSave(profile, original_profile,
+                          {.is_migration_to_account = true}, base::DoNothing());
+  std::u16string email =
+      base::UTF8ToUTF16(GetPrimaryAccountInfoFromBrowserContext(
+                            web_contents()->GetBrowserContext())
+                            ->email);
+
+  EXPECT_EQ(controller()->GetWindowTitle(),
+            l10n_util::GetStringUTF16(
+                IDS_AUTOFILL_ACCOUNT_MIGRATE_ADDRESS_PROMPT_TITLE));
+  EXPECT_NE(controller()->GetHeaderImages(), absl::nullopt);
+  EXPECT_EQ(controller()->GetBodyText(),
+            l10n_util::GetStringFUTF16(
+                IDS_AUTOFILL_LOCAL_PROFILE_MIGRATION_PROMPT_NOTICE, email));
+  EXPECT_FALSE(controller()->GetAddressSummary().empty());
+  EXPECT_TRUE(controller()->GetProfileEmail().empty());
+  EXPECT_TRUE(controller()->GetProfilePhone().empty());
+  EXPECT_EQ(controller()->GetOkButtonLabel(),
+            l10n_util::GetStringUTF16(
+                IDS_AUTOFILL_MIGRATE_ADDRESS_DIALOG_OK_BUTTON_LABEL_SAVE));
+  EXPECT_TRUE(controller()->GetFooterMessage().empty());
+}
+
 }  // namespace autofill
diff --git a/chrome/browser/ui/autofill/ui_util.cc b/chrome/browser/ui/autofill/ui_util.cc
new file mode 100644
index 0000000..58e60fd
--- /dev/null
+++ b/chrome/browser/ui/autofill/ui_util.cc
@@ -0,0 +1,27 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/autofill/ui_util.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "components/signin/public/identity_manager/account_info.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+
+namespace autofill {
+
+absl::optional<AccountInfo> GetPrimaryAccountInfoFromBrowserContext(
+    content::BrowserContext* context) {
+  Profile* profile = Profile::FromBrowserContext(context);
+  signin::IdentityManager* identity_manager =
+      IdentityManagerFactory::GetForProfile(profile);
+  if (!identity_manager) {
+    return absl::nullopt;
+  }
+  CoreAccountInfo core_account =
+      identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin);
+  return identity_manager->FindExtendedAccountInfo(core_account);
+}
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/autofill/ui_util.h b/chrome/browser/ui/autofill/ui_util.h
new file mode 100644
index 0000000..d222d5e0
--- /dev/null
+++ b/chrome/browser/ui/autofill/ui_util.h
@@ -0,0 +1,24 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_AUTOFILL_UI_UTIL_H_
+#define CHROME_BROWSER_UI_AUTOFILL_UI_UTIL_H_
+
+#include "components/signin/public/identity_manager/account_info.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace autofill {
+
+// Retrieves user's primary account from BrowserContext, traversing a chain
+// of dependencies up to signin::IdentityManager.
+absl::optional<AccountInfo> GetPrimaryAccountInfoFromBrowserContext(
+    content::BrowserContext* context);
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_AUTOFILL_UI_UTIL_H_
diff --git a/chrome/browser/ui/toolbar/app_menu_icon_controller_unittest.cc b/chrome/browser/ui/toolbar/app_menu_icon_controller_unittest.cc
index 390af72..e0d3d457 100644
--- a/chrome/browser/ui/toolbar/app_menu_icon_controller_unittest.cc
+++ b/chrome/browser/ui/toolbar/app_menu_icon_controller_unittest.cc
@@ -101,7 +101,7 @@
   void SetUp() override {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
-        std::make_unique<user_manager::FakeUserManager>());
+        std::make_unique<user_manager::FakeUserManager>(&local_state_));
     auto* user_manager = static_cast<user_manager::FakeUserManager*>(
         user_manager::UserManager::Get());
     const auto account_id = AccountId::FromUserEmail("test@test");
@@ -110,7 +110,6 @@
                                /*browser_restart=*/false,
                                /*is_child=*/false);
     crosapi::browser_util::RegisterLocalStatePrefs(local_state_.registry());
-    user_manager->set_local_state(&local_state_);
 #endif
   }
 
diff --git a/chrome/browser/ui/toolbar/app_menu_model_unittest.cc b/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
index 9102b15..e6264dc 100644
--- a/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
@@ -108,7 +108,6 @@
     user_manager->UserLoggedIn(account_id, user->username_hash(),
                                /*browser_restart=*/false,
                                /*is_child=*/false);
-    user_manager->set_local_state(g_browser_process->local_state());
 #endif
   }
 
diff --git a/chrome/browser/ui/views/autofill/edit_address_profile_view.cc b/chrome/browser/ui/views/autofill/edit_address_profile_view.cc
index 1944c92..28639d8 100644
--- a/chrome/browser/ui/views/autofill/edit_address_profile_view.cc
+++ b/chrome/browser/ui/views/autofill/edit_address_profile_view.cc
@@ -14,6 +14,8 @@
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
 
 namespace autofill {
@@ -36,7 +38,10 @@
       &EditAddressProfileView::OnUserDecision, base::Unretained(this),
       AutofillClient::SaveAddressProfileOfferUserDecision::kEditDeclined));
 
-  SetLayoutManager(std::make_unique<views::FillLayout>());
+  SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kVertical, gfx::Insets(),
+      views::LayoutProvider::Get()->GetDistanceMetric(
+          views::DISTANCE_UNRELATED_CONTROL_VERTICAL)));
   set_margins(ChromeLayoutProvider::Get()->GetInsetsMetric(
       views::InsetsMetric::INSETS_DIALOG));
 
@@ -66,6 +71,17 @@
 
   address_editor_view_ = AddChildView(std::make_unique<AddressEditorView>(
       std::move(address_editor_controller)));
+
+  const std::u16string& footer_message = controller_->GetFooterMessage();
+  if (!footer_message.empty()) {
+    AddChildView(
+        views::Builder<views::Label>()
+            .SetText(footer_message)
+            .SetTextStyle(views::style::STYLE_SECONDARY)
+            .SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT)
+            .SetMultiLine(true)
+            .Build());
+  }
 }
 
 void EditAddressProfileView::Hide() {
diff --git a/chrome/browser/ui/views/autofill/edit_address_profile_view_unittest.cc b/chrome/browser/ui/views/autofill/edit_address_profile_view_unittest.cc
index 2f6a0178..6e81da1 100644
--- a/chrome/browser/ui/views/autofill/edit_address_profile_view_unittest.cc
+++ b/chrome/browser/ui/views/autofill/edit_address_profile_view_unittest.cc
@@ -31,6 +31,7 @@
     : public EditAddressProfileDialogController {
  public:
   MOCK_METHOD(std::u16string, GetWindowTitle, (), (const, override));
+  MOCK_METHOD(const std::u16string&, GetFooterMessage, (), (const, override));
   MOCK_METHOD(std::u16string, GetOkButtonLabel, (), (const, override));
   MOCK_METHOD(const AutofillProfile&, GetProfileToEdit, (), (const, override));
   MOCK_METHOD(bool, GetIsValidatable, (), (const, override));
@@ -55,6 +56,9 @@
     address_profile_to_edit_ = test::GetFullProfile();
     test_web_contents_ =
         content::WebContentsTester::CreateTestWebContents(&profile_, nullptr);
+
+    ON_CALL(mock_controller_, GetFooterMessage)
+        .WillByDefault(::testing::ReturnRefOfCopy(std::u16string()));
   }
 
   void TearDown() override {
diff --git a/chrome/browser/ui/views/autofill/save_address_profile_view.cc b/chrome/browser/ui/views/autofill/save_address_profile_view.cc
index 923e560..9e07d8c 100644
--- a/chrome/browser/ui/views/autofill/save_address_profile_view.cc
+++ b/chrome/browser/ui/views/autofill/save_address_profile_view.cc
@@ -5,7 +5,9 @@
 #include "chrome/browser/ui/views/autofill/save_address_profile_view.h"
 
 #include <memory>
+#include <string>
 
+#include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/browser_process.h"
@@ -25,16 +27,27 @@
 #include "components/strings/grit/components_strings.h"
 #include "components/vector_icons/vector_icons.h"
 #include "content/public/browser/web_contents.h"
+#include "skia/ext/image_operations.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/image_model.h"
 #include "ui/base/models/simple_combobox_model.h"
 #include "ui/color/color_id.h"
+#include "ui/gfx/canvas.h"
 #include "ui/gfx/color_utils.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/image/canvas_image_source.h"
+#include "ui/gfx/image/image_skia.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/button/image_button_factory.h"
 #include "ui/views/controls/editable_combobox/editable_combobox.h"
 #include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/flex_layout.h"
+#include "ui/views/layout/flex_layout_view.h"
 #include "ui/views/layout/layout_provider.h"
+#include "ui/views/metadata/view_factory_internal.h"
+#include "ui/views/style/typography.h"
 #include "ui/views/view_class_properties.h"
 
 namespace autofill {
@@ -43,15 +56,6 @@
 
 constexpr int kIconSize = 16;
 
-// Maps an AddressField to a ServerFieldType making sure
-// NAME_FULL_WITH_HONORIFIC_PREFIX is returned instead of NAME_FULL for
-// RECIPIENT type.
-ServerFieldType AddressFieldToServerFieldTypeWithHonorificPrefix(
-    ::i18n::addressinput::AddressField address_field) {
-  ServerFieldType type = autofill::i18n::TypeForField(address_field);
-  return type == NAME_FULL ? NAME_FULL_WITH_HONORIFIC_PREFIX : type;
-}
-
 int ComboboxIconSize() {
   // Use the line height of the body small text. This allows the icons to adapt
   // if the user changes the font size.
@@ -96,78 +100,15 @@
                            std::move(text_label));
 }
 
-std::unique_ptr<views::View> CreateAddressLineView() {
-  auto line = std::make_unique<views::View>();
-  views::FlexLayout* line_layout =
-      line->SetLayoutManager(std::make_unique<views::FlexLayout>());
-  line_layout->SetOrientation(views::LayoutOrientation::kHorizontal)
-      .SetIgnoreDefaultMainAxisMargins(true)
-      .SetCollapseMargins(true);
-  return line;
-}
-
-std::unique_ptr<views::Label> CreateAddressComponentLabel(
-    const std::u16string& text) {
-  auto text_label =
-      std::make_unique<views::Label>(text, views::style::CONTEXT_LABEL);
-  text_label->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
-  text_label->SetMultiLine(true);
-  return text_label;
-}
-
-// Create a view that contains the address in an envelope style format. Returns
-// nullptr if the address is empty.
+// Create a view that contains the address in an envelope style format.
 std::unique_ptr<views::View> CreateStreetAddressView(
-    const AutofillProfile& profile,
-    const std::string& locale) {
-  auto address_view = std::make_unique<views::View>();
-  views::FlexLayout* flex_layout =
-      address_view->SetLayoutManager(std::make_unique<views::FlexLayout>());
-  flex_layout->SetOrientation(views::LayoutOrientation::kVertical)
-      .SetCrossAxisAlignment(views::LayoutAlignment::kStart)
-      .SetCollapseMargins(true)
-      .SetDefault(views::kMarginsKey, gfx::Insets());
-
-  const AutofillType kCountryCode(HtmlFieldType::kCountryCode,
-                                  HtmlFieldMode::kNone);
-  const std::u16string& country_code = profile.GetInfo(kCountryCode, locale);
-
-  std::vector<std::vector<autofill::ExtendedAddressUiComponent>> components;
-  autofill::GetAddressComponents(base::UTF16ToUTF8(country_code), locale,
-                                 /*include_literals=*/true, &components,
-                                 nullptr);
-
-  for (const std::vector<autofill::ExtendedAddressUiComponent>& line :
-       components) {
-    std::unique_ptr<views::View> line_view = CreateAddressLineView();
-    std::vector<std::u16string> components_str;
-    for (const autofill::ExtendedAddressUiComponent& component : line) {
-      // AddressUiComponent can represent an address field such as City, or a
-      // formatting literal such as "," or "-". If the literal field is empty,
-      // then it represents a field, otherwise, it is a literal.
-      std::u16string field_value =
-          component.literal.empty()
-              ? profile.GetInfo(
-                    AddressFieldToServerFieldTypeWithHonorificPrefix(
-                        component.field),
-                    locale)
-              : base::UTF8ToUTF16(component.literal);
-      if (!field_value.empty())
-        line_view->AddChildView(CreateAddressComponentLabel(field_value));
-    }
-    if (!line_view->children().empty())
-      address_view->AddChildView(std::move(line_view));
-  }
-  // Append the country to the end.
-  std::u16string country = profile.GetInfo(ADDRESS_HOME_COUNTRY, locale);
-  if (!country.empty()) {
-    std::unique_ptr<views::View> line_view = CreateAddressLineView();
-    line_view->AddChildView(CreateAddressComponentLabel(country));
-    address_view->AddChildView(std::move(line_view));
-  }
-  if (!address_view->children().empty())
-    return address_view;
-  return nullptr;
+    const std::u16string& summary) {
+  return views::Builder<views::Label>()
+      .SetText(summary)
+      .SetTextContext(views::style::CONTEXT_LABEL)
+      .SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT)
+      .SetMultiLine(true)
+      .Build();
 }
 
 std::unique_ptr<views::EditableCombobox> CreateNicknameEditableCombobox() {
@@ -232,50 +173,67 @@
                  l10n_util::GetStringUTF16(
                      IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_CANCEL_BUTTON_LABEL));
 
-  SetLayoutManager(std::make_unique<views::FlexLayout>())
-      ->SetOrientation(views::LayoutOrientation::kHorizontal)
-      .SetCrossAxisAlignment(views::LayoutAlignment::kStart)
-      .SetIgnoreDefaultMainAxisMargins(true)
-      .SetCollapseMargins(true);
+  SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kVertical, gfx::Insets(),
+      views::LayoutProvider::Get()->GetDistanceMetric(
+          views::DISTANCE_UNRELATED_CONTROL_VERTICAL)));
 
-  address_components_view_ = AddChildView(std::make_unique<views::View>());
-  address_components_view_->SetProperty(
-      views::kFlexBehaviorKey,
-      views::FlexSpecification(
-          views::MinimumFlexSizeRule::kPreferredSnapToMinimum,
-          views::MaximumFlexSizeRule::kUnbounded));
+  std::u16string description = controller->GetBodyText();
+  if (!description.empty()) {
+    AddChildView(
+        views::Builder<views::Label>()
+            .SetText(description)
+            .SetTextStyle(views::style::STYLE_SECONDARY)
+            .SetPreferredSize(
+                gfx::Size(views::LayoutProvider::Get()->GetDistanceMetric(
+                              views::DISTANCE_BUBBLE_PREFERRED_WIDTH) -
+                              margins().width(),
+                          0))
+            .SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT)
+            .SetMultiLine(true)
+            .Build());
+  }
 
-  edit_button_ = AddChildView(CreateEditButton(base::BindRepeating(
-      &SaveUpdateAddressProfileBubbleController::OnEditButtonClicked,
-      base::Unretained(controller_))));
+  views::FlexLayoutView* details_section =
+      AddChildView(views::Builder<views::FlexLayoutView>()
+                       .SetOrientation(views::LayoutOrientation::kHorizontal)
+                       .SetCrossAxisAlignment(views::LayoutAlignment::kStart)
+                       .SetIgnoreDefaultMainAxisMargins(true)
+                       .SetCollapseMargins(true)
+                       .SetInteriorMargin(gfx::Insets::TLBR(
+                           0, 0,
+                           ChromeLayoutProvider::Get()->GetDistanceMetric(
+                               views::DISTANCE_CONTROL_VERTICAL_TEXT_PADDING),
+                           0))
+                       .Build());
 
-  address_components_view_
-      ->SetLayoutManager(std::make_unique<views::FlexLayout>())
-      ->SetOrientation(views::LayoutOrientation::kVertical)
-      .SetCrossAxisAlignment(views::LayoutAlignment::kStretch)
-      .SetIgnoreDefaultMainAxisMargins(true)
-      .SetCollapseMargins(true)
-      .SetDefault(
-          views::kMarginsKey,
-          gfx::Insets::VH(ChromeLayoutProvider::Get()->GetDistanceMetric(
-                              DISTANCE_CONTROL_LIST_VERTICAL),
-                          0));
+  address_components_view_ = details_section->AddChildView(
+      views::Builder<views::BoxLayoutView>()
+          .SetProperty(views::kFlexBehaviorKey,
+                       views::FlexSpecification(
+                           views::MinimumFlexSizeRule::kPreferredSnapToMinimum,
+                           views::MaximumFlexSizeRule::kUnbounded))
+          .SetOrientation(views::BoxLayout::Orientation::kVertical)
+          .SetBetweenChildSpacing(
+              ChromeLayoutProvider::Get()->GetDistanceMetric(
+                  DISTANCE_CONTROL_LIST_VERTICAL))
+          .Build());
 
-  const std::string locale = g_browser_process->GetApplicationLocale();
-  const AutofillProfile& profile = controller_->GetProfileToSave();
+  edit_button_ =
+      details_section->AddChildView(CreateEditButton(base::BindRepeating(
+          &SaveUpdateAddressProfileBubbleController::OnEditButtonClicked,
+          base::Unretained(controller_))));
 
-  std::unique_ptr<views::View> street_address_view =
-      CreateStreetAddressView(profile, locale);
-  if (street_address_view) {
+  std::u16string address = controller_->GetAddressSummary();
+  if (!address.empty()) {
     std::unique_ptr<views::ImageView> icon =
         CreateAddressSectionIcon(vector_icons::kLocationOnIcon);
     address_section_icons_.push_back(icon.get());
-    AddAddressSection(
-        /*parent_view=*/address_components_view_, std::move(icon),
-        std::move(street_address_view));
+    AddAddressSection(/*parent_view=*/address_components_view_, std::move(icon),
+                      CreateStreetAddressView(address));
   }
 
-  std::u16string phone = profile.GetInfo(PHONE_HOME_WHOLE_NUMBER, locale);
+  std::u16string phone = controller_->GetProfilePhone();
   if (!phone.empty()) {
     std::unique_ptr<views::ImageView> icon =
         CreateAddressSectionIcon(vector_icons::kCallIcon);
@@ -284,7 +242,7 @@
                       phone);
   }
 
-  std::u16string email = profile.GetInfo(EMAIL_ADDRESS, locale);
+  std::u16string email = controller_->GetProfileEmail();
   if (!email.empty()) {
     std::unique_ptr<views::ImageView> icon =
         CreateAddressSectionIcon(vector_icons::kEmailIcon);
@@ -302,12 +260,11 @@
                       CreateNicknameEditableCombobox());
   }
 
-  absl::optional<std::u16string> footer_message =
-      controller_->GetFooterMessage();
-  if (footer_message) {
+  std::u16string footer_message = controller_->GetFooterMessage();
+  if (!footer_message.empty()) {
     SetFootnoteView(
         views::Builder<views::Label>()
-            .SetText(footer_message.value())
+            .SetText(footer_message)
             .SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT)
             .SetMultiLine(true)
             .Build());
@@ -353,14 +310,16 @@
 }
 
 void SaveAddressProfileView::AddedToWidget() {
-  // Set the header image.
-  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
-  auto image_view = std::make_unique<ThemeTrackingNonAccessibleImageView>(
-      *bundle.GetImageSkiaNamed(IDR_SAVE_ADDRESS),
-      *bundle.GetImageSkiaNamed(IDR_SAVE_ADDRESS_DARK),
-      base::BindRepeating(&views::BubbleDialogDelegate::GetBackgroundColor,
-                          base::Unretained(this)));
-  GetBubbleFrameView()->SetHeaderView(std::move(image_view));
+  absl::optional<SaveUpdateAddressProfileBubbleController::HeaderImages>
+      images = controller_->GetHeaderImages();
+  if (images) {
+    GetBubbleFrameView()->SetHeaderView(
+        std::make_unique<ThemeTrackingNonAccessibleImageView>(
+            images->light, images->dark,
+            base::BindRepeating(
+                &views::BubbleDialogDelegate::GetBackgroundColor,
+                base::Unretained(this))));
+  }
 }
 
 void SaveAddressProfileView::OnThemeChanged() {
diff --git a/chrome/browser/ui/views/autofill/save_address_profile_view_unittest.cc b/chrome/browser/ui/views/autofill/save_address_profile_view_unittest.cc
index 9f8eb634..68649fcb 100644
--- a/chrome/browser/ui/views/autofill/save_address_profile_view_unittest.cc
+++ b/chrome/browser/ui/views/autofill/save_address_profile_view_unittest.cc
@@ -23,11 +23,16 @@
     : public SaveUpdateAddressProfileBubbleController {
  public:
   MOCK_METHOD(std::u16string, GetWindowTitle, (), (const, override));
-  MOCK_METHOD(std::u16string, GetOkButtonLabel, (), (const, override));
-  MOCK_METHOD(absl::optional<std::u16string>,
-              GetFooterMessage,
+  MOCK_METHOD(absl::optional<HeaderImages>,
+              GetHeaderImages,
               (),
               (const, override));
+  MOCK_METHOD(std::u16string, GetBodyText, (), (const, override));
+  MOCK_METHOD(std::u16string, GetAddressSummary, (), (const, override));
+  MOCK_METHOD(std::u16string, GetProfileEmail, (), (const, override));
+  MOCK_METHOD(std::u16string, GetProfilePhone, (), (const, override));
+  MOCK_METHOD(std::u16string, GetOkButtonLabel, (), (const, override));
+  MOCK_METHOD(std::u16string, GetFooterMessage, (), (const, override));
   MOCK_METHOD(const AutofillProfile&, GetProfileToSave, (), (const, override));
   MOCK_METHOD(const AutofillProfile*,
               GetOriginalProfile,
diff --git a/chrome/browser/ui/views/autofill/update_address_profile_view.cc b/chrome/browser/ui/views/autofill/update_address_profile_view.cc
index f6937dd..6d3663d 100644
--- a/chrome/browser/ui/views/autofill/update_address_profile_view.cc
+++ b/chrome/browser/ui/views/autofill/update_address_profile_view.cc
@@ -251,12 +251,11 @@
                  /*edit_button_callback=*/{});
   }
 
-  absl::optional<std::u16string> footer_message =
-      controller_->GetFooterMessage();
-  if (footer_message) {
+  std::u16string footer_message = controller_->GetFooterMessage();
+  if (!footer_message.empty()) {
     SetFootnoteView(
         views::Builder<views::Label>()
-            .SetText(footer_message.value())
+            .SetText(footer_message)
             .SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT)
             .SetMultiLine(true)
             .Build());
diff --git a/chrome/browser/ui/views/autofill/update_address_profile_view_unittest.cc b/chrome/browser/ui/views/autofill/update_address_profile_view_unittest.cc
index 71fd53f..532bf38 100644
--- a/chrome/browser/ui/views/autofill/update_address_profile_view_unittest.cc
+++ b/chrome/browser/ui/views/autofill/update_address_profile_view_unittest.cc
@@ -23,11 +23,16 @@
     : public SaveUpdateAddressProfileBubbleController {
  public:
   MOCK_METHOD(std::u16string, GetWindowTitle, (), (const, override));
-  MOCK_METHOD(std::u16string, GetOkButtonLabel, (), (const, override));
-  MOCK_METHOD(absl::optional<std::u16string>,
-              GetFooterMessage,
+  MOCK_METHOD(absl::optional<HeaderImages>,
+              GetHeaderImages,
               (),
               (const, override));
+  MOCK_METHOD(std::u16string, GetBodyText, (), (const, override));
+  MOCK_METHOD(std::u16string, GetAddressSummary, (), (const, override));
+  MOCK_METHOD(std::u16string, GetProfileEmail, (), (const, override));
+  MOCK_METHOD(std::u16string, GetProfilePhone, (), (const, override));
+  MOCK_METHOD(std::u16string, GetOkButtonLabel, (), (const, override));
+  MOCK_METHOD(std::u16string, GetFooterMessage, (), (const, override));
   MOCK_METHOD(const AutofillProfile&, GetProfileToSave, (), (const, override));
   MOCK_METHOD(const AutofillProfile*,
               GetOriginalProfile,
diff --git a/chrome/browser/ui/views/bruschetta/bruschetta_installer_view.cc b/chrome/browser/ui/views/bruschetta/bruschetta_installer_view.cc
index b27ecf6..e6d0226 100644
--- a/chrome/browser/ui/views/bruschetta/bruschetta_installer_view.cc
+++ b/chrome/browser/ui/views/bruschetta/bruschetta_installer_view.cc
@@ -291,11 +291,11 @@
         case InstallerState::kInstallStarted:
           // We don't really spend any time in the InstallStarted state, the
           // real first step is installing DLC so fall through to that.
-        case InstallerState::kDlcInstall:
+        case InstallerState::kToolsDlcInstall:
+        case InstallerState::kFirmwareDlcInstall:
           return l10n_util::GetStringUTF16(
               IDS_BRUSCHETTA_INSTALLER_INSTALLING_DLC_MESSAGE);
         case InstallerState::kBootDiskDownload:
-        case InstallerState::kFirmwareDownload:
         case InstallerState::kPflashDownload:
         case InstallerState::kOpenFiles:
           return l10n_util::GetStringUTF16(
diff --git a/chrome/browser/ui/views/media_router/cast_toolbar_button.cc b/chrome/browser/ui/views/media_router/cast_toolbar_button.cc
index 7788c59..e0447650 100644
--- a/chrome/browser/ui/views/media_router/cast_toolbar_button.cc
+++ b/chrome/browser/ui/views/media_router/cast_toolbar_button.cc
@@ -83,6 +83,7 @@
 }
 
 CastToolbarButton::~CastToolbarButton() {
+  StopObservingMirroringMediaControllerHosts();
   if (GetActionController())
     GetActionController()->RemoveObserver(this);
 }
@@ -122,6 +123,21 @@
     const std::vector<media_router::MediaRoute>& routes) {
   has_local_route_ =
       base::Contains(routes, true, &media_router::MediaRoute::is_local);
+  StopObservingMirroringMediaControllerHosts();
+  for (const auto& route : routes) {
+    const auto& route_id = route.media_route_id();
+    MirroringMediaControllerHost* mirroring_controller_host =
+        MediaRouterFactory::GetApiForBrowserContext(profile_)
+            ->GetMirroringMediaControllerHost(route_id);
+    if (mirroring_controller_host) {
+      mirroring_controller_host->AddObserver(this);
+      tracked_mirroring_routes_.emplace_back(route_id);
+    }
+  }
+  UpdateIcon();
+}
+
+void CastToolbarButton::OnFreezeInfoChanged() {
   UpdateIcon();
 }
 
@@ -163,6 +179,15 @@
   using Severity = media_router::IssueInfo::Severity;
   const auto severity =
       current_issue_ ? current_issue_->severity : Severity::NOTIFICATION;
+  bool is_frozen = false;
+  for (const auto& route_id : tracked_mirroring_routes_) {
+    MirroringMediaControllerHost* mirroring_controller_host =
+        MediaRouterFactory::GetApiForBrowserContext(profile_)
+            ->GetMirroringMediaControllerHost(route_id);
+    if (mirroring_controller_host) {
+      is_frozen = is_frozen || mirroring_controller_host->is_frozen();
+    }
+  }
   const gfx::VectorIcon* new_icon = nullptr;
   SkColor icon_color;
 
@@ -175,6 +200,9 @@
   } else if (severity == Severity::WARNING) {
     new_icon = &vector_icons::kMediaRouterWarningIcon;
     icon_color = color_provider->GetColor(kColorMediaRouterIconWarning);
+  } else if (is_frozen) {
+    new_icon = &vector_icons::kMediaRouterPausedIcon;
+    icon_color = gfx::kPlaceholderColor;
   } else {
     new_icon = features::IsChromeRefresh2023()
                    ? &vector_icons::kMediaRouterActiveChromeRefreshIcon
@@ -236,6 +264,11 @@
   } else if (icon_ == &vector_icons::kMediaRouterWarningIcon) {
     logger_->LogInfo(mojom::LogCategory::kUi, kLoggerComponent,
                      "Cast toolbar icon shows a warning issue.", "", "", "");
+  } else if (icon_ == &vector_icons::kMediaRouterPausedIcon) {
+    logger_->LogInfo(
+        mojom::LogCategory::kUi, kLoggerComponent,
+        "Cast toolbar icon indicated there is a paused mirroring session.", "",
+        "", "");
   } else {
     CHECK_EQ(icon_, features::IsChromeRefresh2023()
                         ? &vector_icons::kMediaRouterActiveChromeRefreshIcon
@@ -246,6 +279,18 @@
   }
 }
 
+void CastToolbarButton::StopObservingMirroringMediaControllerHosts() {
+  for (const auto& route_id : tracked_mirroring_routes_) {
+    media_router::MirroringMediaControllerHost* mirroring_controller_host =
+        MediaRouterFactory::GetApiForBrowserContext(profile_)
+            ->GetMirroringMediaControllerHost(route_id);
+    if (mirroring_controller_host) {
+      mirroring_controller_host->RemoveObserver(this);
+    }
+  }
+  tracked_mirroring_routes_.clear();
+}
+
 BEGIN_METADATA(CastToolbarButton, ToolbarButton)
 END_METADATA
 
diff --git a/chrome/browser/ui/views/media_router/cast_toolbar_button.h b/chrome/browser/ui/views/media_router/cast_toolbar_button.h
index 1feb877..7815562 100644
--- a/chrome/browser/ui/views/media_router/cast_toolbar_button.h
+++ b/chrome/browser/ui/views/media_router/cast_toolbar_button.h
@@ -10,6 +10,7 @@
 #include "chrome/browser/ui/toolbar/media_router_contextual_menu.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
 #include "components/media_router/browser/issues_observer.h"
+#include "components/media_router/browser/mirroring_media_controller_host.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/events/event.h"
 
@@ -29,7 +30,8 @@
 class CastToolbarButton : public ToolbarButton,
                           public MediaRouterActionController::Observer,
                           public IssuesObserver,
-                          public MediaRoutesObserver {
+                          public MediaRoutesObserver,
+                          public MirroringMediaControllerHost::Observer {
  public:
   METADATA_HEADER(CastToolbarButton);
 
@@ -56,6 +58,9 @@
   void OnRoutesUpdated(
       const std::vector<media_router::MediaRoute>& routes) override;
 
+  // MirroringMediaControllerHost::Observer:
+  void OnFreezeInfoChanged() override;
+
   // ToolbarButton:
   bool OnMousePressed(const ui::MouseEvent& event) override;
   void OnMouseReleased(const ui::MouseEvent& event) override;
@@ -77,6 +82,8 @@
 
   void LogIconChange(const gfx::VectorIcon* icon);
 
+  void StopObservingMirroringMediaControllerHosts();
+
   const raw_ptr<Browser> browser_;
   const raw_ptr<Profile> profile_;
 
@@ -90,6 +97,9 @@
   raw_ptr<const gfx::VectorIcon> icon_ = nullptr;
 
   const raw_ptr<LoggerImpl> logger_;
+
+  // The list of routes we are observing to see if mirroring pauses.
+  std::vector<MediaRoute::Id> tracked_mirroring_routes_;
 };
 
 }  // namespace media_router
diff --git a/chrome/browser/ui/views/media_router/cast_toolbar_button_unittest.cc b/chrome/browser/ui/views/media_router/cast_toolbar_button_unittest.cc
index 8f57160c..289ab51 100644
--- a/chrome/browser/ui/views/media_router/cast_toolbar_button_unittest.cc
+++ b/chrome/browser/ui/views/media_router/cast_toolbar_button_unittest.cc
@@ -20,8 +20,10 @@
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/views/chrome_views_test_base.h"
 #include "components/media_router/browser/media_router_factory.h"
+#include "components/media_router/browser/mirroring_media_controller_host.h"
 #include "components/media_router/browser/test/mock_media_router.h"
 #include "components/vector_icons/vector_icons.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/theme_provider.h"
@@ -88,11 +90,16 @@
     Browser::CreateParams browser_params(profile_.get(), true);
     browser_params.window = window_.get();
     browser_ = std::unique_ptr<Browser>(Browser::Create(browser_params));
-    MockMediaRouter* media_router = static_cast<MockMediaRouter*>(
+    media_router_ = static_cast<MockMediaRouter*>(
         MediaRouterFactory::GetApiForBrowserContext(profile_.get()));
     logger_ = std::make_unique<LoggerImpl>();
-    ON_CALL(*media_router, GetLogger())
+    ON_CALL(*media_router_, GetLogger())
         .WillByDefault(testing::Return(logger_.get()));
+    mojo::Remote<media_router::mojom::MediaController> controller_remote;
+    mirroring_controller_host_ = std::make_unique<MirroringMediaControllerHost>(
+        std::move(controller_remote));
+    ON_CALL(*media_router_, GetMirroringMediaControllerHost(_))
+        .WillByDefault(testing::Return(mirroring_controller_host_.get()));
 
     auto context_menu = std::make_unique<MediaRouterContextualMenu>(
         browser_.get(), false, &context_menu_observer_);
@@ -100,7 +107,7 @@
     // Button needs to be in a widget to be able to access ColorProvider.
     widget_ = CreateTestWidget();
     button_ = widget_->SetContentsView(std::make_unique<CastToolbarButton>(
-        browser_.get(), media_router, std::move(context_menu)));
+        browser_.get(), media_router_, std::move(context_menu)));
 
     const ui::ColorProvider* color_provider = button_->GetColorProvider();
     idle_icon_ = gfx::Image(gfx::CreateVectorIcon(
@@ -112,6 +119,13 @@
     active_icon_ = gfx::Image(gfx::CreateVectorIcon(
         vector_icons::kMediaRouterActiveIcon,
         color_provider->GetColor(kColorMediaRouterIconActive)));
+    // Paused icon matches the style of Chrome Refresh icons, so its default
+    // size is 20. However, CastToolbarButton icons with standard colors are
+    // always size ToolbarButton::kDefaultIconSize, so match that size here.
+    paused_icon_ = gfx::Image(gfx::CreateVectorIcon(
+        vector_icons::kMediaRouterPausedIcon,
+        /* ToolbarButton::kDefaultIconSize */ 16,
+        color_provider->GetColor(kColorToolbarButtonIcon)));
   }
 
   void TearDown() override {
@@ -134,10 +148,13 @@
   MockContextMenuObserver context_menu_observer_;
   std::unique_ptr<TestingProfile> profile_;
   std::unique_ptr<LoggerImpl> logger_;
+  raw_ptr<MockMediaRouter> media_router_ = nullptr;
+  std::unique_ptr<MirroringMediaControllerHost> mirroring_controller_host_;
 
   gfx::Image idle_icon_;
   gfx::Image warning_icon_;
   gfx::Image active_icon_;
+  gfx::Image paused_icon_;
 
   const std::vector<MediaRoute> local_display_route_list_ = {
       CreateLocalDisplayRoute()};
@@ -185,4 +202,13 @@
   EXPECT_TRUE(gfx::test::AreImagesEqual(idle_icon_, GetIcon()));
 }
 
+TEST_F(CastToolbarButtonTest, PausedIcon) {
+  button_->UpdateIcon();
+  EXPECT_TRUE(gfx::test::AreImagesEqual(idle_icon_, GetIcon()));
+
+  mirroring_controller_host_.get()->set_is_frozen_for_test(true);
+  button_->OnRoutesUpdated(local_display_route_list_);
+  EXPECT_TRUE(gfx::test::AreImagesEqual(paused_icon_, GetIcon()));
+}
+
 }  // namespace media_router
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.cc
index 85252af..68a6441 100644
--- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.cc
+++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.cc
@@ -28,6 +28,11 @@
   SetTooltipText(tooltip);
 }
 
+bool ReadAnythingButtonView::IsGroupFocusTraversable() const {
+  // Only the first item in the toolbar should be reachable with tab
+  return false;
+}
+
 void ReadAnythingButtonView::UpdateIcon(const gfx::VectorIcon& icon,
                                         int icon_size,
                                         ui::ColorId icon_color) {
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.h b/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.h
index ea60cb6..fa02f5f 100644
--- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.h
+++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.h
@@ -30,6 +30,9 @@
   ReadAnythingButtonView& operator=(const ReadAnythingButtonView&) = delete;
   ~ReadAnythingButtonView() override;
 
+  // views::ImageButton
+  bool IsGroupFocusTraversable() const override;
+
   void UpdateIcon(const gfx::VectorIcon& icon,
                   int icon_size,
                   ui::ColorId icon_color);
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.cc
index 01561fba..43ea252f4 100644
--- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.cc
+++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.cc
@@ -34,6 +34,11 @@
 
 ReadAnythingMenuButton::~ReadAnythingMenuButton() = default;
 
+bool ReadAnythingMenuButton::IsGroupFocusTraversable() const {
+  // Only the first item in the toolbar should be reachable with tab
+  return false;
+}
+
 void ReadAnythingMenuButton::ButtonPressed() {
   menu_runner_ = std::make_unique<views::MenuRunner>(
       menu_model_.get(), views::MenuRunner::HAS_MNEMONICS);
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.h b/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.h
index b889539..1336d20f 100644
--- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.h
+++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.h
@@ -26,6 +26,9 @@
   ReadAnythingMenuButton& operator=(const ReadAnythingMenuButton&) = delete;
   ~ReadAnythingMenuButton() override;
 
+  // views::MenuButton
+  bool IsGroupFocusTraversable() const override;
+
   void SetMenuModel(ReadAnythingMenuModel* menu_model);
   ReadAnythingMenuModel* GetMenuModel() const;
   absl::optional<size_t> GetSelectedIndex() const;
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.cc
index 090105ad..33dab7f 100644
--- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.cc
+++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.cc
@@ -51,6 +51,7 @@
   combobox->SetProperty(
       views::kFlexBehaviorKey,
       views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToMinimum));
+  combobox->SetGroup(kToolbarGroupId);
 
   // Create the decrease/increase text size buttons.
   auto decrease_size_button = std::make_unique<ReadAnythingButtonView>(
@@ -61,6 +62,7 @@
           IDS_READING_MODE_DECREASE_FONT_SIZE_BUTTON_LABEL));
   decrease_size_button->SetProperty(views::kCrossAxisAlignmentKey,
                                     views::LayoutAlignment::kCenter);
+  decrease_size_button->SetGroup(kToolbarGroupId);
 
   auto increase_size_button = std::make_unique<ReadAnythingButtonView>(
       base::BindRepeating(&ReadAnythingToolbarView::IncreaseFontSizeCallback,
@@ -70,6 +72,7 @@
           IDS_READING_MODE_INCREASE_FONT_SIZE_BUTTON_LABEL));
   increase_size_button->SetProperty(views::kCrossAxisAlignmentKey,
                                     views::LayoutAlignment::kCenter);
+  increase_size_button->SetGroup(kToolbarGroupId);
 
   // Create theme selection menubutton.
   auto colors_button = std::make_unique<ReadAnythingMenuButton>(
@@ -78,6 +81,7 @@
       kPaletteIcon,
       l10n_util::GetStringUTF16(IDS_READING_MODE_COLORS_COMBOBOX_LABEL),
       delegate_->GetColorsModel());
+  colors_button->SetGroup(kToolbarGroupId);
 
   // Create line spacing menubutton.
   auto line_spacing_button = std::make_unique<ReadAnythingMenuButton>(
@@ -86,6 +90,7 @@
       kReadAnythingLineSpacingIcon,
       l10n_util::GetStringUTF16(IDS_READING_MODE_LINE_SPACING_COMBOBOX_LABEL),
       delegate_->GetLineSpacingModel());
+  line_spacing_button->SetGroup(kToolbarGroupId);
 
   // Create letter spacing menubutton.
   auto letter_spacing_button = std::make_unique<ReadAnythingMenuButton>(
@@ -94,6 +99,7 @@
       kReadAnythingLetterSpacingIcon,
       l10n_util::GetStringUTF16(IDS_READING_MODE_LETTER_SPACING_COMBOBOX_LABEL),
       delegate_->GetLetterSpacingModel());
+  letter_spacing_button->SetGroup(kToolbarGroupId);
 
   // Add all views as children.
   font_combobox_ = AddChildView(std::move(combobox));
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view_browsertest.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view_browsertest.cc
index b51d4b9..cbdd11d 100644
--- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view_browsertest.cc
+++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view_browsertest.cc
@@ -113,6 +113,18 @@
     return toolbar_view_->increase_text_size_button_->GetState();
   }
 
+  std::vector<views::View*> GetChildren() {
+    std::vector<views::View*> children;
+    children.emplace_back(toolbar_view_->font_combobox_);
+    children.emplace_back(toolbar_view_->increase_text_size_button_);
+    children.emplace_back(toolbar_view_->decrease_text_size_button_);
+    children.emplace_back(toolbar_view_->colors_button_);
+    children.emplace_back(toolbar_view_->line_spacing_button_);
+    children.emplace_back(toolbar_view_->letter_spacing_button_);
+    children.shrink_to_fit();
+    return children;
+  }
+
  protected:
   MockReadAnythingToolbarViewDelegate toolbar_delegate_;
   MockReadAnythingFontComboboxDelegate font_combobox_delegate_;
@@ -203,3 +215,19 @@
   EXPECT_EQ(l10n_util::GetStringUTF8(IDS_READING_MODE_TOOLBAR_LABEL),
             node_data.GetStringAttribute(ax::mojom::StringAttribute::kName));
 }
+
+IN_PROC_BROWSER_TEST_F(ReadAnythingToolbarViewTest,
+                       AllToolbarElementsInOneGroup) {
+  for (views::View* view : GetChildren()) {
+    EXPECT_EQ(view->GetGroup(), kToolbarGroupId);
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(ReadAnythingToolbarViewTest,
+                       OnlyFirstElementIsGroupTraversable) {
+  std::vector<views::View*> children = GetChildren();
+  EXPECT_TRUE(children.front()->IsGroupFocusTraversable());
+  for (size_t i = 1; i < children.size(); i++) {
+    EXPECT_FALSE(children.at(i)->IsGroupFocusTraversable());
+  }
+}
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog_browsertest.cc b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog_browsertest.cc
index d9658b7..42dc0f7 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog_browsertest.cc
+++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog_browsertest.cc
@@ -40,6 +40,7 @@
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
 #include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -562,7 +563,7 @@
   void AddFakeODFS() {
     auto fake_provider =
         ash::file_system_provider::FakeExtensionProvider::Create(
-            file_manager::file_tasks::kODFSExtensionId);
+            extension_misc::kODFSExtensionId);
     const auto kProviderId = fake_provider->GetId();
     auto* service = file_system_provider::Service::Get(profile());
     service->RegisterProvider(std::move(fake_provider));
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/one_drive_upload_handler_browsertest.cc b/chrome/browser/ui/webui/ash/cloud_upload/one_drive_upload_handler_browsertest.cc
index 0245c61..fecc7f5 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/one_drive_upload_handler_browsertest.cc
+++ b/chrome/browser/ui/webui/ash/cloud_upload/one_drive_upload_handler_browsertest.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_util.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/test/browser_test.h"
 #include "storage/browser/file_system/external_mount_points.h"
@@ -85,10 +86,10 @@
     file_system_provider::MountOptions options("odfs", "ODFS");
     const file_system_provider::ProviderId provider_id =
         file_system_provider::ProviderId::CreateFromExtensionId(
-            file_manager::file_tasks::kODFSExtensionId);
+            extension_misc::kODFSExtensionId);
     service->RegisterProvider(
         file_system_provider::FakeExtensionProvider::Create(
-            file_manager::file_tasks::kODFSExtensionId));
+            extension_misc::kODFSExtensionId));
     EXPECT_EQ(base::File::FILE_OK,
               service->MountFileSystem(provider_id, options));
   }
diff --git a/chrome/browser/ui/webui/ash/drive_internals_ui.cc b/chrome/browser/ui/webui/ash/drive_internals_ui.cc
index d1c4d151..428d5f5 100644
--- a/chrome/browser/ui/webui/ash/drive_internals_ui.cc
+++ b/chrome/browser/ui/webui/ash/drive_internals_ui.cc
@@ -666,6 +666,10 @@
     d.Set("listed_shortcuts", ToString(progress.listed_shortcuts));
     d.Set("active_queries", ToString(progress.active_queries));
     d.Set("max_active_queries", ToString(progress.max_active_queries));
+    d.Set("time_spent_listing_items",
+          drivefs::pinning::ToString(progress.time_spent_listing_items));
+    d.Set("time_spent_pinning_files",
+          drivefs::pinning::ToString(progress.time_spent_pinning_files));
     MaybeCallJavascript("onBulkPinningProgress", base::Value(std::move(d)));
   }
 
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 87811e3..d10c26e 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -188,8 +188,6 @@
 #include "ash/webui/camera_app_ui/url_constants.h"
 #include "ash/webui/color_internals/color_internals_ui.h"
 #include "ash/webui/color_internals/url_constants.h"
-#include "ash/webui/connectivity_diagnostics/connectivity_diagnostics_ui.h"
-#include "ash/webui/connectivity_diagnostics/url_constants.h"
 #include "ash/webui/diagnostics_ui/diagnostics_ui.h"
 #include "ash/webui/diagnostics_ui/url_constants.h"
 #include "ash/webui/eche_app_ui/eche_app_manager.h"
@@ -693,33 +691,6 @@
 }
 
 template <>
-WebUIController* NewWebUI<ash::ConnectivityDiagnosticsUI>(WebUI* web_ui,
-                                                          const GURL& url) {
-  return new ash::ConnectivityDiagnosticsUI(
-      web_ui,
-      /* BindNetworkDiagnosticsServiceCallback */
-      base::BindRepeating(
-          [](mojo::PendingReceiver<
-              chromeos::network_diagnostics::mojom::NetworkDiagnosticsRoutines>
-                 receiver) {
-            ash::network_health::NetworkHealthManager::GetInstance()
-                ->BindDiagnosticsReceiver(std::move(receiver));
-          }),
-      /* BindNetworkHealthServiceCallback */
-      base::BindRepeating(
-          [](mojo::PendingReceiver<
-              chromeos::network_health::mojom::NetworkHealthService> receiver) {
-            ash::network_health::NetworkHealthManager::GetInstance()
-                ->BindHealthReceiver(std::move(receiver));
-          }),
-      /* SendFeedbackReportCallback */
-      base::BindRepeating(
-          &chrome::ShowFeedbackDialogForWebUI,
-          chrome::WebUIFeedbackSource::kConnectivityDiagnostics),
-      /*show_feedback_button=*/!chrome::IsRunningInAppMode());
-}
-
-template <>
 WebUIController* NewWebUI<ash::personalization_app::PersonalizationAppUI>(
     WebUI* web_ui,
     const GURL& url) {
@@ -994,8 +965,6 @@
     return &NewComponentUI<ash::file_manager::FileManagerUI,
                            ChromeFileManagerUIDelegate>;
   }
-  if (url.host_piece() == ash::kChromeUIConnectivityDiagnosticsHost)
-    return &NewWebUI<ash::ConnectivityDiagnosticsUI>;
   if (url.host_piece() == ash::kChromeUIGuestOSInstallerHost)
     return &NewWebUI<ash::GuestOSInstallerUI>;
   if (url.host_piece() == ash::kChromeUIHelpAppHost)
diff --git a/chrome/browser/ui/webui/chromeos/chrome_web_ui_configs_chromeos.cc b/chrome/browser/ui/webui/chromeos/chrome_web_ui_configs_chromeos.cc
index 1cf465d..e8bcb4d 100644
--- a/chrome/browser/ui/webui/chromeos/chrome_web_ui_configs_chromeos.cc
+++ b/chrome/browser/ui/webui/chromeos/chrome_web_ui_configs_chromeos.cc
@@ -8,14 +8,24 @@
 #include "content/public/browser/webui_config_map.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+// Headers that are part of the //chrome/browser target.
+//
+// Depending on //chrome/browser would cause a circular dependency because it
+// depends on //chrome/browser/ui which depends on this file's target. So we
+// suppress gn warnings.
+#include "chrome/browser/app_mode/app_mode_utils.h"         // nogncheck
+#include "chrome/browser/feedback/feedback_dialog_utils.h"  // nogncheck
+
 #include "ash/constants/ash_features.h"
 #include "ash/webui/camera_app_ui/camera_app_ui.h"
 #include "ash/webui/color_internals/color_internals_ui.h"
+#include "ash/webui/connectivity_diagnostics/connectivity_diagnostics_ui.h"
 #include "ash/webui/files_internals/files_internals_ui.h"
 #include "ash/webui/firmware_update_ui/firmware_update_app_ui.h"
 #include "ash/webui/os_feedback_ui/os_feedback_ui.h"
 #include "ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.h"
 #include "ash/webui/system_extensions_internals_ui/system_extensions_internals_ui.h"
+#include "chrome/browser/ash/net/network_health/network_health_manager.h"
 #include "chrome/browser/ash/os_feedback/chrome_os_feedback_delegate.h"
 #include "chrome/browser/ash/web_applications/camera_app/chrome_camera_app_ui_delegate.h"
 #include "chrome/browser/ash/web_applications/files_internals_ui_delegate.h"
@@ -92,6 +102,37 @@
 }
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+std::unique_ptr<content::WebUIConfig> MakeConnectivityDiagnosticsUIConfig() {
+  CreateWebUIControllerFunc create_controller_func =
+      [](content::WebUI* web_ui) -> std::unique_ptr<content::WebUIController> {
+    return std::make_unique<ash::ConnectivityDiagnosticsUI>(
+        web_ui,
+        /* BindNetworkDiagnosticsServiceCallback */
+        base::BindRepeating(
+            [](mojo::PendingReceiver<chromeos::network_diagnostics::mojom::
+                                         NetworkDiagnosticsRoutines> receiver) {
+              ash::network_health::NetworkHealthManager::GetInstance()
+                  ->BindDiagnosticsReceiver(std::move(receiver));
+            }),
+        /* BindNetworkHealthServiceCallback */
+        base::BindRepeating(
+            [](mojo::PendingReceiver<
+                chromeos::network_health::mojom::NetworkHealthService>
+                   receiver) {
+              ash::network_health::NetworkHealthManager::GetInstance()
+                  ->BindHealthReceiver(std::move(receiver));
+            }),
+        /* SendFeedbackReportCallback */
+        base::BindRepeating(
+            &chrome::ShowFeedbackDialogForWebUI,
+            chrome::WebUIFeedbackSource::kConnectivityDiagnostics),
+        /*show_feedback_button=*/!chrome::IsRunningInAppMode());
+  };
+
+  return std::make_unique<ash::ConnectivityDiagnosticsUIConfig>(
+      create_controller_func);
+}
+
 void RegisterAshChromeWebUIConfigs() {
   // Add `WebUIConfig`s for Ash ChromeOS to the list here.
   auto& map = content::WebUIConfigMap::GetInstance();
@@ -114,6 +155,7 @@
       std::make_unique<ash::cloud_upload::CloudUploadUIConfig>());
   map.AddWebUIConfig(std::make_unique<ash::ColorInternalsUIConfig>());
   map.AddWebUIConfig(std::make_unique<ash::ConfirmPasswordChangeUIConfig>());
+  map.AddWebUIConfig(MakeConnectivityDiagnosticsUIConfig());
   map.AddWebUIConfig(std::make_unique<ash::CrostiniInstallerUIConfig>());
   map.AddWebUIConfig(std::make_unique<ash::CrostiniUpgraderUIConfig>());
   map.AddWebUIConfig(std::make_unique<ash::CryptohomeUIConfig>());
diff --git a/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc b/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
index 319ca33..d25a2fd2 100644
--- a/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
+++ b/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
@@ -1166,8 +1166,8 @@
                    base::Value("www.test-dns.com"));
 
   // Owned by |scoped_user_manager|.
-  auto user_manager = std::make_unique<user_manager::FakeUserManager>();
-  user_manager->set_local_state(&local_state_);
+  auto user_manager =
+      std::make_unique<user_manager::FakeUserManager>(&local_state_);
   // The DNS templates with identifiers only work is a user is logged in.
   const AccountId account_id(AccountId::FromUserEmailGaiaId(kUser, kGaiaId));
   user_manager->AddUser(account_id);
diff --git a/chrome/browser/ui/webui/password_manager/password_manager_ui.cc b/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
index 26fc5b85..05bd4673 100644
--- a/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
+++ b/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
@@ -161,6 +161,11 @@
     {"help", IDS_PASSWORD_MANAGER_UI_HELP},
     {"hidePassword", IDS_PASSWORD_MANAGER_UI_HIDE_PASSWORD},
     {"importPasswords", IDS_PASSWORD_MANAGER_UI_IMPORT_BANNER_TITLE},
+    {"importPasswordsCompleteTitle",
+     IDS_PASSWORD_MANAGER_UI_IMPORT_COMPLETE_TITLE},
+    {"importPasswordsSuccessTitle",
+     IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_TITLE},
+    {"importPasswordsSuccessTip", IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_TIP},
     {"importPasswordsDescriptionAccount",
      IDS_PASSWORD_MANAGER_UI_IMPORT_DESCRIPTION_SYNCING_USERS},
     {"importPasswordsSelectFile",
@@ -364,6 +369,18 @@
       "compromisedPasswords",
       IDS_PASSWORD_MANAGER_UI_COMPROMISED_PASSWORDS_COUNT);
   plural_string_handler->AddLocalizedString(
+      "importPasswordsFailuresSummary",
+      IDS_PASSWORD_MANAGER_UI_IMPORT_FAILURES_SUMMARY);
+  plural_string_handler->AddLocalizedString(
+      "importPasswordsBadRowsFormat",
+      IDS_PASSWORD_MANAGER_UI_IMPORT_BAD_ROWS_FORMAT);
+  plural_string_handler->AddLocalizedString(
+      "importPasswordsSuccessSummaryAccount",
+      IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_SUMMARY_ACCOUNT);
+  plural_string_handler->AddLocalizedString(
+      "importPasswordsSuccessSummaryDevice",
+      IDS_PASSWORD_MANAGER_UI_IMPORT_SUCCESS_SUMMARY_DEVICE);
+  plural_string_handler->AddLocalizedString(
       "numberOfAccounts", IDS_PASSWORD_MANAGER_UI_NUMBER_OF_ACCOUNTS);
   plural_string_handler->AddLocalizedString(
       "numberOfPasswordReuse",
diff --git a/chrome/browser/ui/webui/settings/ash/people_section.cc b/chrome/browser/ui/webui/settings/ash/people_section.cc
index fafc2618..9a2d219 100644
--- a/chrome/browser/ui/webui/settings/ash/people_section.cc
+++ b/chrome/browser/ui/webui/settings/ash/people_section.cc
@@ -284,6 +284,8 @@
        IDS_SETTINGS_PEOPLE_RECOVERY_DISABLE_DIALOG_TITLE},
       {"recoveryDisableDialogMessage",
        IDS_SETTINGS_PEOPLE_RECOVERY_DISABLE_DIALOG_MESSAGE},
+      {"recoveryNotSupportedMessage",
+       IDS_SETTINGS_PEOPLE_RECOVERY_NOT_SUPPORTED_MESSAGE},
   };
   html_source->AddLocalizedStrings(kLocalizedStrings);
 
@@ -305,6 +307,9 @@
                              ui::GetChromeOSDeviceName()));
   html_source->AddString("fingerprintLearnMoreLink",
                          chrome::kFingerprintLearnMoreURL);
+  html_source->AddBoolean("cryptohomeRecoveryEnabled",
+                          features::IsCryptohomeRecoveryEnabled());
+  html_source->AddString("recoveryLearnMoreUrl", chrome::kRecoveryLearnMoreURL);
 }
 
 void AddFingerprintListStrings(content::WebUIDataSource* html_source) {
diff --git a/chrome/browser/ui/webui/settings/settings_secure_dns_handler.cc b/chrome/browser/ui/webui/settings/settings_secure_dns_handler.cc
index 537e7ee..d1721d5 100644
--- a/chrome/browser/ui/webui/settings/settings_secure_dns_handler.cc
+++ b/chrome/browser/ui/webui/settings/settings_secure_dns_handler.cc
@@ -249,9 +249,13 @@
 
 // static
 net::DohProviderEntry::List SecureDnsHandler::GetFilteredProviders() {
-  return secure_dns::ProvidersForCountry(
-      secure_dns::SelectEnabledProviders(net::DohProviderEntry::GetList()),
-      country_codes::GetCurrentCountryID());
+  // Note: Check whether each provider is enabled *after* filtering based on
+  // country code so that if we are doing experimentation via Finch for a
+  // regional provider, the experiment groups will be less likely to include
+  // users from other regions unnecessarily (since a client will be included in
+  // the experiment if the provider feature flag is checked).
+  return secure_dns::SelectEnabledProviders(secure_dns::ProvidersForCountry(
+      net::DohProviderEntry::GetList(), country_codes::GetCurrentCountryID()));
 }
 
 }  // namespace settings
diff --git a/chrome/browser/web_applications/commands/install_placeholder_command.cc b/chrome/browser/web_applications/commands/install_placeholder_command.cc
index efa19a4..d29e560 100644
--- a/chrome/browser/web_applications/commands/install_placeholder_command.cc
+++ b/chrome/browser/web_applications/commands/install_placeholder_command.cc
@@ -37,7 +37,8 @@
     std::unique_ptr<WebAppDataRetriever> data_retriever)
     : WebAppCommandTemplate<AppLock>("InstallPlaceholderCommand"),
       profile_(profile),
-      app_id_(GenerateAppId(/*manifest_id=*/"", install_options.install_url)),
+      app_id_(GenerateAppId(/*manifest_id=*/absl::nullopt,
+                            install_options.install_url)),
       lock_description_(std::make_unique<AppLockDescription>(app_id_)),
       install_options_(install_options),
       callback_(std::move(callback)),
@@ -189,8 +190,8 @@
       Profile::FromBrowserContext(web_contents_->GetBrowserContext())
           ->GetPrefs(),
       app_id,
-      (ConvertExternalInstallSourceToInstallSource(
-          install_options_.install_source)));
+      ConvertExternalInstallSourceToInstallSource(
+          install_options_.install_source));
 
   RecordAppBanner(web_contents_.get(), install_options_.install_url);
 
diff --git a/chrome/browser/web_applications/commands/install_placeholder_command_unittest.cc b/chrome/browser/web_applications/commands/install_placeholder_command_unittest.cc
index 85d72e7b..2f3e2518 100644
--- a/chrome/browser/web_applications/commands/install_placeholder_command_unittest.cc
+++ b/chrome/browser/web_applications/commands/install_placeholder_command_unittest.cc
@@ -64,10 +64,8 @@
   ExternalInstallOptions options(kInstallUrl, mojom::UserDisplayMode::kBrowser,
                                  ExternalInstallSource::kExternalPolicy);
   base::test::TestFuture<const AppId&, webapps::InstallResultCode, bool> future;
-  provider()->scheduler().InstallPlaceholder(
-      options, future.GetCallback(), web_contents()->GetWeakPtr()
-
-  );
+  provider()->scheduler().InstallPlaceholder(options, future.GetCallback(),
+                                             web_contents()->GetWeakPtr());
   EXPECT_EQ(future.Get<webapps::InstallResultCode>(),
             webapps::InstallResultCode::kSuccessNewInstall);
   const AppId app_id = future.Get<AppId>();
diff --git a/chrome/browser/web_applications/locks/with_app_resources.cc b/chrome/browser/web_applications/locks/with_app_resources.cc
index 8ce29b73..f6a026f 100644
--- a/chrome/browser/web_applications/locks/with_app_resources.cc
+++ b/chrome/browser/web_applications/locks/with_app_resources.cc
@@ -43,6 +43,10 @@
   CHECK(lock_manager_);
   return lock_manager_->provider().ui_manager();
 }
+WebAppOriginAssociationManager& WithAppResources::origin_association_manager() {
+  CHECK(lock_manager_);
+  return lock_manager_->provider().origin_association_manager();
+}
 WithAppResources::WithAppResources(
     base::WeakPtr<WebAppLockManager> lock_manager)
     : lock_manager_(std::move(lock_manager)) {}
diff --git a/chrome/browser/web_applications/locks/with_app_resources.h b/chrome/browser/web_applications/locks/with_app_resources.h
index 003647b9..01103fe 100644
--- a/chrome/browser/web_applications/locks/with_app_resources.h
+++ b/chrome/browser/web_applications/locks/with_app_resources.h
@@ -19,6 +19,7 @@
 class WebAppSyncBridge;
 class WebAppTranslationManager;
 class WebAppUiManager;
+class WebAppOriginAssociationManager;
 
 // This gives access to web app components that allow read/write access to web
 // apps. A lock class that needs read/read access to web apps can inherit from
@@ -43,6 +44,7 @@
   WebAppIconManager& icon_manager();
   WebAppTranslationManager& translation_manager();
   WebAppUiManager& ui_manager();
+  WebAppOriginAssociationManager& origin_association_manager();
 
  protected:
   explicit WithAppResources(base::WeakPtr<WebAppLockManager> lock_manager);
diff --git a/chrome/build/lacros-arm.pgo.txt b/chrome/build/lacros-arm.pgo.txt
index 94237abe..a3a143e3 100644
--- a/chrome/build/lacros-arm.pgo.txt
+++ b/chrome/build/lacros-arm.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-arm-generic-main-1681833573-facbb0e521b087fe29e120ff6e07d3c78bcd2a54.profdata
+chrome-chromeos-arm-generic-main-1681876473-2e7c8574ec18bf4bd376e2f0fc5e7cb4031b5dca.profdata
diff --git a/chrome/build/lacros64.pgo.txt b/chrome/build/lacros64.pgo.txt
index 89fa929..f263314 100644
--- a/chrome/build/lacros64.pgo.txt
+++ b/chrome/build/lacros64.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-amd64-generic-main-1681833573-b45faf655ae34ca08ec48ceb278433a53cb3372e.profdata
+chrome-chromeos-amd64-generic-main-1681876473-cba0ce2b44ace0b05f624f78f76d2361ea948c5f.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 13f3371..7a82050 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1681840647-3a51566332637ec1788be6b95a0900ce8faa5f6d.profdata
+chrome-linux-main-1681862179-0c38d08a3325d83eab5a1fd229876b875ad615a4.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 0564f7e..f625c679 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1681855118-05776b4e23dc63a836bf8f35c38143167a1f085f.profdata
+chrome-mac-arm-main-1681876473-e8bb3c2cf2d8e604c223929bccfe83f8f8ea9a10.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 8ba325c..ff05a6df 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1681840647-d5566fc27940004c741123a0c0db09a86d94bfdd.profdata
+chrome-mac-main-1681862179-af02b9c95b8520245033a38f255eaa25b19dee4f.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 4cb7845..b2d3aef 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1681851513-c6e6e570724c3bd82ffafb438b7e7134e2aa2ca4.profdata
+chrome-win32-main-1681862179-7827ca44a7b9a52225429c0ff08e6c434d42bbd0.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 5cce8380..824d614d 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1681851513-cb681ad4d1b64517a03aef276f1d30cdd117067e.profdata
+chrome-win64-main-1681873183-2e55fab298ef0dff390fb1224d113a2453ce8229.profdata
diff --git a/chrome/common/accessibility/read_anything_constants.h b/chrome/common/accessibility/read_anything_constants.h
index 107cb9a6..195434a 100644
--- a/chrome/common/accessibility/read_anything_constants.h
+++ b/chrome/common/accessibility/read_anything_constants.h
@@ -26,6 +26,9 @@
 const ui::AXMode kReadAnythingAXMode =
     ui::AXMode::kWebContents | ui::AXMode::kHTML | ui::AXMode::kScreenReader;
 
+// Group id for the toolbar
+const int kToolbarGroupId = 0;
+
 // Visual constants for Read Anything feature.
 const int kInternalInsets = 8;
 const int kSeparatorTopBottomPadding = 4;
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 885c982..189a1070 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -80,6 +80,7 @@
 const char kDeskApiExtensionId[] = "kflgdebkpepnpjobkdfeeipcjdahoomc";
 const char kBruSecurityKeyForwarderExtensionId[] =
     "lcooaekmckohjjnpaaokodoepajbnill";
+const char kODFSExtensionId[] = "gnnndjlaomemikopnjhhnoombakkkkdg";
 #endif
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 const char kAccessibilityCommonExtensionId[] =
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index a203eb84..e9c43b0 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -171,6 +171,8 @@
 extern const char kDeskApiExtensionId[];
 // The extension id of the Bruschetta Security Key Forwarder extension.
 extern const char kBruSecurityKeyForwarderExtensionId[];
+// The extension id of the OneDrive FS external component extension.
+extern const char kODFSExtensionId[];
 #endif
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 // The extension id of the Accessibility Common extension.
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 3cf8a4a..84ca4b70 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -488,6 +488,9 @@
 extern const char kFingerprintLearnMoreURL[] =
     "https://support.google.com/chromebook?p=chromebook_fingerprint";
 
+extern const char kRecoveryLearnMoreURL[] =
+    "https://support.google.com/chrome?p=local_data_recovery";
+
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(IS_MAC)
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index c3ab345..f4fe5f4f 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -463,6 +463,10 @@
 
 // The URL for the help center article about fingerprint on Chrome OS devices.
 extern const char kFingerprintLearnMoreURL[];
+
+// The URL for the help center article about local data recovery on Chrome OS
+// devices.
+extern const char kRecoveryLearnMoreURL[];
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(IS_MAC)
diff --git a/chrome/test/base/browser_with_test_window_test.cc b/chrome/test/base/browser_with_test_window_test.cc
index afe853a..2e6d322 100644
--- a/chrome/test/base/browser_with_test_window_test.cc
+++ b/chrome/test/base/browser_with_test_window_test.cc
@@ -64,10 +64,15 @@
 
   base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kNoFirstRun);
 
+  profile_manager_ = std::make_unique<TestingProfileManager>(
+      TestingBrowserProcess::GetGlobal());
+  ASSERT_TRUE(profile_manager_->SetUp());
+
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   if (!user_manager::UserManager::IsInitialized()) {
     scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
-        std::make_unique<user_manager::FakeUserManager>());
+        std::make_unique<user_manager::FakeUserManager>(
+            g_browser_process->local_state()));
   }
   ash_test_helper_.SetUp();
 #endif
@@ -88,10 +93,6 @@
   SetConstrainedWindowViewsClient(CreateChromeConstrainedWindowViewsClient());
 #endif
 
-  profile_manager_ = std::make_unique<TestingProfileManager>(
-      TestingBrowserProcess::GetGlobal());
-  ASSERT_TRUE(profile_manager_->SetUp());
-
   user_performance_tuning_manager_environment_.SetUp(
       profile_manager_->local_state()->Get());
 
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_offline_gif_test.ts b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_offline_gif_test.ts
index 04646b88..b33331b6 100644
--- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_offline_gif_test.ts
+++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_offline_gif_test.ts
@@ -52,7 +52,7 @@
   });
 
   test(
-      'There exists emoji-error component in the Trending category.',
+      'There exists emoji-error component in the Emoji Category.',
       async () => {
         const categoryButton =
             emojiSearch.shadowRoot!
@@ -65,8 +65,6 @@
             findInEmojiPicker('#list-container', '#groups', 'emoji-error')!;
         assert(errorElement);
 
-        assert(errorElement.shadowRoot!.querySelector(
-            '.gif-error-container > #no-internet-icon'));
         const errorText = errorElement.shadowRoot!.querySelector(
             '.gif-error-container > .error-text');
         assertEquals(
@@ -84,8 +82,6 @@
         const errorElement = results!.querySelector('.no-result > emoji-error');
         assert(errorElement);
 
-        assert(errorElement!.shadowRoot!.querySelector(
-            '.gif-error-container > #no-internet-icon'));
         const errorText = errorElement!.shadowRoot!.querySelector(
             '.gif-error-container > .error-text');
         assertEquals(
diff --git a/chrome/test/data/webui/new_tab_page/realbox/realbox_test.ts b/chrome/test/data/webui/new_tab_page/realbox/realbox_test.ts
index 57c4ed4..3f199612 100644
--- a/chrome/test/data/webui/new_tab_page/realbox/realbox_test.ts
+++ b/chrome/test/data/webui/new_tab_page/realbox/realbox_test.ts
@@ -2271,6 +2271,40 @@
     assertEquals(2, matchEls.length);
   });
 
+  test('HidesDropdownIfNoPrimaryMatches', async () => {
+    realbox.$.input.value = '';
+    realbox.$.input.dispatchEvent(new MouseEvent('mousedown', {button: 0}));
+
+    const matches = [createUrlMatch({suggestionGroupId: 100})];
+    const suggestionGroupsMap = {
+      100: {
+        header: mojoString16('People also search for'),
+        hideGroupA11yLabel: mojoString16(''),
+        showGroupA11yLabel: mojoString16(''),
+        hidden: false,
+        sideType: SideType.kSecondary,
+      },
+    };
+    testProxy.callbackRouterRemote.autocompleteResultChanged({
+      input: mojoString16(''),
+      matches,
+      suggestionGroupsMap,
+    });
+    await testProxy.callbackRouterRemote.$.flushForTesting();
+    assertFalse(areMatchesShowing());
+
+    // Verify updating the suggestion group to be a primary group makes the
+    // realbox dropdown show.
+    suggestionGroupsMap[100].sideType = SideType.kDefaultPrimary;
+    testProxy.callbackRouterRemote.autocompleteResultChanged({
+      input: mojoString16(''),
+      matches,
+      suggestionGroupsMap,
+    });
+    await testProxy.callbackRouterRemote.$.flushForTesting();
+    assertTrue(areMatchesShowing());
+  });
+
   test(
       'focusing suggestion group header resets selection and input text',
       async () => {
diff --git a/chrome/test/data/webui/password_manager/passwords_importer_test.ts b/chrome/test/data/webui/password_manager/passwords_importer_test.ts
index 9fc513d..5f71315 100644
--- a/chrome/test/data/webui/password_manager/passwords_importer_test.ts
+++ b/chrome/test/data/webui/password_manager/passwords_importer_test.ts
@@ -5,9 +5,11 @@
 import 'chrome://password-manager/password_manager.js';
 
 import {CrDialogElement, PasswordManagerImpl, PasswordsImporterElement} from 'chrome://password-manager/password_manager.js';
+import {PluralStringProxyImpl} from 'chrome://resources/js/plural_string_proxy.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
+import {TestPluralStringProxy} from 'chrome://webui-test/test_plural_string_proxy.js';
 import {isChildVisible, isVisible} from 'chrome://webui-test/test_util.js';
 
 import {TestPasswordManagerProxy} from './test_password_manager_proxy.js';
@@ -57,13 +59,26 @@
   assertEquals(expectedText, element?.textContent!.trim());
 }
 
+function assertButtonShouldCloseDialog(
+    importer: PasswordsImporterElement, dialog: HTMLElement, selector: string) {
+  const button = dialog.querySelector<HTMLElement>(selector);
+  assertTrue(!!button);
+  // Should close the dialog.
+  button.click();
+  flush();
+  assertFalse(!!importer.shadowRoot!.querySelector<CrDialogElement>('#dialog'));
+}
+
 suite('PasswordsImporterTest', function() {
   let passwordManager: TestPasswordManagerProxy;
+  let pluralString: TestPluralStringProxy;
 
   setup(function() {
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
     passwordManager = new TestPasswordManagerProxy();
     PasswordManagerImpl.setInstance(passwordManager);
+    pluralString = new TestPluralStringProxy();
+    PluralStringProxyImpl.setInstance(pluralString);
   });
 
   test('has correct non-syncing initial state', function() {
@@ -128,6 +143,8 @@
     assertVisibleTextContent(
         dialog, '#selectFileButton', importer.i18n('selectFile'));
     assertVisibleTextContent(dialog, '#cancelButton', importer.i18n('cancel'));
+
+    assertButtonShouldCloseDialog(importer, dialog, '#cancelButton');
   });
 
   test('account store user can import passwords to device', async function() {
@@ -161,4 +178,148 @@
     const expectedStore = chrome.passwordsPrivate.PasswordStoreSet.ACCOUNT;
     await triggerImportHelper(importer, passwordManager, expectedStore);
   });
+
+  test('has correct success state with no errors', async function() {
+    const importer = createPasswordsImporter();
+    passwordManager.setImportResults({
+      status: chrome.passwordsPrivate.ImportResultsStatus.SUCCESS,
+      numberImported: 42,
+      displayedEntries: [],
+      fileName: 'test.csv',
+    });
+
+    await triggerImportHelper(importer, passwordManager);
+    await pluralString.whenCalled('getPluralString');
+    await flushTasks();
+
+    const dialog =
+        importer.shadowRoot!.querySelector<CrDialogElement>('#dialog');
+    assertTrue(!!dialog);
+    assertTrue(dialog.open);
+
+    assertVisibleTextContent(
+        dialog, '#title', importer.i18n('importPasswordsSuccessTitle'));
+
+    assertTrue(isChildVisible(dialog, '#tipBox', /*checkLightDom=*/ true));
+    assertFalse(
+        isChildVisible(dialog, '#failuresSummary', /*checkLightDom=*/ true));
+
+    const successTip = dialog.querySelector('#successTip');
+    assertTrue(!!successTip);
+    assertEquals(
+        successTip.innerHTML.toString(),
+        importer
+            .i18nAdvanced(
+                'importPasswordsSuccessTip',
+                {attrs: ['class'], substitutions: ['test.csv']})
+            .toString());
+
+    assertVisibleTextContent(dialog, '#closeButton', importer.i18n('close'));
+
+    assertButtonShouldCloseDialog(importer, dialog, '#closeButton');
+  });
+
+  test('has correct success state with failures', async function() {
+    const importer = createPasswordsImporter();
+    passwordManager.setImportResults({
+      status: chrome.passwordsPrivate.ImportResultsStatus.SUCCESS,
+      numberImported: 42,
+      displayedEntries: [
+        {
+          status: chrome.passwordsPrivate.ImportEntryStatus.MISSING_PASSWORD,
+          username: 'username',
+          url: 'https://google.com',
+          password: '',
+          id: 0,
+        },
+        {
+          status: chrome.passwordsPrivate.ImportEntryStatus.MISSING_URL,
+          username: 'username',
+          url: '',
+          password: '',
+          id: 0,
+        },
+        {
+          status: chrome.passwordsPrivate.ImportEntryStatus.INVALID_URL,
+          username: 'username',
+          url: 'http/google.com',
+          password: '',
+          id: 0,
+        },
+        {
+          status: chrome.passwordsPrivate.ImportEntryStatus.LONG_URL,
+          username: 'username',
+          url: 'https://morethan2048chars.com',
+          password: '',
+          id: 0,
+        },
+        {
+          status: chrome.passwordsPrivate.ImportEntryStatus.NON_ASCII_URL,
+          username: 'username',
+          url: 'https://أهلا.com',
+          password: '',
+          id: 0,
+        },
+        {
+          status: chrome.passwordsPrivate.ImportEntryStatus.LONG_PASSWORD,
+          username: 'username',
+          url: 'https://google.com',
+          password: '',
+          id: 0,
+        },
+        {
+          status: chrome.passwordsPrivate.ImportEntryStatus.LONG_USERNAME,
+          username: 'morethan1000chars',
+          url: 'https://google.com',
+          password: '',
+          id: 0,
+        },
+        {
+          status: chrome.passwordsPrivate.ImportEntryStatus.CONFLICT_PROFILE,
+          username: 'username',
+          url: 'https://google.com',
+          password: '',
+          id: 0,
+        },
+        {
+          status: chrome.passwordsPrivate.ImportEntryStatus.CONFLICT_ACCOUNT,
+          username: 'username',
+          url: 'https://google.com',
+          password: '',
+          id: 0,
+        },
+        {
+          status: chrome.passwordsPrivate.ImportEntryStatus.UNKNOWN_ERROR,
+          username: '',
+          url: '',
+          password: '',
+          id: 0,
+        },
+      ],
+      fileName: 'test.csv',
+    });
+
+    await triggerImportHelper(importer, passwordManager);
+    await pluralString.whenCalled('getPluralString');
+    await flushTasks();
+
+    const dialog =
+        importer.shadowRoot!.querySelector<CrDialogElement>('#dialog');
+    assertTrue(!!dialog);
+    assertTrue(dialog.open);
+
+    assertVisibleTextContent(
+        dialog, '#title', importer.i18n('importPasswordsCompleteTitle'));
+
+    // Success tip should not be visible.
+    assertFalse(isChildVisible(dialog, '#tipBox', /*checkLightDom=*/ true));
+
+    assertTrue(
+        isChildVisible(dialog, '#failuresSummary', /*checkLightDom=*/ true));
+
+    assertVisibleTextContent(dialog, '#closeButton', importer.i18n('close'));
+
+    assertButtonShouldCloseDialog(importer, dialog, '#closeButton');
+  });
+
 });
diff --git a/chrome/test/data/webui/password_manager/test_password_manager_proxy.ts b/chrome/test/data/webui/password_manager/test_password_manager_proxy.ts
index 7d60a52..4a6ce8dc 100644
--- a/chrome/test/data/webui/password_manager/test_password_manager_proxy.ts
+++ b/chrome/test/data/webui/password_manager/test_password_manager_proxy.ts
@@ -311,6 +311,13 @@
     this.listeners.accountStorageOptInStateListener = null;
   }
 
+  /**
+   * Sets the value to be returned by importPasswords.
+   */
+  setImportResults(results: chrome.passwordsPrivate.ImportResults) {
+    this.importResults_ = results;
+  }
+
   importPasswords(toStore: chrome.passwordsPrivate.PasswordStoreSet) {
     this.methodCalled('importPasswords', toStore);
     return Promise.resolve(this.importResults_);
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager.cc b/chromeos/ash/components/drivefs/drivefs_pin_manager.cc
index 845f2eb7..3d309c920 100644
--- a/chromeos/ash/components/drivefs/drivefs_pin_manager.cc
+++ b/chromeos/ash/components/drivefs/drivefs_pin_manager.cc
@@ -16,6 +16,7 @@
 #include "base/no_destructor.h"
 #include "base/notreached.h"
 #include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
 #include "base/task/sequenced_task_runner.h"
 #include "chromeos/ash/components/dbus/spaced/spaced_client.h"
 #include "chromeos/ash/components/drivefs/mojom/drivefs.mojom.h"
@@ -102,16 +103,16 @@
 
   const double seconds = ms / 1000.0;
   if (seconds < 60) {
-    return out << std::setprecision(2) << seconds << " seconds";
+    return out << base::StringPrintf("%.1f seconds", seconds);
   }
 
   const double minutes = seconds / 60.0;
   if (minutes < 60) {
-    return out << std::setprecision(2) << minutes << " minutes";
+    return out << base::StringPrintf("%.1f minutes", minutes);
   }
 
   const double hours = minutes / 60.0;
-  return out << std::setprecision(2) << hours << " hours";
+  return out << base::StringPrintf("%.1f hours", hours);
 }
 
 ostream& operator<<(ostream& out, Quoter<Path> q) {
@@ -320,6 +321,10 @@
   return (std::ostringstream() << Quote(stage)).str();
 }
 
+std::string ToString(TimeDelta time_delta) {
+  return (std::ostringstream() << Quote(time_delta)).str();
+}
+
 constexpr TimeDelta kStalledFileInterval = base::Seconds(10);
 
 bool PinManager::CanPin(const FileMetadata& md, const Path& path) {
@@ -719,6 +724,8 @@
     }
   }
 
+  progress_.time_spent_listing_items = timer_.Elapsed();
+
   if (items.empty()) {
     VLOG(1) << "Visited " << dir_id << " " << Quote(dir_path);
 
@@ -729,7 +736,8 @@
       return;
     }
 
-    VLOG(1) << "Finished listing files in " << Quote(timer_.Elapsed());
+    VLOG(1) << "Finished listing files in "
+            << Quote(progress_.time_spent_listing_items);
     VLOG(1) << NiceNum << "Total queries: " << progress_.total_queries;
     VLOG(1) << NiceNum
             << "Max active queries: " << progress_.max_active_queries;
@@ -752,8 +760,9 @@
   }
 
   VLOG(1) << NiceNum << "Listed " << progress_.listed_items << " items in "
-          << Quote(timer_.Elapsed()) << ", Skipped " << progress_.skipped_items
-          << " items, Tracking " << files_to_track_.size() << " files";
+          << Quote(progress_.time_spent_listing_items) << ", Skipped "
+          << progress_.skipped_items << " items, Tracking "
+          << files_to_track_.size() << " files";
   NotifyProgress();
   GetNextPage(dir_id, std::move(dir_path), std::move(query));
 }
@@ -953,27 +962,37 @@
     DCHECK_EQ(progress_.syncing_files, CountPinnedFiles());
   }
 
+  if (!progress_.emptied_queue) {
+    progress_.time_spent_pinning_files = timer_.Elapsed();
+  }
+
+  bool notify_progress = false;
   if (progress_timer_.Elapsed() >= base::Seconds(1)) {
+    notify_progress = true;
     VLOG(1) << NiceNum << "Progress "
             << Percentage(progress_.pinned_bytes, progress_.bytes_to_pin)
             << "%: Synced " << HumanReadableSize(progress_.pinned_bytes)
-            << " and " << progress_.pinned_files << " files, Syncing "
+            << " and " << progress_.pinned_files << " files in "
+            << Quote(progress_.time_spent_pinning_files) << ", Syncing "
             << progress_.syncing_files << " files";
     progress_timer_ = {};
   }
 
   if (files_to_track_.empty() && !progress_.emptied_queue) {
+    notify_progress = true;
     progress_.emptied_queue = true;
     LOG_IF(ERROR, progress_.failed_files > 0)
         << NiceNum << "Failed to pin " << progress_.failed_files << " files";
     VLOG(1) << NiceNum << "Pinned " << progress_.pinned_files << " files and "
             << HumanReadableSize(progress_.pinned_bytes) << " in "
-            << Quote(timer_.Elapsed());
+            << Quote(progress_.time_spent_pinning_files);
     VLOG(2) << NiceNum << "Useful events: " << progress_.useful_events;
     VLOG(2) << NiceNum << "Duplicated events: " << progress_.duplicated_events;
   }
 
-  NotifyProgress();
+  if (notify_progress) {
+    NotifyProgress();
+  }
 }
 
 void PinManager::OnFilePinned(const Id id,
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager.h b/chromeos/ash/components/drivefs/drivefs_pin_manager.h
index 25b1a939..51b1872 100644
--- a/chromeos/ash/components/drivefs/drivefs_pin_manager.h
+++ b/chromeos/ash/components/drivefs/drivefs_pin_manager.h
@@ -45,9 +45,13 @@
 std::ostream& operator<<(std::ostream& out, HumanReadableSize size);
 
 using pin_manager_types::mojom::Stage;
+
 COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DRIVEFS)
 std::string ToString(Stage stage);
 
+COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DRIVEFS)
+std::string ToString(base::TimeDelta time_delta);
+
 // When the manager is setting up, this struct maintains all the information
 // gathered.
 struct COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DRIVEFS) Progress {
@@ -112,6 +116,9 @@
   // Stage of the setup process.
   Stage stage = Stage::kStopped;
 
+  base::TimeDelta time_spent_listing_items;
+  base::TimeDelta time_spent_pinning_files;
+
   // Has the PinManager ever emptied its set of tracking items?
   bool emptied_queue = false;
 
diff --git a/chromeos/ash/services/ime/public/mojom/input_method.mojom b/chromeos/ash/services/ime/public/mojom/input_method.mojom
index 117b403..ffcf0b60f 100644
--- a/chromeos/ash/services/ime/public/mojom/input_method.mojom
+++ b/chromeos/ash/services/ime/public/mojom/input_method.mojom
@@ -6,7 +6,7 @@
 // the Chromium repo. This file should be updated first, before syncing in the
 // other repos.
 
-// Next MinVersion: 19
+// Next MinVersion: 20
 
 module ash.ime.mojom;
 
@@ -302,7 +302,7 @@
   [MinVersion=10] TextPredictionMode text_prediction@3;
 };
 
-// Next ordinal: 4
+// Next ordinal: 8
 //
 // TODO(crbug.com/1261313): Note that this type must be marked [Extensible] in
 // all deployed versions before new ordinals can be introduced, and [Extensible]
@@ -315,6 +315,8 @@
   ZhuyinSettings zhuyin_settings@3;
   [MinVersion=14, Default] bool null_settings@4;
   [MinVersion=15] JapaneseSettings japanese_settings@5;
+  [MinVersion=19] VietnameseTelexSettings vietnamese_telex_settings@6;
+  [MinVersion=19] VietnameseVniSettings vietnamese_vni_settings@7;
 };
 
 // Next ordinal: 9
@@ -624,3 +626,39 @@
   // shown, dismissed, accepted etc).
   [MinVersion=13] OnAssistiveWindowChanged@9(AssistiveWindow window);
 };
+
+// Settings for Vietnamese Telex input method.
+//
+// Next ordinal: 4
+[Stable]
+struct VietnameseTelexSettings {
+  // Allow flexible diacritic assignment.
+  bool allow_flexible_diacritics@0;
+
+  // Defines the placement of tone marks for some syllables.
+  // If false, use "old style" placement.
+  bool new_style_tone_mark_placement@1;
+
+  // When a horn modifier is applied to "uo", it will add horns to both u and o.
+  bool enable_insert_double_horn_on_uo@2;
+
+  // Type the horn modifier trigger to get u-horn.
+  bool enable_w_for_u_horn_shortcut@3;
+};
+
+// Settings for Vietnamese VNI input method.
+//
+// Next ordinal: 3
+[Stable]
+struct VietnameseVniSettings {
+  // Allow flexible diacritic assignment.
+  bool allow_flexible_diacritics@0;
+
+  // Defines the placement of tone marks for some syllables.
+  // If false, use "old style" placement.
+  bool new_style_tone_mark_placement@1;
+
+  // When a horn modifier is applied to "uo", it will add horns to both u and o.
+  bool enable_insert_double_horn_on_uo@2;
+};
+
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 7272277..571e347 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -253,8 +253,8 @@
     "logging/log_router.h",
     "logging/text_log_receiver.cc",
     "logging/text_log_receiver.h",
-    "manual_testing_profile_import.cc",
-    "manual_testing_profile_import.h",
+    "manual_testing_import.cc",
+    "manual_testing_import.h",
     "merchant_promo_code_manager.cc",
     "merchant_promo_code_manager.h",
     "metrics/autofill_metrics.cc",
@@ -921,7 +921,7 @@
     "logging/log_manager_unittest.cc",
     "logging/log_router_unittest.cc",
     "logging/text_log_receiver_unittest.cc",
-    "manual_testing_profile_import_unittest.cc",
+    "manual_testing_import_unittest.cc",
     "merchant_promo_code_manager_unittest.cc",
     "metrics/autofill_metrics_unittest.cc",
     "metrics/converge_to_extreme_length_address_metrics_unittest.cc",
diff --git a/components/autofill/core/browser/manual_testing_profile_import.cc b/components/autofill/core/browser/manual_testing_import.cc
similarity index 99%
rename from components/autofill/core/browser/manual_testing_profile_import.cc
rename to components/autofill/core/browser/manual_testing_import.cc
index 7181c4ae..4d2f2065 100644
--- a/components/autofill/core/browser/manual_testing_profile_import.cc
+++ b/components/autofill/core/browser/manual_testing_import.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/autofill/core/browser/manual_testing_profile_import.h"
+#include "components/autofill/core/browser/manual_testing_import.h"
 
 #include <string>
 
diff --git a/components/autofill/core/browser/manual_testing_profile_import.h b/components/autofill/core/browser/manual_testing_import.h
similarity index 94%
rename from components/autofill/core/browser/manual_testing_profile_import.h
rename to components/autofill/core/browser/manual_testing_import.h
index 0aa2ca7..f0666182 100644
--- a/components/autofill/core/browser/manual_testing_profile_import.h
+++ b/components/autofill/core/browser/manual_testing_import.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_MANUAL_TESTING_PROFILE_IMPORT_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_MANUAL_TESTING_PROFILE_IMPORT_H_
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_MANUAL_TESTING_IMPORT_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_MANUAL_TESTING_IMPORT_H_
 
 #include <vector>
 
@@ -103,4 +103,4 @@
 
 }  // namespace autofill
 
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_MANUAL_TESTING_PROFILE_IMPORT_H_
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_MANUAL_TESTING_IMPORT_H_
diff --git a/components/autofill/core/browser/manual_testing_profile_import_unittest.cc b/components/autofill/core/browser/manual_testing_import_unittest.cc
similarity index 99%
rename from components/autofill/core/browser/manual_testing_profile_import_unittest.cc
rename to components/autofill/core/browser/manual_testing_import_unittest.cc
index 08e365e..d305b2e 100644
--- a/components/autofill/core/browser/manual_testing_profile_import_unittest.cc
+++ b/components/autofill/core/browser/manual_testing_import_unittest.cc
@@ -4,7 +4,7 @@
 
 #include <vector>
 
-#include "components/autofill/core/browser/manual_testing_profile_import.h"
+#include "components/autofill/core/browser/manual_testing_import.h"
 
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 2599afe..61242722 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -44,7 +44,7 @@
 #include "components/autofill/core/browser/geo/country_data.h"
 #include "components/autofill/core/browser/geo/country_names.h"
 #include "components/autofill/core/browser/geo/phone_number_i18n.h"
-#include "components/autofill/core/browser/manual_testing_profile_import.h"
+#include "components/autofill/core/browser/manual_testing_import.h"
 #include "components/autofill/core/browser/metrics/autofill_metrics.h"
 #include "components/autofill/core/browser/metrics/payments/iban_metrics.h"
 #include "components/autofill/core/browser/metrics/payments/offers_metrics.h"
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp
index fe38f67..a21fe0e 100644
--- a/components/autofill_strings.grdp
+++ b/components/autofill_strings.grdp
@@ -215,9 +215,6 @@
   <message name="IDS_AUTOFILL_ENABLE_CREDIT_CARDS_TOGGLE_SUBLABEL" desc="Sublabel for a toggle that allows users to control whether credit cards should be saved and forms should be autofilled with it." formatter_data="android_java">
     Fills in payment forms with your saved payment methods
   </message>
-  <message name="IDS_AUTOFILL_EDIT_ACCOUNT_ADDRESS_SOURCE_NOTICE" desc="The footer message in the 'Add/Edit address' dialog warning the user that this address is stored in their account.">
-    This address is saved in your Google Account (<ph name="ACCOUNT">$1<ex>alexpark@gmail.com</ex></ph>). You can use address across Google products on any device.
-  </message>
   <message name="IDS_AUTOFILL_DELETE_ACCOUNT_ADDRESS_SOURCE_NOTICE" desc="The notice/warning for the user before the address deletion." formatter_data="android_java">
     This address will be deleted from your Google Account, <ph name="ACCOUNT">$1<ex>alexpark@gmail.com</ex></ph>
   </message>
@@ -383,6 +380,18 @@
   <message name="IDS_AUTOFILL_MIGRATE_ADDRESS_PROMPT_CANCEL_BUTTON_LABEL" desc="Label of the Cancel button in the prompt that offers the user to migrate an existing address profile in their Google account." meaning="Don't migrate this address">
     No thanks
   </message>
+  <message name="IDS_AUTOFILL_SAVE_IN_ACCOUNT_PROMPT_ADDRESS_SOURCE_NOTICE" desc="The footer message in the 'Save address' prompt informing the user that this address will be stored in their account.">
+    You can use saved addresses across Google products. This address will be saved in your Google Account, <ph name="ACCOUNT">$1<ex>alexpark@gmail.com</ex></ph>.
+  </message>
+  <message name="IDS_AUTOFILL_UPDATE_PROMPT_ACCOUNT_ADDRESS_SOURCE_NOTICE" desc="The footer message in the 'Update address' prompt informing the user that this address is stored in their account.">
+    You can use saved addresses across Google products. This address is saved in your Google Account, <ph name="ACCOUNT">$1<ex>alexpark@gmail.com</ex></ph>.
+  </message>
+  <message name="IDS_AUTOFILL_SYNCABLE_PROFILE_MIGRATION_PROMPT_NOTICE" desc="The syncable profile prompt body text.">
+    This address is saved only to Chrome. To use it across Google products, save it in your Google Account, <ph name="ACCOUNT">$1<ex>alexpark@gmail.com</ex></ph>.
+  </message>
+  <message name="IDS_AUTOFILL_LOCAL_PROFILE_MIGRATION_PROMPT_NOTICE" desc="The local profile prompt body text.">
+    This address is saved only to this device. To use it across Google products, save it in your Google Account, <ph name="ACCOUNT">$1<ex>alexpark@gmail.com</ex></ph>.
+  </message>
   <!-- Used on Android: -->
   <if expr="is_android">
     <message name="IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_TITLE" desc="Title shown at the top of prompt that offers the user to save a new address.">
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_EDIT_ACCOUNT_ADDRESS_SOURCE_NOTICE.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_EDIT_ACCOUNT_ADDRESS_SOURCE_NOTICE.png.sha1
deleted file mode 100644
index 3c796293..0000000
--- a/components/autofill_strings_grdp/IDS_AUTOFILL_EDIT_ACCOUNT_ADDRESS_SOURCE_NOTICE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-59984ae104b528e40dc547676dadf59f6644f9da
\ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_LOCAL_PROFILE_MIGRATION_PROMPT_NOTICE.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_LOCAL_PROFILE_MIGRATION_PROMPT_NOTICE.png.sha1
new file mode 100644
index 0000000..c1649f01
--- /dev/null
+++ b/components/autofill_strings_grdp/IDS_AUTOFILL_LOCAL_PROFILE_MIGRATION_PROMPT_NOTICE.png.sha1
@@ -0,0 +1 @@
+02aa25ac028b247e1431e5ed928ad4f8bfe46893
\ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_SAVE_IN_ACCOUNT_PROMPT_ADDRESS_SOURCE_NOTICE.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_SAVE_IN_ACCOUNT_PROMPT_ADDRESS_SOURCE_NOTICE.png.sha1
new file mode 100644
index 0000000..2f89c85
--- /dev/null
+++ b/components/autofill_strings_grdp/IDS_AUTOFILL_SAVE_IN_ACCOUNT_PROMPT_ADDRESS_SOURCE_NOTICE.png.sha1
@@ -0,0 +1 @@
+4413d00471f889e2b1f13c7a9b610b2f0b5a691a
\ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_SYNCABLE_PROFILE_MIGRATION_PROMPT_NOTICE.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_SYNCABLE_PROFILE_MIGRATION_PROMPT_NOTICE.png.sha1
new file mode 100644
index 0000000..8b490cc2
--- /dev/null
+++ b/components/autofill_strings_grdp/IDS_AUTOFILL_SYNCABLE_PROFILE_MIGRATION_PROMPT_NOTICE.png.sha1
@@ -0,0 +1 @@
+3a59d0ba58d4ca4d0e5033a96aff393b2dbce91a
\ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_UPDATE_PROMPT_ACCOUNT_ADDRESS_SOURCE_NOTICE.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_UPDATE_PROMPT_ACCOUNT_ADDRESS_SOURCE_NOTICE.png.sha1
new file mode 100644
index 0000000..e0baa20
--- /dev/null
+++ b/components/autofill_strings_grdp/IDS_AUTOFILL_UPDATE_PROMPT_ACCOUNT_ADDRESS_SOURCE_NOTICE.png.sha1
@@ -0,0 +1 @@
+90a661a9ec222b2ce4047c306aa5bdf27d49866b
\ No newline at end of file
diff --git a/components/dom_distiller/core/dom_distiller_service.cc b/components/dom_distiller/core/dom_distiller_service.cc
index e8cad4f..bbb308fa 100644
--- a/components/dom_distiller/core/dom_distiller_service.cc
+++ b/components/dom_distiller/core/dom_distiller_service.cc
@@ -23,7 +23,7 @@
 
 ArticleEntry CreateSkeletonEntryForUrl(const GURL& url) {
   ArticleEntry skeleton;
-  skeleton.entry_id = base::GenerateUuid();
+  skeleton.entry_id = base::Uuid::GenerateRandomV4().AsLowercaseString();
   skeleton.pages.push_back(url);
 
   DCHECK(IsEntryValid(skeleton));
diff --git a/components/dom_distiller/core/url_utils.cc b/components/dom_distiller/core/url_utils.cc
index 164c4b52..4f0871c 100644
--- a/components/dom_distiller/core/url_utils.cc
+++ b/components/dom_distiller/core/url_utils.cc
@@ -36,7 +36,7 @@
 
 const GURL GetDistillerViewUrlFromEntryId(const std::string& scheme,
                                           const std::string& entry_id) {
-  GURL url(scheme + "://" + base::GenerateUuid());
+  GURL url(scheme + "://" + base::Uuid::GenerateRandomV4().AsLowercaseString());
   return net::AppendOrReplaceQueryParameter(url, kEntryIdKey, entry_id);
 }
 
@@ -44,8 +44,9 @@
                                       const GURL& url,
                                       const std::string& title,
                                       int64_t start_time_ms) {
-  GURL view_url(scheme + "://" + base::GenerateUuid() + kSeparator +
-                SHA256InHex(url.spec()));
+  GURL view_url(scheme + "://" +
+                base::Uuid::GenerateRandomV4().AsLowercaseString() +
+                kSeparator + SHA256InHex(url.spec()));
   view_url = net::AppendOrReplaceQueryParameter(view_url, kTitleKey, title);
   if (start_time_ms > 0) {
     view_url = net::AppendOrReplaceQueryParameter(
diff --git a/components/media_router/browser/mirroring_media_controller_host.cc b/components/media_router/browser/mirroring_media_controller_host.cc
index 0300cbf..332fd16 100644
--- a/components/media_router/browser/mirroring_media_controller_host.cc
+++ b/components/media_router/browser/mirroring_media_controller_host.cc
@@ -49,7 +49,7 @@
 
 void MirroringMediaControllerHost::OnMediaStatusUpdated(
     media_router::mojom::MediaStatusPtr status) {
-  // TODO(b/271442872): Once freeze info is implemented in MediaStatus, set
+  // TODO(b/271446487): Once freeze info is implemented in MediaStatus, set
   // can_freeze_ and is_frozen_ and update observers.
   for (MirroringMediaControllerHost::Observer& observer : observers_) {
     observer.OnFreezeInfoChanged();
diff --git a/components/media_router/browser/mirroring_media_controller_host.h b/components/media_router/browser/mirroring_media_controller_host.h
index 9018af7..d909473 100644
--- a/components/media_router/browser/mirroring_media_controller_host.h
+++ b/components/media_router/browser/mirroring_media_controller_host.h
@@ -45,6 +45,11 @@
   bool can_freeze() const { return can_freeze_; }
   bool is_frozen() const { return is_frozen_; }
 
+  // TODO(b/271446487): Once mojom::MediaStatus changes are implemented, remove
+  // this function and have tests call
+  // MirroringMediaControllerHost::OnMediaStatusUpdated() directly.
+  void set_is_frozen_for_test(bool is_frozen) { is_frozen_ = is_frozen; }
+
   void Freeze();
   void Unfreeze();
 
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc
index 7b143d9..667935c 100644
--- a/components/omnibox/browser/autocomplete_controller.cc
+++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -479,11 +479,6 @@
   expire_timer_.Stop();
   stop_timer_.Stop();
 
-  // Cancel any pending requests to the scoring model and invalidate the WeakPtr
-  // to prevent its callbacks from being called.
-  scoring_model_task_tracker_.TryCancelAll();
-  scoring_model_weak_ptr_ = nullptr;
-
   // Start the new query.
   sync_pass_done_ = false;
   // Use `start_time` rather than `metrics.start_time_` for
@@ -944,6 +939,9 @@
 void AutocompleteController::UpdateResult(
     bool regenerate_result,
     bool force_notify_default_match_changed) {
+  // Cancel the scoring model when updating `result_`.
+  CancelUrlScoringModel();
+
   TRACE_EVENT0("omnibox", "AutocompleteController::UpdateResult");
   SCOPED_UMA_HISTOGRAM_TIMER_MICROS("Omnibox.AutocompletionTime.UpdateResult");
 
@@ -1015,19 +1013,17 @@
         input_, template_url_service_, triggered_feature_service_,
         preserve_default_after_transfer ? preserve_default_match : nullptr);
   } else if (OmniboxFieldTrial::IsMlUrlScoringEnabled()) {
-    // The async ML scoring is only run once all the providers are done. Use a
-    // WeakPtr since the model is not owned and `this` may no longer be alive.
-    // `AnnotateResultAndNotifyChanged()` is called when the async ML scoring
-    // is done.
+    // The async scoring model is only run once all the providers are done. Use
+    // a WeakPtr since the model is not owned and `this` may no longer be alive.
+    // `AnnotateResultAndNotifyChanged()` is called when the model is done.
     // TODO(crbug.com/1405555): Deduplicate the matches before running the
     //  model in order to combine the signals. Optionally also trim the matches
     //  prior to running the model.
     // TODO(crbug.com/1405555): Investigate preserving the default match when
     //  reranking the matches using the model.
-    scoring_model_weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
     RunUrlScoringModel(base::BindOnce(
         &AutocompleteController::AnnotateResultAndNotifyChanged,
-        scoring_model_weak_ptr_, last_default_match,
+        weak_ptr_factory_.GetWeakPtr(), last_default_match,
         last_default_associated_keyword, force_notify_default_match_changed));
     return;
   } else {
@@ -1403,16 +1399,15 @@
     provider->Stop(clear_result, due_to_user_inactivity);
   }
 
-  // Cancel any pending requests to the scoring model and invalidate the WeakPtr
-  // to prevent its callbacks from being called.
-  scoring_model_task_tracker_.TryCancelAll();
-  scoring_model_weak_ptr_ = nullptr;
-
   expire_timer_.Stop();
   stop_timer_.Stop();
   done_ = true;
   if (clear_result && !result_.empty()) {
+    // Cancel the scoring model when updating `result_`.
+    CancelUrlScoringModel();
+
     result_.Reset();
+
     // Pass false to clear only the popup and not the edit. Passing true would,
     // e.g., discard the selected suggestion when closing the omnibox.
     DelayedNotifyChanged(false);
@@ -1522,6 +1517,44 @@
   return true;
 }
 
+void AutocompleteController::RunUrlScoringModel(
+    base::OnceClosure completion_callback) {
+  TRACE_EVENT0("omnibox", "AutocompleteController::RunUrlScoringModel");
+
+  auto barrier_callback =
+      base::BarrierCallback<std::tuple<absl::optional<float>, size_t, GURL>>(
+          result_.size(),
+          base::BindOnce(&AutocompleteController::OnUrlScoringModelDone,
+                         weak_ptr_factory_.GetWeakPtr(), input_,
+                         base::ElapsedTimer(), std::move(completion_callback)));
+
+  for (size_t match_index = 0; match_index < result_.matches_.size();
+       match_index++) {
+    auto* match = result_.match_at(match_index);
+    // The scoring model only supports URL matches - bookmarks, history, etc.
+    // Call the model for those types and directly invoke the model callback for
+    // any other match type.
+    if (AutocompleteMatch::GetDefaultGroupId(match->type) !=
+        omnibox::GROUP_OTHER_NAVS) {
+      barrier_callback.Run(
+          std::make_tuple(absl::nullopt, match_index, match->destination_url));
+      continue;
+    }
+
+    provider_client_->GetAutocompleteScoringModelService()
+        ->ScoreAutocompleteUrlMatch(&scoring_model_task_tracker_,
+                                    match->scoring_signals, match_index,
+                                    match->destination_url, barrier_callback);
+  }
+}
+
+void AutocompleteController::CancelUrlScoringModel() {
+  // Try to cancel any pending requests to the scoring model and invalidate the
+  // WeakPtr to prevent its callbacks from being called.
+  scoring_model_task_tracker_.TryCancelAll();
+  weak_ptr_factory_.InvalidateWeakPtrs();
+}
+
 void AutocompleteController::OnUrlScoringModelDone(
     AutocompleteInput input,
     const base::ElapsedTimer elapsed_timer,
@@ -1530,8 +1563,8 @@
         outputs_and_match_info) {
   TRACE_EVENT0("omnibox", "AutocompleteController::OnUrlScoringModelDone");
   // The goal is to redistribute the existing relevance scores among the URL
-  // suggestions according to the ML model output values. Construct two max
-  // heaps for the (legacy) relevance score and the output scores.
+  // suggestions according to the model output values. Construct two max heaps
+  // for the (legacy) relevance score and the output scores.
   std::priority_queue<int> relevance_heap;
   std::priority_queue<std::pair<float, size_t>> output_and_match_index_heap;
   for (auto& [output, index, destination_url] : outputs_and_match_info) {
@@ -1595,34 +1628,3 @@
 
   std::move(completion_callback).Run();
 }
-
-void AutocompleteController::RunUrlScoringModel(
-    base::OnceClosure completion_callback) {
-  TRACE_EVENT0("omnibox", "AutocompleteController::RunUrlScoringModel");
-
-  auto barrier_callback =
-      base::BarrierCallback<std::tuple<absl::optional<float>, size_t, GURL>>(
-          result_.size(),
-          base::BindOnce(&AutocompleteController::OnUrlScoringModelDone,
-                         scoring_model_weak_ptr_, input_, base::ElapsedTimer(),
-                         std::move(completion_callback)));
-
-  for (size_t match_index = 0; match_index < result_.matches_.size();
-       match_index++) {
-    auto* match = result_.match_at(match_index);
-    // The ML scoring model only supports URL matches - bookmarks, history, etc.
-    // Call the model for those types and directly invoke the model callback for
-    // any other match type.
-    if (AutocompleteMatch::GetDefaultGroupId(match->type) !=
-        omnibox::GROUP_OTHER_NAVS) {
-      barrier_callback.Run(
-          std::make_tuple(absl::nullopt, match_index, match->destination_url));
-      continue;
-    }
-
-    provider_client_->GetAutocompleteScoringModelService()
-        ->ScoreAutocompleteUrlMatch(&scoring_model_task_tracker_,
-                                    match->scoring_signals, match_index,
-                                    match->destination_url, barrier_callback);
-  }
-}
diff --git a/components/omnibox/browser/autocomplete_controller.h b/components/omnibox/browser/autocomplete_controller.h
index 3a5da688..5ae18b8 100644
--- a/components/omnibox/browser/autocomplete_controller.h
+++ b/components/omnibox/browser/autocomplete_controller.h
@@ -363,11 +363,23 @@
   // only runs on Lacros and the @tabs scope.
   bool ShouldRunProvider(AutocompleteProvider* provider) const;
 
-  // Called when the model is done running for all the eligible matches in
-  // `results_.matches_`. Redistributes the existing relevance scores to the
-  // matches based on the model output (i.e. highest relevance now belongs to
-  // the match with the highest output value, and vice versa), re-sorts and
-  // trims the matches, and calls `completion_callback`.
+  // Runs the async scoring model for all the eligible matches in
+  // `results_.matches_` and bypasses the ineligible matches. Passes
+  // `completion_callback` to `OnUrlScoringModelDone()` callback which is called
+  // once the model is done for all the eligible matches, whether successfully
+  // or not, and all the ineligible matches are bypassed.
+  void RunUrlScoringModel(base::OnceClosure completion_callback);
+
+  // Tries to cancel any pending requests to the scoring model and prevents
+  // `OnUrlScoringModelDone()` and its completion callback from being called.
+  void CancelUrlScoringModel();
+
+  // Called when the async scoring model is done running for all the eligible
+  // matches in `results_.matches_` and all the ineligible matches are bypassed.
+  // Redistributes the existing relevance scores to the matches based on the
+  // model output (i.e. highest relevance now belongs to the match with the
+  // highest output value, and vice versa), re-sorts and trims the matches, and
+  // calls `completion_callback`.
   void OnUrlScoringModelDone(
       AutocompleteInput input,
       const base::ElapsedTimer elapsed_timer,
@@ -375,12 +387,6 @@
       std::vector<std::tuple<absl::optional<float>, size_t, GURL>>
           outputs_and_match_info);
 
-  // Runs the ML scoring model asynchronously for all the eligible matches in
-  // `results_.matches_`. Passes `completion_callback` to
-  // `OnUrlScoringModelDone()` callback which is called once the scoring is done
-  // for all the eligible matches, whether successfully or not.
-  void RunUrlScoringModel(base::OnceClosure completion_callback);
-
   base::ObserverList<Observer> observers_;
 
   // The client passed to the providers.
@@ -507,10 +513,8 @@
   // Combined, used to cancel model execution requests sent to
   // `AutocompleteScoringModelService` and to prevent its callbacks from being
   // called `base::CancelableTaskTracker` alone is insufficient because it
-  // cannot cancel tasks that have already started.
+  // cannot cancel tasks that have already started to run.
   base::CancelableTaskTracker scoring_model_task_tracker_;
-  base::WeakPtr<AutocompleteController> scoring_model_weak_ptr_;
-
   base::WeakPtrFactory<AutocompleteController> weak_ptr_factory_{this};
 };
 
diff --git a/components/policy/resources/templates/policy_definitions/Miscellaneous/BruschettaVMConfiguration.yaml b/components/policy/resources/templates/policy_definitions/Miscellaneous/BruschettaVMConfiguration.yaml
index 58356ed..121e0c0b7 100644
--- a/components/policy/resources/templates/policy_definitions/Miscellaneous/BruschettaVMConfiguration.yaml
+++ b/components/policy/resources/templates/policy_definitions/Miscellaneous/BruschettaVMConfiguration.yaml
@@ -80,20 +80,6 @@
             hash:
               type: string
               description: Hexadecimal encoded SHA-256 hash of the data.
-        uefi_image_x86_64:
-          type: object
-          description: The UEFI firmware image used by the VM. This exists as a
-           temporary measure while we package it as a ChromeOS DLC.
-          required:
-          - url
-          - hash
-          properties:
-            url:
-              type: string
-              description: URL of the firmware image to download.
-            hash:
-              type: string
-              description: Hexadecimal encoded SHA-256 hash of the firmware image.
         vtpm:
           type: object
           description: Controls if VMs using this configuration have
@@ -133,9 +119,6 @@
     uefi_pflash_x86_64:
       url: https://example.com/uefi_pflash
       hash: 4d9a81e8feb96abb6da0d92642996a26edea6e94345da12a19999470c57bb0a6
-    uefi_image_x86_64:
-      url: https://example.com/uefi_image
-      hash: 5dcf78750da3326fb02b89051135ac563eb9509ec1587769ef36e86c260ab86d
     vtpm:
       enabled: true
       policy_update_action: NONE
diff --git a/components/policy/test/data/policy_test_cases.json b/components/policy/test/data/policy_test_cases.json
index 72007c8..3887ff5 100644
--- a/components/policy/test/data/policy_test_cases.json
+++ b/components/policy/test/data/policy_test_cases.json
@@ -11689,10 +11689,6 @@
               "uefi_pflash_x86_64": {
                 "url": "https://example.com/uefi_pflash",
                 "hash": "4d9a81e8feb96abb6da0d92642996a26edea6e94345da12a19999470c57bb0a6"
-              },
-              "uefi_image_x86_64": {
-                "url": "https://example.com/uefi_image",
-                "hash": "5dcf78750da3326fb02b89051135ac563eb9509ec1587769ef36e86c260ab86d"
               }
             }
           }
@@ -11723,10 +11719,6 @@
               "installer_image_x86_64": {
                 "url": "https://example.com/installer_image",
                 "hash": "761b22509ee7bd3e1a3da9eb9e37c6443acfc582670b733601ca5a1de44b99de"
-              },
-              "uefi_image_x86_64": {
-                "url": "https://example.com/uefi_image",
-                "hash": "5dcf78750da3326fb02b89051135ac563eb9509ec1587769ef36e86c260ab86d"
               }
             }
           }
@@ -11741,44 +11733,6 @@
                   "url": "https://example.com/installer_image",
                   "hash": "761b22509ee7bd3e1a3da9eb9e37c6443acfc582670b733601ca5a1de44b99de"
                 },
-                "uefi_image": {
-                  "url": "https://example.com/uefi_image",
-                  "hash": "5dcf78750da3326fb02b89051135ac563eb9509ec1587769ef36e86c260ab86d"
-                },
-                "vtpm": {
-                  "enabled": false,
-                  "policy_update_action": 1
-                },
-                "oem_strings": []
-              }
-            }
-          }
-        }
-      },
-      {
-        "note": "INSTALL_ALLOWED is downgraded if no uefi_image is set",
-        "policies": {
-          "BruschettaVMConfiguration": {
-            "vm-type": {
-              "name": "Standard Virtual Machine",
-              "enabled_state": "INSTALL_ALLOWED",
-              "installer_image_x86_64": {
-                "url": "https://example.com/installer_image",
-                "hash": "761b22509ee7bd3e1a3da9eb9e37c6443acfc582670b733601ca5a1de44b99de"
-              },
-              "uefi_pflash_x86_64": {
-                "url": "https://example.com/uefi_pflash",
-                "hash": "4d9a81e8feb96abb6da0d92642996a26edea6e94345da12a19999470c57bb0a6"
-              }
-            }
-          }
-        },
-        "prefs": {
-          "bruschetta.vm_configuration": {
-            "value": {
-              "vm-type": {
-                "name": "Standard Virtual Machine",
-                "enabled_state": 1,
                 "vtpm": {
                   "enabled": false,
                   "policy_update_action": 1
@@ -11801,9 +11755,6 @@
               },
               "uefi_pflash_x86_64": {
                 "hash": "4d9a81e8feb96abb6da0d92642996a26edea6e94345da12a19999470c57bb0a6"
-              },
-              "uefi_image_x86_64": {
-                "hash": "5dcf78750da3326fb02b89051135ac563eb9509ec1587769ef36e86c260ab86d"
               }
             }
           }
@@ -11828,10 +11779,6 @@
               "uefi_pflash_x86_64": {
                 "url": "invalid url",
                 "hash": "4d9a81e8feb96abb6da0d92642996a26edea6e94345da12a19999470c57bb0a6"
-              },
-              "uefi_image_x86_64": {
-                "url": "invalid url",
-                "hash": "5dcf78750da3326fb02b89051135ac563eb9509ec1587769ef36e86c260ab86d"
               }
             }
           }
@@ -11864,9 +11811,6 @@
               },
               "uefi_pflash_x86_64": {
                 "url": "https://example.com/uefi_pflash"
-              },
-              "uefi_image_x86_64": {
-                "url": "https://example.com/uefi_image"
               }
             }
           }
@@ -11891,10 +11835,6 @@
               "uefi_pflash_x86_64": {
                 "url": "https://example.com/uefi_pflash",
                 "hash": "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
-              },
-              "uefi_image_x86_64": {
-                "url": "https://example.com/uefi_image",
-                "hash": "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
               }
             }
           }
@@ -11929,10 +11869,6 @@
               "uefi_pflash_x86_64": {
                 "url": "https://example.com/uefi_pflash",
                 "hash": "4d9a81e8feb96abb6da0d92642996a26edea6e9434"
-              },
-              "uefi_image_x86_64": {
-                "url": "https://example.com/uefi_image",
-                "hash": "5dcf78750da3326fb02b89051135ac563eb9509ec1"
               }
             }
           }
@@ -11968,10 +11904,6 @@
                 "url": "https://example.com/uefi_pflash",
                 "hash": "4d9a81e8feb96abb6da0d92642996a26edea6e94345da12a19999470c57bb0a6"
               },
-              "uefi_image_x86_64": {
-                "url": "https://example.com/uefi_image",
-                "hash": "5dcf78750da3326fb02b89051135ac563eb9509ec1587769ef36e86c260ab86d"
-              },
               "vtpm": {
                 "enabled": true
               }
@@ -11987,10 +11919,6 @@
                 "url": "https://example.com/uefi_pflash_2",
                 "hash": "0923a3ddb53b9f1be54e0486322c8315e25a678a64941e15276d17ad2c63ee82"
               },
-              "uefi_image_x86_64": {
-                "url": "https://example.com/uefi_image_2",
-                "hash": "01b243b310908d7d54c275db05c411151bc3e3c331340e83eab5c8322819c2d9"
-              },
               "vtpm": {
                 "enabled": false,
                 "policy_update_action": "FORCE_SHUTDOWN_ALWAYS"
@@ -12013,10 +11941,6 @@
               "uefi_pflash_x86_64": {
                 "url": "https://example.com/uefi_pflash_2",
                 "hash": "0923a3ddb53b9f1be54e0486322c8315e25a678a64941e15276d17ad2c63ee82"
-              },
-              "uefi_image_x86_64": {
-                "url": "https://example.com/uefi_image_2",
-                "hash": "01b243b310908d7d54c275db05c411151bc3e3c331340e83eab5c8322819c2d9"
               }
             },
             "vulnerable-vm-type": {
@@ -12039,10 +11963,6 @@
                   "url": "https://example.com/uefi_pflash",
                   "hash": "4d9a81e8feb96abb6da0d92642996a26edea6e94345da12a19999470c57bb0a6"
                 },
-                "uefi_image": {
-                  "url": "https://example.com/uefi_image",
-                  "hash": "5dcf78750da3326fb02b89051135ac563eb9509ec1587769ef36e86c260ab86d"
-                },
                 "vtpm": {
                   "enabled": true,
                   "policy_update_action": 1
@@ -12060,10 +11980,6 @@
                   "url": "https://example.com/uefi_pflash_2",
                   "hash": "0923a3ddb53b9f1be54e0486322c8315e25a678a64941e15276d17ad2c63ee82"
                 },
-                "uefi_image": {
-                  "url": "https://example.com/uefi_image_2",
-                  "hash": "01b243b310908d7d54c275db05c411151bc3e3c331340e83eab5c8322819c2d9"
-                },
                 "vtpm": {
                   "enabled": false,
                   "policy_update_action": 2
diff --git a/components/services/font/public/cpp/font_loader.cc b/components/services/font/public/cpp/font_loader.cc
index 56bd5702..0248f7e0 100644
--- a/components/services/font/public/cpp/font_loader.cc
+++ b/components/services/font/public/cpp/font_loader.cc
@@ -28,7 +28,7 @@
                                  SkString* out_family_name,
                                  SkFontStyle* out_style) {
   TRACE_EVENT1("fonts", "FontServiceThread::MatchFamilyName", "family_name",
-               TRACE_STR_COPY(family_name));
+               TRACE_STR_COPY(family_name ? family_name : "<unspecified>"));
   return thread_->MatchFamilyName(family_name, requested, out_font_identifier,
                                   out_family_name, out_style);
 }
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
index 4adbd692..564949a 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
@@ -467,10 +467,10 @@
       weak_ptr_factory_.GetWeakPtr(), frame_host));
   filter->set_first_disallowed_load_callback(std::move(disallowed_callback));
 
-  AsyncDocumentSubresourceFilter* raw_ptr = filter.get();
+  AsyncDocumentSubresourceFilter* filter_ptr = filter.get();
   frame_host_filter_map_[frame_host] = std::move(filter);
 
-  return raw_ptr;
+  return filter_ptr;
 }
 
 void ContentSubresourceFilterThrottleManager::
diff --git a/components/user_manager/fake_user_manager.cc b/components/user_manager/fake_user_manager.cc
index cd0cab59..9a4fcedb 100644
--- a/components/user_manager/fake_user_manager.cc
+++ b/components/user_manager/fake_user_manager.cc
@@ -42,10 +42,10 @@
 
 namespace user_manager {
 
-FakeUserManager::FakeUserManager() : UserManagerBase(new FakeTaskRunner()) {}
+FakeUserManager::FakeUserManager(PrefService* local_state)
+    : UserManagerBase(new FakeTaskRunner(), local_state) {}
 
-FakeUserManager::~FakeUserManager() {
-}
+FakeUserManager::~FakeUserManager() = default;
 
 std::string FakeUserManager::GetFakeUsernameHash(const AccountId& account_id) {
   // Consistent with the
@@ -360,10 +360,6 @@
   return default_locale;
 }
 
-PrefService* FakeUserManager::GetLocalState() const {
-  return local_state_;
-}
-
 bool FakeUserManager::IsEnterpriseManaged() const {
   return false;
 }
diff --git a/components/user_manager/fake_user_manager.h b/components/user_manager/fake_user_manager.h
index 738f921a..3caa371f 100644
--- a/components/user_manager/fake_user_manager.h
+++ b/components/user_manager/fake_user_manager.h
@@ -21,7 +21,7 @@
 // and set as logged in, and those users can be returned.
 class USER_MANAGER_EXPORT FakeUserManager : public UserManagerBase {
  public:
-  FakeUserManager();
+  explicit FakeUserManager(PrefService* local_state = nullptr);
 
   FakeUserManager(const FakeUserManager&) = delete;
   FakeUserManager& operator=(const FakeUserManager&) = delete;
@@ -56,7 +56,6 @@
   void SetUserNonCryptohomeDataEphemeral(const AccountId& account_id,
                                          bool is_ephemeral);
 
-  void set_local_state(PrefService* local_state) { local_state_ = local_state; }
   void set_is_current_user_new(bool is_current_user_new) {
     is_current_user_new_ = is_current_user_new;
   }
@@ -153,7 +152,6 @@
       EphemeralModeConfig ephemeral_mode_config) override;
 
   const std::string& GetApplicationLocale() const override;
-  PrefService* GetLocalState() const override;
   bool IsEnterpriseManaged() const override;
   void LoadDeviceLocalAccounts(
       std::set<AccountId>* device_local_accounts_set) override {}
@@ -166,9 +164,6 @@
   void OnUserRemoved(const AccountId& account_id) override {}
 
  protected:
-  // Can be set by set_local_state().
-  raw_ptr<PrefService> local_state_ = nullptr;
-
   // If set this is the active user. If empty, the first created user is the
   // active user.
   AccountId active_account_id_ = EmptyAccountId();
diff --git a/components/user_manager/user_manager_base.cc b/components/user_manager/user_manager_base.cc
index cbd8a40..be328318 100644
--- a/components/user_manager/user_manager_base.cc
+++ b/components/user_manager/user_manager_base.cc
@@ -10,6 +10,7 @@
 #include <set>
 #include <utility>
 
+#include "base/check_is_test.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/format_macros.h"
@@ -153,8 +154,14 @@
 }
 
 UserManagerBase::UserManagerBase(
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-    : task_runner_(std::move(task_runner)) {}
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+    PrefService* local_state)
+    : task_runner_(std::move(task_runner)), local_state_(local_state) {
+  // |local_state| can be nullptr only for testing.
+  if (!local_state) {
+    CHECK_IS_TEST();
+  }
+}
 
 UserManagerBase::~UserManagerBase() {
   // Can't use STLDeleteElements because of the private destructor of User.
@@ -202,7 +209,7 @@
 
   if (!last_session_active_account_id_initialized_) {
     last_session_active_account_id_ =
-        AccountId::FromUserEmail(GetLocalState()->GetString(kLastActiveUser));
+        AccountId::FromUserEmail(local_state_->GetString(kLastActiveUser));
     last_session_active_account_id_initialized_ = true;
   }
 
@@ -280,9 +287,9 @@
   static crash_reporter::CrashKeyString<32> session_type("session-type");
   session_type.Set(UserTypeToString(active_user_->GetType()));
 
-  GetLocalState()->SetString(
-      kLastLoggedInGaiaUser,
-      active_user_->HasGaiaAccount() ? account_id.GetUserEmail() : "");
+  local_state_->SetString(kLastLoggedInGaiaUser, active_user_->HasGaiaAccount()
+                                                     ? account_id.GetUserEmail()
+                                                     : "");
 
   NotifyOnLogin();
   PerformPostUserLoggedInActions(browser_restart);
@@ -341,14 +348,14 @@
   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
 
   CallUpdateLoginState();
-  GetLocalState()->CommitPendingWrite();
+  local_state_->CommitPendingWrite();
 }
 
 void UserManagerBase::RemoveUser(const AccountId& account_id,
                                  UserRemovalReason reason) {
   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
 
-  UserDirectoryIntegrityManager integrity_manager(GetLocalState());
+  UserDirectoryIntegrityManager integrity_manager(local_state_.get());
   // Misconfigured user would not be included in GetUsers(),
   // account for them separately.
   if (!CanUserBeRemoved(FindUser(account_id)) &&
@@ -394,7 +401,7 @@
   }
 
   RemoveNonCryptohomeData(account_id);
-  KnownUser(GetLocalState()).RemovePrefs(account_id);
+  KnownUser(local_state_.get()).RemovePrefs(account_id);
   if (user_loading_stage_ == STAGE_LOADED) {
     // After the User object is deleted from memory in DeleteUser() here,
     // the account_id reference will be invalid if the reference points
@@ -411,7 +418,7 @@
   }
 
   // Make sure that new data is persisted to Local State.
-  GetLocalState()->CommitPendingWrite();
+  local_state_->CommitPendingWrite();
 }
 
 bool UserManagerBase::IsKnownUser(const AccountId& account_id) const {
@@ -419,7 +426,7 @@
   // `WallpaperControllerClientImpl::RemoveUserWallpaper` would not remove
   // the wallpaper prefs if we return false here, thus leaving behind
   // orphan prefs for the misconfigured users.
-  UserDirectoryIntegrityManager integrity_manager(GetLocalState());
+  UserDirectoryIntegrityManager integrity_manager(local_state_.get());
   return FindUser(account_id) != nullptr ||
          integrity_manager.IsUserMisconfigured(account_id);
 }
@@ -469,12 +476,12 @@
     return;
 
   {
-    ScopedDictPrefUpdate oauth_status_update(GetLocalState(),
+    ScopedDictPrefUpdate oauth_status_update(local_state_.get(),
                                              kUserOAuthTokenStatus);
     oauth_status_update->Set(account_id.GetUserEmail(),
                              static_cast<int>(oauth_token_status));
   }
-  GetLocalState()->CommitPendingWrite();
+  local_state_->CommitPendingWrite();
 }
 
 void UserManagerBase::SaveForceOnlineSignin(const AccountId& account_id,
@@ -491,11 +498,11 @@
     return;
 
   {
-    ScopedDictPrefUpdate force_online_update(GetLocalState(),
+    ScopedDictPrefUpdate force_online_update(local_state_.get(),
                                              kUserForceOnlineSignin);
     force_online_update->Set(account_id.GetUserEmail(), force_online_signin);
   }
-  GetLocalState()->CommitPendingWrite();
+  local_state_->CommitPendingWrite();
 }
 
 void UserManagerBase::SaveUserDisplayName(const AccountId& account_id,
@@ -508,7 +515,7 @@
     // Do not update local state if data stored or cached outside the user's
     // cryptohome is to be treated as ephemeral.
     if (!IsUserNonCryptohomeDataEphemeral(account_id)) {
-      ScopedDictPrefUpdate display_name_update(GetLocalState(),
+      ScopedDictPrefUpdate display_name_update(local_state_.get(),
                                                kUserDisplayName);
       display_name_update->Set(account_id.GetUserEmail(), display_name);
     }
@@ -538,13 +545,13 @@
   if (IsUserNonCryptohomeDataEphemeral(account_id))
     return;
 
-  ScopedDictPrefUpdate display_email_update(GetLocalState(), kUserDisplayEmail);
+  ScopedDictPrefUpdate display_email_update(local_state_.get(),
+                                            kUserDisplayEmail);
   display_email_update->Set(account_id.GetUserEmail(), display_email);
 }
 
 UserType UserManagerBase::GetUserType(const AccountId& account_id) {
-  const base::Value::Dict& prefs_user_types =
-      GetLocalState()->GetDict(kUserType);
+  const base::Value::Dict& prefs_user_types = local_state_->GetDict(kUserType);
   return GetStoredUserType(prefs_user_types, account_id);
 }
 
@@ -557,14 +564,14 @@
   if (IsUserNonCryptohomeDataEphemeral(user->GetAccountId()))
     return;
 
-  ScopedDictPrefUpdate user_type_update(GetLocalState(), kUserType);
+  ScopedDictPrefUpdate user_type_update(local_state_.get(), kUserType);
   user_type_update->Set(user->GetAccountId().GetAccountIdKey(),
                         static_cast<int>(user->GetType()));
-  GetLocalState()->CommitPendingWrite();
+  local_state_->CommitPendingWrite();
 }
 
 absl::optional<std::string> UserManagerBase::GetOwnerEmail() {
-  const base::Value::Dict& owner = GetLocalState()->GetDict(kOwnerAccount);
+  const base::Value::Dict& owner = local_state_->GetDict(kOwnerAccount);
   absl::optional<int> type = owner.FindInt(kOwnerAccountType);
   if (!type.has_value() || (static_cast<OwnerAccountType>(type.value())) !=
                                OwnerAccountType::kGoogleEmail) {
@@ -583,11 +590,11 @@
   owner_dict.Set(kOwnerAccountType,
                  static_cast<int>(OwnerAccountType::kGoogleEmail));
   owner_dict.Set(kOwnerAccountIdentity, owner.GetUserEmail());
-  GetLocalState()->SetDict(kOwnerAccount, std::move(owner_dict));
+  local_state_->SetDict(kOwnerAccount, std::move(owner_dict));
   // The information about the owner might be needed for recovery if Chrome
   // crashes before establishing ownership, so it needs to be written on disk as
   // soon as possible.
-  GetLocalState()->CommitPendingWrite();
+  local_state_->CommitPendingWrite();
 }
 
 void UserManagerBase::UpdateUserAccountData(
@@ -601,7 +608,8 @@
     std::u16string given_name = account_data.given_name();
     user->set_given_name(given_name);
     if (!IsUserNonCryptohomeDataEphemeral(account_id)) {
-      ScopedDictPrefUpdate given_name_update(GetLocalState(), kUserGivenName);
+      ScopedDictPrefUpdate given_name_update(local_state_.get(),
+                                             kUserGivenName);
       given_name_update->Set(account_id.GetUserEmail(), given_name);
     }
   }
@@ -623,7 +631,7 @@
     }
 
     const AccountId account_id =
-        KnownUser(GetLocalState())
+        KnownUser(local_state_.get())
             .GetAccountId(*email, std::string() /* id */, AccountType::UNKNOWN);
 
     if (existing_users.find(account_id) != existing_users.end() ||
@@ -933,24 +941,24 @@
 
 void UserManagerBase::EnsureUsersLoaded() {
   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
-  if (!GetLocalState())
+  if (!local_state_) {
     return;
+  }
 
   if (user_loading_stage_ != STAGE_NOT_LOADED)
     return;
   user_loading_stage_ = STAGE_LOADING;
 
-  PrefService* local_state = GetLocalState();
   const base::Value::List& prefs_regular_users =
-      local_state->GetList(kRegularUsersPref);
+      local_state_->GetList(kRegularUsersPref);
 
   const base::Value::Dict& prefs_display_names =
-      local_state->GetDict(kUserDisplayName);
+      local_state_->GetDict(kUserDisplayName);
   const base::Value::Dict& prefs_given_names =
-      local_state->GetDict(kUserGivenName);
+      local_state_->GetDict(kUserGivenName);
   const base::Value::Dict& prefs_display_emails =
-      local_state->GetDict(kUserDisplayEmail);
-  const base::Value::Dict& prefs_user_types = local_state->GetDict(kUserType);
+      local_state_->GetDict(kUserDisplayEmail);
+  const base::Value::Dict& prefs_user_types = local_state_->GetDict(kUserType);
 
   // Load public sessions first.
   std::set<AccountId> device_local_accounts_set;
@@ -969,7 +977,7 @@
       continue;
     }
 
-    UserDirectoryIntegrityManager integrity_manager(GetLocalState());
+    UserDirectoryIntegrityManager integrity_manager(local_state_.get());
     if (integrity_manager.IsUserMisconfigured(*it)) {
       // Skip misconfigured user.
       VLOG(1) << "Encountered misconfigured user while loading list of "
@@ -984,7 +992,7 @@
         User::CreateRegularUser(*it, GetStoredUserType(prefs_user_types, *it));
     user->set_oauth_token_status(LoadUserOAuthStatus(*it));
     user->set_force_online_signin(LoadForceOnlineSignin(*it));
-    KnownUser known_user(GetLocalState());
+    KnownUser known_user(local_state_.get());
     user->set_using_saml(known_user.IsUsingSAML(*it));
     users_.push_back(user);
   }
@@ -1029,8 +1037,7 @@
 }
 
 bool UserManagerBase::UserExistsInList(const AccountId& account_id) const {
-  const base::Value::List& user_list =
-      GetLocalState()->GetList(kRegularUsersPref);
+  const base::Value::List& user_list = local_state_->GetList(kRegularUsersPref);
   for (const base::Value& i : user_list) {
     const std::string* email = i.GetIfString();
     if (email && (account_id.GetUserEmail() == *email))
@@ -1055,7 +1062,8 @@
 
 void UserManagerBase::AddUserRecord(User* user) {
   // Add the user to the front of the user list.
-  ScopedListPrefUpdate prefs_users_update(GetLocalState(), kRegularUsersPref);
+  ScopedListPrefUpdate prefs_users_update(local_state_.get(),
+                                          kRegularUsersPref);
   prefs_users_update->Insert(prefs_users_update->begin(),
                              base::Value(user->GetAccountId().GetUserEmail()));
   users_.insert(users_.begin(), user);
@@ -1066,7 +1074,7 @@
   // Remove the user from the user list.
   active_user_ =
       RemoveRegularOrSupervisedUserFromList(account_id, false /* notify */);
-  KnownUser known_user(GetLocalState());
+  KnownUser known_user(local_state_.get());
 
   if (active_user_ && active_user_->GetType() != user_type) {
     active_user_->UpdateType(user_type);
@@ -1092,7 +1100,7 @@
   known_user.SetIsEphemeralUser(active_user_->GetAccountId(), false);
 
   // Make sure that new data is persisted to Local State.
-  GetLocalState()->CommitPendingWrite();
+  local_state_->CommitPendingWrite();
 }
 
 void UserManagerBase::RegularUserLoggedInAsEphemeral(
@@ -1102,7 +1110,7 @@
   SetIsCurrentUserNew(true);
   is_current_user_ephemeral_regular_user_ = true;
   active_user_ = User::CreateRegularUser(account_id, user_type);
-  KnownUser(GetLocalState())
+  KnownUser(local_state_.get())
       .SetIsEphemeralUser(active_user_->GetAccountId(), true);
 }
 
@@ -1124,7 +1132,7 @@
   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
 
   const base::Value::Dict& prefs_oauth_status =
-      GetLocalState()->GetDict(kUserOAuthTokenStatus);
+      local_state_->GetDict(kUserOAuthTokenStatus);
 
   absl::optional<int> oauth_token_status =
       prefs_oauth_status.FindInt(account_id.GetUserEmail());
@@ -1138,40 +1146,41 @@
   DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
 
   const base::Value::Dict& prefs_force_online =
-      GetLocalState()->GetDict(kUserForceOnlineSignin);
+      local_state_->GetDict(kUserForceOnlineSignin);
 
   return prefs_force_online.FindBool(account_id.GetUserEmail()).value_or(false);
 }
 
 void UserManagerBase::RemoveNonCryptohomeData(const AccountId& account_id) {
-  PrefService* prefs = GetLocalState();
-  ScopedDictPrefUpdate prefs_display_name_update(prefs, kUserDisplayName);
-  prefs_display_name_update->Remove(account_id.GetUserEmail());
+  ScopedDictPrefUpdate(local_state_.get(), kUserDisplayName)
+      ->Remove(account_id.GetUserEmail());
 
-  ScopedDictPrefUpdate prefs_given_name_update(prefs, kUserGivenName);
-  prefs_given_name_update->Remove(account_id.GetUserEmail());
+  ScopedDictPrefUpdate(local_state_.get(), kUserGivenName)
+      ->Remove(account_id.GetUserEmail());
 
-  ScopedDictPrefUpdate prefs_display_email_update(prefs, kUserDisplayEmail);
-  prefs_display_email_update->Remove(account_id.GetUserEmail());
+  ScopedDictPrefUpdate(local_state_.get(), kUserDisplayEmail)
+      ->Remove(account_id.GetUserEmail());
 
-  ScopedDictPrefUpdate prefs_oauth_update(prefs, kUserOAuthTokenStatus);
-  prefs_oauth_update->Remove(account_id.GetUserEmail());
+  ScopedDictPrefUpdate(local_state_.get(), kUserOAuthTokenStatus)
+      ->Remove(account_id.GetUserEmail());
 
-  ScopedDictPrefUpdate prefs_force_online_update(prefs, kUserForceOnlineSignin);
-  prefs_force_online_update->Remove(account_id.GetUserEmail());
+  ScopedDictPrefUpdate(local_state_.get(), kUserForceOnlineSignin)
+      ->Remove(account_id.GetUserEmail());
 
-  KnownUser(prefs).RemovePrefs(account_id);
+  KnownUser(local_state_.get()).RemovePrefs(account_id);
 
   const AccountId last_active_user =
-      AccountId::FromUserEmail(GetLocalState()->GetString(kLastActiveUser));
-  if (account_id == last_active_user)
-    GetLocalState()->SetString(kLastActiveUser, std::string());
+      AccountId::FromUserEmail(local_state_->GetString(kLastActiveUser));
+  if (account_id == last_active_user) {
+    local_state_->SetString(kLastActiveUser, std::string());
+  }
 }
 
 User* UserManagerBase::RemoveRegularOrSupervisedUserFromList(
     const AccountId& account_id,
     bool notify) {
-  ScopedListPrefUpdate prefs_users_update(GetLocalState(), kRegularUsersPref);
+  ScopedListPrefUpdate prefs_users_update(local_state_.get(),
+                                          kRegularUsersPref);
   prefs_users_update->clear();
   User* user = nullptr;
   for (UserList::iterator it = users_.begin(); it != users_.end();) {
@@ -1200,13 +1209,16 @@
     observer.UserAddedToSession(added_user);
 }
 
+PrefService* UserManagerBase::GetLocalState() const {
+  return local_state_.get();
+}
+
 void UserManagerBase::Initialize() {
   UserManager::Initialize();
   if (!HasBrowserRestarted()) {
-    PrefService* local_state = GetLocalState();
     // local_state may be null in unit tests.
-    if (local_state) {
-      KnownUser known_user(local_state);
+    if (local_state_) {
+      KnownUser known_user(local_state_.get());
       known_user.CleanEphemeralUsers();
       known_user.CleanObsoletePrefs();
     }
@@ -1219,9 +1231,8 @@
 }
 
 void UserManagerBase::SetLRUUser(User* user) {
-  GetLocalState()->SetString(kLastActiveUser,
-                             user->GetAccountId().GetUserEmail());
-  GetLocalState()->CommitPendingWrite();
+  local_state_->SetString(kLastActiveUser, user->GetAccountId().GetUserEmail());
+  local_state_->CommitPendingWrite();
 
   UserList::iterator it = base::ranges::find(lru_logged_in_users_, user);
   if (it != lru_logged_in_users_.end())
@@ -1235,8 +1246,7 @@
   if (IsFirstExecAfterBoot())
     return;
 
-  const std::string last_email =
-      GetLocalState()->GetString(kLastLoggedInGaiaUser);
+  const std::string last_email = local_state_->GetString(kLastLoggedInGaiaUser);
   const base::TimeDelta time_to_login =
       base::TimeTicks::Now() - manager_creation_time_;
   if (!last_email.empty() &&
diff --git a/components/user_manager/user_manager_base.h b/components/user_manager/user_manager_base.h
index b81735bc..6cb56f0 100644
--- a/components/user_manager/user_manager_base.h
+++ b/components/user_manager/user_manager_base.h
@@ -63,9 +63,10 @@
     kMaxValue = kLSUDeleted
   };
 
-  // Creates UserManagerBase with |task_runner| for UI thread.
-  explicit UserManagerBase(
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+  // Creates UserManagerBase with |task_runner| for UI thread, and given
+  // |local_state|. |local_state| must outlive this UserManager.
+  UserManagerBase(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+                  PrefService* local_state);
 
   UserManagerBase(const UserManagerBase&) = delete;
   UserManagerBase& operator=(const UserManagerBase&) = delete;
@@ -159,6 +160,7 @@
   void NotifyUserToBeRemoved(const AccountId& account_id) override;
   void NotifyUserRemoved(const AccountId& account_id,
                          UserRemovalReason reason) override;
+  PrefService* GetLocalState() const final;
   void Initialize() override;
 
   // This method updates "User was added to the device in this session nad is
@@ -418,6 +420,8 @@
   // TaskRunner for UI thread.
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
+  const base::raw_ptr<PrefService> local_state_;
+
   base::WeakPtrFactory<UserManagerBase> weak_factory_{this};
 };
 
diff --git a/components/vector_icons/BUILD.gn b/components/vector_icons/BUILD.gn
index 8a2dcd8..fe4937f 100644
--- a/components/vector_icons/BUILD.gn
+++ b/components/vector_icons/BUILD.gn
@@ -90,6 +90,7 @@
     "media_router_error.icon",
     "media_router_idle.icon",
     "media_router_idle_chrome_refresh.icon",
+    "media_router_paused.icon",
     "media_router_warning.icon",
     "media_seek_backward.icon",
     "media_seek_forward.icon",
diff --git a/components/vector_icons/media_router_paused.icon b/components/vector_icons/media_router_paused.icon
new file mode 100644
index 0000000..9746302
--- /dev/null
+++ b/components/vector_icons/media_router_paused.icon
@@ -0,0 +1,70 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 18, 11.2f,
+CUBIC_TO, 17.54f, 11.47f, 17.03f, 11.67f, 16.5f, 11.81f,
+V_LINE_TO, 14.5f,
+H_LINE_TO, 11.5f,
+V_LINE_TO, 16,
+H_LINE_TO, 16.5f,
+CUBIC_TO, 16.92f, 16, 17.27f, 15.85f, 17.56f, 15.56f,
+CUBIC_TO, 17.85f, 15.26f, 18, 14.9f, 18, 14.5f,
+V_LINE_TO, 11.2f,
+CLOSE,
+MOVE_TO, 9.34f, 4,
+H_LINE_TO, 3.5f,
+CUBIC_TO, 3.1f, 4, 2.74f, 4.15f, 2.44f, 4.46f,
+CUBIC_TO, 2.15f, 4.75f, 2, 5.1f, 2, 5.5f,
+V_LINE_TO, 6.5f,
+H_LINE_TO, 3.5f,
+V_LINE_TO, 5.5f,
+H_LINE_TO, 9.02f,
+CUBIC_TO, 9.06f, 4.98f, 9.17f, 4.48f, 9.34f, 4,
+CLOSE,
+MOVE_TO, 4, 16,
+H_LINE_TO, 2,
+V_LINE_TO, 14,
+CUBIC_TO, 2.56f, 14, 3.03f, 14.19f, 3.42f, 14.58f,
+CUBIC_TO, 3.81f, 14.97f, 4, 15.44f, 4, 16,
+CLOSE,
+MOVE_TO, 7, 16,
+H_LINE_TO, 5.5f,
+CUBIC_TO, 5.5f, 15.03f, 5.16f, 14.2f, 4.48f, 13.52f,
+CUBIC_TO, 3.8f, 12.84f, 2.97f, 12.5f, 2, 12.5f,
+V_LINE_TO, 11,
+CUBIC_TO, 3.39f, 11, 4.57f, 11.49f, 5.54f, 12.46f,
+CUBIC_TO, 6.51f, 13.43f, 7, 14.61f, 7, 16,
+CLOSE,
+MOVE_TO, 2, 9.5f,
+V_LINE_TO, 8,
+CUBIC_TO, 3.11f, 8, 4.15f, 8.21f, 5.1f, 8.63f,
+CUBIC_TO, 6.08f, 9.04f, 6.92f, 9.62f, 7.65f, 10.35f,
+CUBIC_TO, 8.38f, 11.08f, 8.96f, 11.92f, 9.38f, 12.9f,
+CUBIC_TO, 9.79f, 13.85f, 10, 14.89f, 10, 16,
+H_LINE_TO, 8.5f,
+CUBIC_TO, 8.5f, 15.1f, 8.33f, 14.26f, 7.98f, 13.48f,
+CUBIC_TO, 7.65f, 12.69f, 7.18f, 12, 6.58f, 11.42f,
+CUBIC_TO, 6, 10.82f, 5.31f, 10.35f, 4.52f, 10.02f,
+CUBIC_TO, 3.74f, 9.67f, 2.9f, 9.5f, 2, 9.5f,
+CLOSE,
+NEW_PATH,
+MOVE_TO, 15, 1.2f,
+CUBIC_TO, 12.35f, 1.2f, 10.2f, 3.35f, 10.2f, 6,
+CUBIC_TO, 10.2f, 8.65f, 12.35f, 10.8f, 15, 10.8f,
+CUBIC_TO, 17.65f, 10.8f, 19.8f, 8.65f, 19.8f, 6,
+CUBIC_TO, 19.8f, 3.35f, 17.65f, 1.2f, 15, 1.2f,
+CLOSE,
+MOVE_TO, 14.4f, 7.8f,
+H_LINE_TO, 13.2f,
+V_LINE_TO, 4.2f,
+H_LINE_TO, 14.4f,
+V_LINE_TO, 7.8f,
+CLOSE,
+MOVE_TO, 16.8f, 7.8f,
+H_LINE_TO, 15.6f,
+V_LINE_TO, 4.2f,
+H_LINE_TO, 16.8f,
+V_LINE_TO, 7.8f,
+CLOSE
diff --git a/components/viz/service/display/overlay_processor_using_strategy.cc b/components/viz/service/display/overlay_processor_using_strategy.cc
index 8ec1895..a9c9e57 100644
--- a/components/viz/service/display/overlay_processor_using_strategy.cc
+++ b/components/viz/service/display/overlay_processor_using_strategy.cc
@@ -5,16 +5,22 @@
 #include "components/viz/service/display/overlay_processor_using_strategy.h"
 
 #include <algorithm>
+#include <iterator>
 #include <memory>
 #include <set>
 #include <utility>
 #include <vector>
 
+#include "base/check.h"
+#include "base/containers/flat_set.h"
+#include "base/containers/span.h"
 #include "base/feature_list.h"
+#include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/ranges/algorithm.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "base/timer/elapsed_timer.h"
 #include "base/trace_event/trace_event.h"
@@ -30,6 +36,7 @@
 #include "components/viz/service/display/output_surface.h"
 #include "components/viz/service/display/overlay_candidate.h"
 #include "components/viz/service/display/overlay_combination_cache.h"
+#include "components/viz/service/display/overlay_proposed_candidate.h"
 #include "components/viz/service/display/overlay_strategy_single_on_top.h"
 #include "components/viz/service/display/overlay_strategy_underlay.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -71,6 +78,123 @@
     "Compositing.Display.OverlayProcessorUsingStrategy."
     "FramesScalingRequiredOverlays";
 
+using OverlayProposedCandidateIndex =
+    std::vector<OverlayProposedCandidate>::size_type;
+using ConstOverlayProposedCandidateIterator =
+    std::vector<OverlayProposedCandidate>::const_iterator;
+
+// Appends candidates with display masks at the end of `test_candidates` if they
+// occlude any candidate in `test_candidates`. These candidates are in the list
+// between `rounded_corner_candidates_begin` and rounded_corner_candidates_end`.
+//
+// Returns the iterator to start of candidates with display mask in
+// `test_candidates`. If no candidates were added, it returns
+// `test_candidates.cend()`.
+ConstOverlayProposedCandidateIterator MaybeAppendOccludingMaskCandidates(
+    ConstOverlayProposedCandidateIterator candidates_wth_masks_begin,
+    ConstOverlayProposedCandidateIterator candidates_wth_masks_end,
+    std::vector<OverlayProposedCandidate>& test_candidates) {
+  // Keep track of the starting index of mask candidates in test_candidates`
+  // list.
+  OverlayProposedCandidateIndex begin_mask_candidates_index =
+      test_candidates.size();
+
+  for (auto& it = candidates_wth_masks_begin; it < candidates_wth_masks_end;
+       it++) {
+    auto mask_key = OverlayProposedCandidate::ToProposeKey(*it);
+    for (OverlayProposedCandidateIndex i = 0; i < begin_mask_candidates_index;
+         i++) {
+      const auto& keys = test_candidates[i].occluding_mask_keys;
+
+      // Append candidates with masks if they occludes any other overlay
+      // candidate in `test_candidates`.
+      if (keys.contains(mask_key)) {
+        test_candidates.push_back(*it);
+      }
+    }
+  }
+
+  return test_candidates.cbegin() + begin_mask_candidates_index;
+}
+
+// Returns true if `candidate` is occluded by any candidate with rounded-display
+// masks in `mask_candidates`.
+bool IsOccludedByMaskCandidates(
+    const OverlayProposedCandidate& candidate,
+    const std::vector<OverlayProposedCandidate*>& mask_candidates) {
+  if (candidate.occluding_mask_keys.empty()) {
+    return false;
+  }
+
+  return base::ranges::any_of(
+      mask_candidates.begin(), mask_candidates.end(),
+      [&candidate](const auto& iter) {
+        return candidate.occluding_mask_keys.contains(
+            OverlayProposedCandidate::ToProposeKey(*iter));
+      });
+}
+
+// Output of `ProcessOverlayTestResults()`.
+struct OverlayTestResults {
+  // True if any successfully test candidates is an underlays.
+  bool underlay_used = false;
+  // True if any test candidate was marked to be composited for UI correctness.
+  bool candidates_marked_for_compositing = false;
+};
+
+// Processes the `candidates` list by checking which overlay candidates can be
+// handled by DRM and based on that decide which candidates should be promoted
+// or composited to produce the most correct UI. Adjusts the `test_candidates`
+// lists accordingly by marking `overlay_handled`.
+OverlayTestResults ProcessOverlayTestResults(
+    std::vector<OverlayProposedCandidate>& test_candidates) {
+  std::vector<OverlayProposedCandidate*> failed_candidates_with_masks;
+  OverlayTestResults data;
+
+  for (auto& it : test_candidates) {
+    if (!it.candidate.overlay_handled &&
+        it.candidate.has_rounded_display_masks) {
+      failed_candidates_with_masks.push_back(&it);
+    }
+
+    if (it.candidate.overlay_handled && it.candidate.plane_z_order < 0) {
+      data.underlay_used = true;
+    }
+  }
+
+  bool has_promoting_overlays_without_masks = false;
+
+  // If some of the candidates with rounded-display masks fail to promote,
+  // composite other overlay(SingleOnTop) candidates that are occluded by these
+  // failed candidates with masks.
+  for (auto& it : test_candidates) {
+    if (it.strategy->GetUMAEnum() == OverlayStrategy::kSingleOnTop &&
+        !it.candidate.has_rounded_display_masks &&
+        it.candidate.overlay_handled) {
+      if (IsOccludedByMaskCandidates(it, failed_candidates_with_masks)) {
+        it.candidate.overlay_handled = false;
+        data.candidates_marked_for_compositing = true;
+      } else {
+        has_promoting_overlays_without_masks = true;
+      }
+    }
+  }
+
+  // If the only overlay(SingleOnTop) candidates that can be promoted are
+  // candidates with display masks, we can skip promoting them to overlays
+  // to save power.
+  if (!has_promoting_overlays_without_masks) {
+    for (auto& it : test_candidates) {
+      if (it.strategy->GetUMAEnum() == OverlayStrategy::kSingleOnTop) {
+        it.candidate.overlay_handled = false;
+        data.candidates_marked_for_compositing = true;
+      }
+    }
+  }
+
+  return data;
+}
+
 // Gets the minimum scaling amount used by either dimension for the src relative
 // to the dst.
 float GetMinScaleFactor(const OverlayCandidate& candidate) {
@@ -113,6 +237,25 @@
       src_rect, 1.0f / candidate->resource_size_in_pixels.width(),
       1.0f / candidate->resource_size_in_pixels.height());
 }
+
+void SyncOverlayCandidates(
+    std::vector<OverlayProposedCandidate>& proposed_candidates,
+    std::vector<OverlayCandidate>& candidates,
+    bool copy_from_proposed_candidates) {
+  auto cand_it = candidates.begin();
+  auto proposed_it = proposed_candidates.begin();
+  while (cand_it != candidates.end()) {
+    if (copy_from_proposed_candidates) {
+      cand_it->overlay_handled = proposed_it->candidate.overlay_handled;
+    } else {
+      proposed_it->candidate.overlay_handled = cand_it->overlay_handled;
+    }
+
+    cand_it++;
+    proposed_it++;
+  }
+}
+
 }  // namespace
 
 static void LogStrategyEnumUMA(OverlayStrategy strategy) {
@@ -517,7 +660,14 @@
                                          tracker_config_, display_area) >= 0 ||
           !prioritization_config_.damage_rate_threshold));
 
-    if (it->candidate.requires_overlay || passes_min_threshold) {
+    // Candidates that have rounded-display mask textures must be promoted
+    // even though they do not pass the minimum threshold.
+    // These candidates do not have active damage. (rounded-displays do not have
+    // changing corner radii with each frame!) But given the requirement that
+    // these mask textures must be on top of for UI, we need to promote these
+    // textures for correctness.
+    if (it->candidate.requires_overlay ||
+        it->candidate.has_rounded_display_masks || passes_min_threshold) {
       it->relative_power_gain = track_data.GetModeledPowerGain(
           frame_sequence_number_, tracker_config_, display_area);
       ++it;
@@ -541,14 +691,27 @@
   std::stable_sort(
       proposed_candidates->begin(), proposed_candidates->end(),
       [prio_config](const auto& a, const auto& b) {
-        // DRM/CDM HW overlay required:
-        // This comparison is for correctness over performance reasons. Some
-        // candidates must be an HW overlay to function. If both require an HW
-        // overlay we leave them in order so the topmost one gets the overlay.
+        // These following two comparisons are for correctness over performance
+        // reasons.
+        // - Candidates that are marked as `required_overlay` need be an HW
+        // overlay to function.
+        // - Candidates that have rounded_display masks need to be in overlay as
+        // they must be drawn on top of rest of UI.
+
+        // If both require a HW overlay we leave them in order so the topmost
+        // one gets the overlay.
         if (a.candidate.requires_overlay || b.candidate.requires_overlay) {
           return a.candidate.requires_overlay && !b.candidate.requires_overlay;
         }
 
+        // Candidate that require_overlays get more priority over the candidates
+        // that have textures for the rounded_display masks.
+        if (a.candidate.has_rounded_display_masks ||
+            b.candidate.has_rounded_display_masks) {
+          return a.candidate.has_rounded_display_masks &&
+                 !b.candidate.has_rounded_display_masks;
+        }
+
         // Opaque Power Metric:
         // |relative_power_gain| is computed in the tracker for each overlay
         // candidate and being proportional to power saved is directly
@@ -742,11 +905,49 @@
     return false;
   }
 
+  // After sorting in `SortProposedOverlayCandidates()`, all the candidates with
+  // display masks will be in the beginning of `sorted_candidates`.
+  ConstOverlayProposedCandidateIterator first_candidate_without_masks =
+      base::ranges::find_if(
+          sorted_candidates.begin(), sorted_candidates.end(),
+          [](const OverlayProposedCandidate& candidate) {
+            return !candidate.candidate.has_rounded_display_masks;
+          });
+
+  int candidates_with_masks_count =
+      std::distance(sorted_candidates.begin(), first_candidate_without_masks);
+  int candidates_without_masks_count =
+      sorted_candidates.size() - candidates_with_masks_count;
+
+  // If `sorted_candidates` only contains candidates with masks, we can skip
+  // promoting them to overlays.
+  if (candidates_without_masks_count == 0) {
+    UMA_HISTOGRAM_COUNTS_100(kNumOverlaysAttemptedHistogramName, 0);
+    UMA_HISTOGRAM_COUNTS_100(kNumOverlaysFailedHistogramName, 0);
+    return false;
+  }
+
+  // Request a combination to test without candidates with display masks. We
+  // request a combination that is `candidates_with_masks_count` less so
+  // that we can safely(have enough planes to test combination) add candidates
+  // with masks to the test combination.
+  int max_overlays_without_mask_candidates =
+      std::max(0, max_overlays_considered_ - candidates_with_masks_count);
+
   OverlayCombinationToTest result =
       overlay_combination_cache_.GetOverlayCombinationToTest(
-          sorted_candidates, max_overlays_considered_);
+          base::make_span(first_candidate_without_masks,
+                          sorted_candidates.end()),
+          max_overlays_without_mask_candidates);
+
   std::vector<OverlayProposedCandidate> test_candidates =
       result.candidates_to_test;
+
+  ConstOverlayProposedCandidateIterator begin_rounded_corner_candidate =
+      MaybeAppendOccludingMaskCandidates(sorted_candidates.begin(),
+                                         first_candidate_without_masks,
+                                         test_candidates);
+
   UMA_HISTOGRAM_BOOLEAN(
       "Compositing.Display.OverlayProcessorUsingStrategy."
       "CandidateCombinationPreviouslySucceeded",
@@ -760,9 +961,15 @@
   for (auto it = test_candidates.begin(); it != test_candidates.end(); ++it) {
     switch (it->strategy->GetUMAEnum()) {
       case OverlayStrategy::kSingleOnTop:
-        // Ordering of on top candidates doesn't matter (they can't overlap), so
-        // they can all have z = 1.
-        it->candidate.plane_z_order = 1;
+        // SingleOnTop candidates without masks do not overlap with each other,
+        // so the ordering does not matter and they have plane_z_order=1,
+        // letting DRM decide how it wants to arrange these candidates.
+        // Whereas SingleOnTop candidates with masks can overlap with other
+        // SingleOnTop candidates and since they are drawn on top on other
+        // SingleOnTop candidates, without overlapping each other, they have
+        // plane_z_order=2.
+        it->candidate.plane_z_order =
+            it->candidate.has_rounded_display_masks ? 2 : 1;
         break;
       case OverlayStrategy::kUnderlay:
         testing_underlay = true;
@@ -793,22 +1000,28 @@
   }
   const int num_overlays_attempted = candidates.size();
 
-  bool underlay_used = false;
-  auto cand_it = candidates.begin();
-  auto test_it = test_candidates.begin();
-  while (cand_it != candidates.end()) {
-    // Update the test candidates so we can use EraseIf below, and so we can
-    // tell the OverlayCombinationCache which ones succeeded/failed.
-    test_it->candidate.overlay_handled = cand_it->overlay_handled;
-    if (cand_it->overlay_handled && cand_it->plane_z_order < 0) {
-      underlay_used = true;
-    }
-    cand_it++;
-    test_it++;
-  }
-  overlay_combination_cache_.DeclarePromotedCandidates(test_candidates);
+  // Update the test candidates so we can process the result, use EraseIf below
+  // and tell the OverlayCombinationCache which ones succeeded/failed.
+  SyncOverlayCandidates(test_candidates, candidates,
+                        /*copy_from_proposed_candidates=*/false);
 
-  // Remove failed candidates
+  // Decide which test_candidates to commit that will results in correct UI
+  // based on result of testing the combination.
+  OverlayTestResults output = ProcessOverlayTestResults(test_candidates);
+
+  // Only declare test candidates that do not have candidates with rounded
+  // display masks.
+  overlay_combination_cache_.DeclarePromotedCandidates(
+      base::make_span(test_candidates.begin(), begin_rounded_corner_candidate));
+
+  // Update `candidates` if it was decided to composite some test_candidates in
+  // `ProcessOverlayTestResults()`.
+  if (output.candidates_marked_for_compositing) {
+    SyncOverlayCandidates(test_candidates, candidates,
+                          /*copy_from_proposed_candidates=*/true);
+  }
+
+  // Remove failed candidates.
   base::EraseIf(candidates, [](auto& cand) { return !cand.overlay_handled; });
   base::EraseIf(test_candidates, [](auto& proposed) -> bool {
     return !proposed.candidate.overlay_handled;
@@ -825,7 +1038,7 @@
     return false;
   }
 
-  if (underlay_used && primary_plane) {
+  if (output.underlay_used && primary_plane) {
     // Using underlays means the primary plane needs blending enabled.
     primary_plane->enable_blending = true;
   }
diff --git a/components/viz/service/display/overlay_proposed_candidate.cc b/components/viz/service/display/overlay_proposed_candidate.cc
index 484ae8a..2857cfc 100644
--- a/components/viz/service/display/overlay_proposed_candidate.cc
+++ b/components/viz/service/display/overlay_proposed_candidate.cc
@@ -64,6 +64,19 @@
   return mask_rects;
 }
 
+OverlayProposedCandidate::OverlayProposedCandidate(
+    QuadList::Iterator it,
+    OverlayCandidate overlay_candidate,
+    OverlayProcessorStrategy* overlay_strategy)
+    : quad_iter(it), candidate(overlay_candidate), strategy(overlay_strategy) {}
+
+OverlayProposedCandidate::OverlayProposedCandidate(
+    const OverlayProposedCandidate&) = default;
+OverlayProposedCandidate& OverlayProposedCandidate::operator=(
+    const OverlayProposedCandidate&) = default;
+
+OverlayProposedCandidate::~OverlayProposedCandidate() = default;
+
 ProposedCandidateKey OverlayProposedCandidate::ToProposeKey(
     const OverlayProposedCandidate& proposed) {
   return {proposed.candidate.tracking_id, proposed.strategy->GetUMAEnum()};
diff --git a/components/viz/service/display/overlay_proposed_candidate.h b/components/viz/service/display/overlay_proposed_candidate.h
index f1c6532..4c2547df 100644
--- a/components/viz/service/display/overlay_proposed_candidate.h
+++ b/components/viz/service/display/overlay_proposed_candidate.h
@@ -7,6 +7,7 @@
 
 #include <array>
 
+#include "base/containers/flat_set.h"
 #include "components/viz/common/display/overlay_strategy.h"
 #include "components/viz/common/quads/quad_list.h"
 #include "components/viz/common/quads/texture_draw_quad.h"
@@ -26,6 +27,14 @@
     return (tracking_id == other.tracking_id &&
             strategy_id == other.strategy_id);
   }
+
+  bool operator<(const ProposedCandidateKey& other) const {
+    if (tracking_id != other.tracking_id) {
+      return tracking_id < other.tracking_id;
+    }
+
+    return static_cast<int>(strategy_id) < static_cast<int>(other.strategy_id);
+  }
 };
 
 struct ProposedCandidateKeyHasher {
@@ -38,6 +47,15 @@
 // using a specific `OverlayProcessorStrategy`.
 class VIZ_SERVICE_EXPORT OverlayProposedCandidate {
  public:
+  OverlayProposedCandidate(QuadList::Iterator it,
+                           OverlayCandidate overlay_candidate,
+                           OverlayProcessorStrategy* overlay_strategy);
+
+  OverlayProposedCandidate(const OverlayProposedCandidate&);
+  OverlayProposedCandidate& operator=(const OverlayProposedCandidate&);
+
+  ~OverlayProposedCandidate();
+
   // Returns the bounds of rounded display masks in target space that are
   // associated with the `proposed_candidate`.
   static std::array<
@@ -46,13 +64,6 @@
   GetRoundedDisplayMasksBounds(
       const OverlayProposedCandidate& proposed_candidate);
 
-  OverlayProposedCandidate(QuadList::Iterator it,
-                           OverlayCandidate overlay_candidate,
-                           OverlayProcessorStrategy* overlay_strategy)
-      : quad_iter(it),
-        candidate(overlay_candidate),
-        strategy(overlay_strategy) {}
-
   static ProposedCandidateKey ToProposeKey(
       const OverlayProposedCandidate& proposed);
 
@@ -63,6 +74,9 @@
 
   // heuristic sort element
   int relative_power_gain = 0;
+
+  // Keys of candidates with rounded display masks that occlude `this`.
+  base::flat_set<ProposedCandidateKey> occluding_mask_keys;
 };
 
 }  // namespace viz
diff --git a/components/viz/service/display/overlay_strategy_single_on_top.cc b/components/viz/service/display/overlay_strategy_single_on_top.cc
index cf3c11a..b9eaedc9 100644
--- a/components/viz/service/display/overlay_strategy_single_on_top.cc
+++ b/components/viz/service/display/overlay_strategy_single_on_top.cc
@@ -20,21 +20,27 @@
 using OverlayProposedCandidateIndex =
     std::vector<OverlayProposedCandidate>::size_type;
 
-// Returns true if `rounded_corner_candidate` occludes any SingleOnTop
-// candidates in the list between `single_on_top_candidates_start` (inclusively)
-// and `single_on_top_candidates_end` (exclusively).
-bool OccludesAnyOtherSingleOnTopOverlayCandidate(
-    const OverlayProposedCandidate& rounded_corner_candidate,
-    const std::vector<OverlayProposedCandidate>* candidates,
+// Calculates and caches for the candidates in the list between
+// `single_on_top_candidates_start` (inclusively) and
+// `single_on_top_candidates_end` (exclusively) if they are occluded by
+// `candidate_with_display_masks`.
+//
+// Returns true if `candidate_with_display_masks` does occlude any other
+// candidate.
+bool CalculateOcclusionByRoundedDisplayMaskCandidate(
+    OverlayProposedCandidate& candidate_with_display_masks,
+    std::vector<OverlayProposedCandidate>* candidates,
     OverlayProposedCandidateIndex single_on_top_candidates_begin,
     OverlayProposedCandidateIndex single_on_top_candidates_end) {
-  DCHECK(rounded_corner_candidate.candidate.has_rounded_display_masks);
+  DCHECK(candidate_with_display_masks.candidate.has_rounded_display_masks);
 
   auto mask_bounds = OverlayProposedCandidate::GetRoundedDisplayMasksBounds(
-      rounded_corner_candidate);
+      candidate_with_display_masks);
+
+  bool intersects_candidate = false;
   for (OverlayProposedCandidateIndex i = single_on_top_candidates_begin;
        i < single_on_top_candidates_end; i++) {
-    const auto& overlap_candidate = candidates->at(i);
+    auto& overlap_candidate = candidates->at(i);
 
     // The rects are rounded as they're snapped by the compositor to pixel
     // unless it is AA'ed, in which case, it won't be overlaid.
@@ -47,12 +53,18 @@
     // masks.
     for (const gfx::Rect& mask_bound : mask_bounds) {
       if (mask_bound.Intersects(overlap_rect)) {
-        return true;
+        intersects_candidate = true;
+
+        // Cache the occluding `candidate_with_display_masks` for the
+        // overlap_candidate.
+        overlap_candidate.occluding_mask_keys.insert(
+            OverlayProposedCandidate::ToProposeKey(
+                candidate_with_display_masks));
       }
     }
   }
 
-  return false;
+  return intersects_candidate;
 }
 
 }  // namespace
@@ -96,6 +108,10 @@
     if (candidate_factory.FromDrawQuad(*quads_with_masks_iter, candidate) ==
             OverlayCandidate::CandidateStatus::kSuccess &&
         !candidate.has_mask_filter && candidate.has_rounded_display_masks) {
+      // Candidates with rounded-display masks should not overlap any other quad
+      // with rounded-display masks.
+      DCHECK(!candidate_factory.IsOccluded(candidate, quad_list->begin(),
+                                           quads_with_masks_iter));
       candidates_with_masks.emplace_back(quads_with_masks_iter, candidate,
                                          this);
       quads_with_masks_iter++;
@@ -129,7 +145,9 @@
   // To save power we can skip promoting candidates with rounded display mask
   // rects if they do not occlude any other SingleOnTop candidate.
   for (auto& mask_candidate : candidates_with_masks) {
-    if (OccludesAnyOtherSingleOnTopOverlayCandidate(
+    // We mark all the SingleOnTop candidates that are occluded by any mask
+    // rounded-display masks to be later used in overlay processing.
+    if (CalculateOcclusionByRoundedDisplayMaskCandidate(
             mask_candidate, candidates, single_on_top_candidates_begin,
             candidates->size())) {
       candidates->push_back(mask_candidate);
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc
index 85d11ae..47fb0ac 100644
--- a/components/viz/service/display/overlay_unittest.cc
+++ b/components/viz/service/display/overlay_unittest.cc
@@ -4,10 +4,12 @@
 
 #include <stddef.h>
 
+#include <string>
 #include <unordered_map>
 #include <utility>
 #include <vector>
 
+#include "base/containers/cxx20_erase_vector.h"
 #include "base/containers/flat_map.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
@@ -51,6 +53,7 @@
 #include "gpu/config/gpu_finch_features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -287,6 +290,12 @@
     responses_.clear();
   }
 
+  // Overrides the maximum number of candidates that the OverlayProcessor can
+  // consider each frame.
+  void SetMaximumOverlaysConsidered(int overlays_considered) {
+    max_overlays_considered_ = overlays_considered;
+  }
+
  private:
   std::vector<gfx::Rect> expected_rects_;
   std::vector<bool> responses_;
@@ -308,19 +317,10 @@
   }
 };
 
-class MultiUnderlayProcessor : public MultiOverlayProcessorBase {
+class SizeSortedMultiSingleOnTopProcessor : public MultiOverlayProcessorBase {
  public:
-  MultiUnderlayProcessor() {
-    strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(this));
-  }
-};
-
-class SizeSortedMultiOverlayProcessor : public MultiOverlayProcessorBase {
- public:
-  SizeSortedMultiOverlayProcessor() {
-    strategies_.push_back(std::make_unique<OverlayStrategyFullscreen>(this));
+  SizeSortedMultiSingleOnTopProcessor() {
     strategies_.push_back(std::make_unique<OverlayStrategySingleOnTop>(this));
-    strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(this));
   }
 
   // Sort candidates only by their display_rect area.
@@ -336,6 +336,112 @@
                 return a.relative_power_gain > b.relative_power_gain;
               });
   }
+
+  void CheckOverlaySupportImpl(const PrimaryPlane* primary_plane,
+                               OverlayCandidateList* surfaces) override {
+    for (auto& candidate : *surfaces) {
+      candidate.overlay_handled = true;
+    }
+  }
+};
+
+class MultiUnderlayProcessor : public MultiOverlayProcessorBase {
+ public:
+  MultiUnderlayProcessor() {
+    strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(this));
+  }
+};
+
+class SizeSortedMultiOverlayProcessorBase : public MultiOverlayProcessorBase {
+ public:
+  // Sort candidates only by their display_rect area.
+  void SortProposedOverlayCandidates(
+      std::vector<OverlayProposedCandidate>* proposed_candidates) override {
+    // We want the power gains to be assigned for the OverlayCombinationCache.
+    for (auto& proposed_candidate : *proposed_candidates) {
+      proposed_candidate.relative_power_gain =
+          proposed_candidate.candidate.display_rect.size().GetArea();
+    }
+    std::sort(proposed_candidates->begin(), proposed_candidates->end(),
+              [](const auto& a, const auto& b) {
+                return a.relative_power_gain > b.relative_power_gain;
+              });
+  }
+};
+
+class SizeSortedMultiOverlayProcessor
+    : public SizeSortedMultiOverlayProcessorBase {
+ public:
+  SizeSortedMultiOverlayProcessor() {
+    strategies_.push_back(std::make_unique<OverlayStrategyFullscreen>(this));
+    strategies_.push_back(std::make_unique<OverlayStrategySingleOnTop>(this));
+  }
+};
+
+class SizeSortedMultiUnderlayProcessor
+    : public SizeSortedMultiOverlayProcessorBase {
+ public:
+  SizeSortedMultiUnderlayProcessor() {
+    strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(this));
+  }
+};
+
+class TypeAndSizeSortedMultiOverlayProcessor
+    : public MultiOverlayProcessorBase {
+ public:
+  TypeAndSizeSortedMultiOverlayProcessor() {
+    strategies_.push_back(std::make_unique<OverlayStrategySingleOnTop>(this));
+  }
+
+  void SortProposedOverlayCandidates(
+      std::vector<OverlayProposedCandidate>* proposed_candidates) override {
+    // We want the power gains to be assigned for the OverlayCombinationCache.
+    for (auto& proposed_candidate : *proposed_candidates) {
+      proposed_candidate.relative_power_gain =
+          proposed_candidate.candidate.display_rect.size().GetArea();
+    }
+    std::sort(
+        proposed_candidates->begin(), proposed_candidates->end(),
+        [](const auto& a, const auto& b) {
+          if (a.candidate.requires_overlay || b.candidate.requires_overlay) {
+            return a.candidate.requires_overlay &&
+                   !b.candidate.requires_overlay;
+          }
+
+          if (a.candidate.has_rounded_display_masks ||
+              b.candidate.has_rounded_display_masks) {
+            return a.candidate.has_rounded_display_masks &&
+                   !b.candidate.has_rounded_display_masks;
+          }
+
+          return a.relative_power_gain > b.relative_power_gain;
+        });
+  }
+};
+
+// This processor only allows only candidates with rounded-display masks after
+// sorting them.
+class AllowCandidateWithMasksSortedMultiOverlayProcessor
+    : public MultiOverlayProcessorBase {
+ public:
+  AllowCandidateWithMasksSortedMultiOverlayProcessor() {
+    strategies_.push_back(std::make_unique<OverlayStrategySingleOnTop>(this));
+  }
+
+  void SortProposedOverlayCandidates(
+      std::vector<OverlayProposedCandidate>* proposed_candidates) override {
+    // After sort we should only be left with candidates with rounded-display
+    // masks.
+    base::EraseIf(*proposed_candidates, [](OverlayProposedCandidate& cand) {
+      return !cand.candidate.has_rounded_display_masks;
+    });
+
+    // We want the power gains to be assigned for the OverlayCombinationCache.
+    for (auto& proposed_candidate : *proposed_candidates) {
+      proposed_candidate.relative_power_gain =
+          proposed_candidate.candidate.display_rect.size().GetArea();
+    }
+  }
 };
 
 class SingleOnTopOverlayProcessor : public DefaultOverlayProcessor {
@@ -825,8 +931,17 @@
 using MultiUnderlayTest = UseMultipleOverlaysTest<MultiUnderlayProcessor>;
 using MultiSingleOnTopOverlayTest =
     UseMultipleOverlaysTest<MultiSingleOnTopProcessor>;
+using SizeSortedMultiSingeOnTopOverlayTest =
+    UseMultipleOverlaysTest<SizeSortedMultiSingleOnTopProcessor>;
+
+using SizeSortedMultiUnderlayOverlayTest =
+    UseMultipleOverlaysTest<SizeSortedMultiUnderlayProcessor>;
 using SizeSortedMultiOverlayTest =
     UseMultipleOverlaysTest<SizeSortedMultiOverlayProcessor>;
+using TypeAndSizeSortedMultiOverlayTest =
+    UseMultipleOverlaysTest<TypeAndSizeSortedMultiOverlayProcessor>;
+using AllowCandidateWithMasksSortedMultiOverlayTest =
+    UseMultipleOverlaysTest<AllowCandidateWithMasksSortedMultiOverlayProcessor>;
 
 TEST(OverlayTest, OverlaysProcessorHasStrategy) {
   auto overlay_processor = std::make_unique<TestOverlayProcessor>();
@@ -1255,6 +1370,39 @@
       &damage_rect_, &content_bounds_));
 }
 
+TEST_F(DeathMultiSingleOnTopOverlayTest,
+       RoundedDisplayMaskCandidatesOverlapsEachOther) {
+  auto pass = CreateRenderPass();
+
+  // Add a quad with rounded-display masks.
+  CreateQuadWithRoundedDisplayMasksAt(
+      resource_provider_.get(), child_resource_provider_.get(),
+      child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+      /*is_overlay_candidate=*/true, kOverlayTopLeftRect,
+      RoundedDisplayMasksInfo::CreateRoundedDisplayMasksInfo(10, 0));
+
+  // Add a quad with rounded-display masks.
+  CreateFullscreenQuadWithRoundedDisplayMasks(
+      resource_provider_.get(), child_resource_provider_.get(),
+      child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+      /*is_overlay_candidate=*/true,
+      RoundedDisplayMasksInfo::CreateRoundedDisplayMasksInfo(10, 0));
+
+  // Check for potential candidates.
+  OverlayCandidateList candidate_list;
+  OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+  OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+  AggregatedRenderPassList pass_list;
+  pass_list.push_back(std::move(pass));
+  SurfaceDamageRectList surface_damage_rect_list;
+
+  EXPECT_DCHECK_DEATH(overlay_processor_->ProcessForOverlays(
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_backdrop_filters,
+      std::move(surface_damage_rect_list), nullptr, &candidate_list,
+      &damage_rect_, &content_bounds_));
+}
+
 TEST_F(MultiSingleOnTopOverlayTest,
        PromoteRoundedDisplayMaskCandidateIfOccludeOtherCandidates) {
   // Given different rect sizes, the candidate will be out of draw order once
@@ -1269,7 +1417,6 @@
       child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
       /*is_overlay_candidate=*/true, kCandidateRect1,
       RoundedDisplayMasksInfo::CreateRoundedDisplayMasksInfo(0, 10));
-  overlay_processor_->AddExpectedRect(kCandidateRect1, true);
 
   constexpr gfx::Rect kCandidateRect2 = {0, 0, 64, 64};
 
@@ -1279,15 +1426,20 @@
                         child_resource_provider_.get(), child_provider_.get(),
                         pass->shared_quad_state_list.back(), pass.get(),
                         kCandidateRect2);
-  overlay_processor_->AddExpectedRect(kCandidateRect2, true);
 
   // This candidate occludes quad with rounded-display masks.
   CreateCandidateQuadAt(resource_provider_.get(),
                         child_resource_provider_.get(), child_provider_.get(),
                         pass->shared_quad_state_list.back(), pass.get(),
                         kOverlayTopRightRect);
+
+  overlay_processor_->AddExpectedRect(kCandidateRect2, true);
   overlay_processor_->AddExpectedRect(kOverlayTopRightRect, true);
 
+  // Candidates with masks are appended at the end of the surfaces in
+  // `CheckOverlaySupportImpl()` in their respective draw order.
+  overlay_processor_->AddExpectedRect(kCandidateRect1, true);
+
   // Check for potential candidates.
   OverlayCandidateList candidate_list;
   OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
@@ -1380,8 +1532,6 @@
       child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
       /*is_overlay_candidate=*/true, kCandidateWithMaskRect2,
       RoundedDisplayMasksInfo::CreateRoundedDisplayMasksInfo(10, 10));
-  overlay_processor_->AddExpectedRect(kCandidateWithMaskRect2,
-                                      /*response=*/true);
 
   constexpr gfx::Rect kCandidateRect1 = gfx::Rect(10, 0, 50, 50);
 
@@ -1391,7 +1541,6 @@
                         child_resource_provider_.get(), child_provider_.get(),
                         pass->shared_quad_state_list.back(), pass.get(),
                         kCandidateRect1);
-  overlay_processor_->AddExpectedRect(kCandidateRect1, /*response=*/true);
 
   constexpr gfx::Rect kCandidateRect2 = gfx::Rect(0, 90, 50, 50);
 
@@ -1399,8 +1548,16 @@
                         child_resource_provider_.get(), child_provider_.get(),
                         pass->shared_quad_state_list.back(), pass.get(),
                         kCandidateRect2);
+
+  overlay_processor_->AddExpectedRect(kCandidateRect1, /*response=*/true);
+
   overlay_processor_->AddExpectedRect(kCandidateRect2, /*response=*/true);
 
+  // Candidates with masks are appended at the end of the surfaces in
+  // `CheckOverlaySupportImpl()` in their respective draw order.
+  overlay_processor_->AddExpectedRect(kCandidateWithMaskRect2,
+                                      /*response=*/true);
+
   // Check for potential candidates.
   OverlayCandidateList candidate_list;
   OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
@@ -5979,7 +6136,383 @@
   EXPECT_EQ(damage_rect_, kBottomTwo);
 }
 
-TEST_F(SizeSortedMultiOverlayTest, UnderlaysAreSorted) {
+TEST_F(MultiOverlayTest, RoundedDisplayMaskCandidateFailsToPromote) {
+  overlay_processor_->SetMaximumOverlaysConsidered(6);
+
+  const gfx::Rect kRoundedDisplayMaskLeftRect(0, 0, 32, 100);
+  const gfx::Rect kRoundedDisplayMaskRightRect(224, 0, 32, 100);
+  const gfx::Rect kNormalLeft(kOverlayTopLeftRect);
+  const gfx::Rect kNormalRight(kOverlayTopRightRect);
+
+  auto pass = CreateRenderPass();
+  SurfaceDamageRectList surface_damage_rect_list;
+  const auto kRoundedDisplayMaskInfo =
+      RoundedDisplayMasksInfo::CreateRoundedDisplayMasksInfo(16, 16);
+
+  // Create a candidate with rounded display masks in top left.
+  CreateQuadWithRoundedDisplayMasksAt(
+      resource_provider_.get(), child_resource_provider_.get(),
+      child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+      /*is_overlay_candidate=*/true, kRoundedDisplayMaskLeftRect,
+      kRoundedDisplayMaskInfo);
+
+  // Create a candidate with rounded display masks in top right.
+  CreateQuadWithRoundedDisplayMasksAt(
+      resource_provider_.get(), child_resource_provider_.get(),
+      child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+      /*is_overlay_candidate=*/true, kRoundedDisplayMaskRightRect,
+      kRoundedDisplayMaskInfo);
+
+  // This candidate is occluded by top left candidate with rounded display
+  // masks.
+  CreateCandidateQuadAt(resource_provider_.get(),
+                        child_resource_provider_.get(), child_provider_.get(),
+                        pass->shared_quad_state_list.back(), pass.get(),
+                        kNormalLeft);
+
+  // This candidate is occluded by top right candidate with rounded display
+  // masks.
+  CreateCandidateQuadAt(resource_provider_.get(),
+                        child_resource_provider_.get(), child_provider_.get(),
+                        pass->shared_quad_state_list.back(), pass.get(),
+                        kNormalRight);
+
+  // Create a quad that will the next quad to become an underlay.
+  auto* sqs = pass->CreateAndAppendSharedQuadState();
+  CreateFullscreenOpaqueQuad(resource_provider_.get(), sqs, pass.get());
+
+  CreateFullscreenCandidateQuad(resource_provider_.get(),
+                                child_resource_provider_.get(),
+                                child_provider_.get(), sqs, pass.get());
+
+  OverlayCandidateList candidate_list;
+  OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+  OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+  AggregatedRenderPassList pass_list;
+  pass_list.push_back(std::move(pass));
+
+  overlay_processor_->AddExpectedRect(kNormalLeft, true);
+  overlay_processor_->AddExpectedRect(kNormalRight, true);
+  overlay_processor_->AddExpectedRect(kOverlayRect, true);
+
+  // Candidates with masks are appended at the end of the surfaces in
+  // `CheckOverlaySupportImpl()`
+  overlay_processor_->AddExpectedRect(kRoundedDisplayMaskLeftRect, true);
+  overlay_processor_->AddExpectedRect(kRoundedDisplayMaskRightRect, false);
+
+  overlay_processor_->ProcessForOverlays(
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_backdrop_filters,
+      std::move(surface_damage_rect_list), nullptr, &candidate_list,
+      &damage_rect_, &content_bounds_);
+
+  // Since the mask candidate in top right will fail to promote, we will also
+  // composite the SingleOnTop candidate occlude by this failing candidate. The
+  // underlay candidate will promoted normally since it is not effected by the
+  // failing mask candidate (even though it is occluded).
+  ASSERT_EQ(candidate_list.size(), 3u);
+
+  EXPECT_EQ(gfx::ToRoundedRect(candidate_list[0].display_rect), kNormalLeft);
+  EXPECT_EQ(candidate_list[0].plane_z_order, 1);
+  EXPECT_EQ(gfx::ToRoundedRect(candidate_list[1].display_rect), kOverlayRect);
+  EXPECT_EQ(candidate_list[1].plane_z_order, -1);
+
+  // Candidates with masks are appended at the end of the `candidate_list` in
+  // draw order.
+  EXPECT_EQ(gfx::ToRoundedRect(candidate_list[2].display_rect),
+            kRoundedDisplayMaskLeftRect);
+  EXPECT_EQ(candidate_list[2].plane_z_order, 2);
+}
+
+TEST_F(MultiOverlayTest,
+       DontPromoteCandidatesWithMasksIfAreOnlyOverlayCandidatesNotRejected) {
+  overlay_processor_->SetMaximumOverlaysConsidered(6);
+
+  const gfx::Rect kRoundedDisplayMaskLeftRect(0, 0, 32, 100);
+  const gfx::Rect kRoundedDisplayMaskRightRect(224, 0, 32, 100);
+  const gfx::Rect kNormalLeft(kOverlayTopLeftRect);
+  const gfx::Rect kNormalRight(kOverlayTopRightRect);
+
+  auto pass = CreateRenderPass();
+  SurfaceDamageRectList surface_damage_rect_list;
+  const auto kRoundedDisplayMaskInfo =
+      RoundedDisplayMasksInfo::CreateRoundedDisplayMasksInfo(16, 16);
+
+  // Create a candidate with rounded display masks in top left.
+  CreateQuadWithRoundedDisplayMasksAt(
+      resource_provider_.get(), child_resource_provider_.get(),
+      child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+      /*is_overlay_candidate=*/true, kRoundedDisplayMaskLeftRect,
+      kRoundedDisplayMaskInfo);
+
+  // Create a candidate with rounded display masks in top right.
+  CreateQuadWithRoundedDisplayMasksAt(
+      resource_provider_.get(), child_resource_provider_.get(),
+      child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+      /*is_overlay_candidate=*/true, kRoundedDisplayMaskRightRect,
+      kRoundedDisplayMaskInfo);
+
+  // This candidate is occluded by top left candidate with rounded display
+  // masks.
+  CreateCandidateQuadAt(resource_provider_.get(),
+                        child_resource_provider_.get(), child_provider_.get(),
+                        pass->shared_quad_state_list.back(), pass.get(),
+                        kNormalLeft);
+
+  // This candidate is occluded by top right candidate with rounded display
+  // masks.
+  CreateCandidateQuadAt(resource_provider_.get(),
+                        child_resource_provider_.get(), child_provider_.get(),
+                        pass->shared_quad_state_list.back(), pass.get(),
+                        kNormalRight);
+
+  // Create a quad that will the next quad to become an underlay.
+  auto* sqs = pass->CreateAndAppendSharedQuadState();
+  CreateFullscreenOpaqueQuad(resource_provider_.get(), sqs, pass.get());
+
+  CreateFullscreenCandidateQuad(resource_provider_.get(),
+                                child_resource_provider_.get(),
+                                child_provider_.get(), sqs, pass.get());
+
+  OverlayCandidateList candidate_list;
+  OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+  OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+  AggregatedRenderPassList pass_list;
+  pass_list.push_back(std::move(pass));
+
+  overlay_processor_->AddExpectedRect(kNormalLeft, false);
+  overlay_processor_->AddExpectedRect(kNormalRight, false);
+  overlay_processor_->AddExpectedRect(kOverlayRect, true);
+
+  // Candidates with masks are appended at the end of the surfaces in
+  // `CheckOverlaySupportImpl()`
+  overlay_processor_->AddExpectedRect(kRoundedDisplayMaskLeftRect, true);
+  overlay_processor_->AddExpectedRect(kRoundedDisplayMaskRightRect, true);
+
+  overlay_processor_->ProcessForOverlays(
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_backdrop_filters,
+      std::move(surface_damage_rect_list), nullptr, &candidate_list,
+      &damage_rect_, &content_bounds_);
+
+  // Since both the overlay (SingleOnTop) candidates without masks failed to
+  // promote, we end up composting both candidates with masks as well. Only the
+  // underlay candidate is promoted.
+  ASSERT_EQ(candidate_list.size(), 1u);
+
+  EXPECT_EQ(gfx::ToRoundedRect(candidate_list[0].display_rect), kOverlayRect);
+  EXPECT_EQ(candidate_list[0].plane_z_order, -1);
+}
+
+// Since AllowCandidateWithMasksSortedMultiOverlayProcessor will only allow
+// candidates with masks after sorting in `SortProposedOverlayCandidates()`.
+TEST_F(AllowCandidateWithMasksSortedMultiOverlayTest,
+       DontPromoteCandidatesWithMasksIfAreOnlySingleOnTopCandidates) {
+  auto pass = CreateRenderPass();
+
+  // Add a quad with rounded-display masks.
+  CreateQuadWithRoundedDisplayMasksAt(
+      resource_provider_.get(), child_resource_provider_.get(),
+      child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+      /*is_overlay_candidate=*/true, kOverlayTopLeftRect,
+      RoundedDisplayMasksInfo::CreateRoundedDisplayMasksInfo(10, 0));
+
+  // Add a quad with rounded-display masks.
+  CreateQuadWithRoundedDisplayMasksAt(
+      resource_provider_.get(), child_resource_provider_.get(),
+      child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+      /*is_overlay_candidate=*/true, kOverlayTopRightRect,
+      RoundedDisplayMasksInfo::CreateRoundedDisplayMasksInfo(10, 0));
+
+  CreateFullscreenCandidateQuad(
+      resource_provider_.get(), child_resource_provider_.get(),
+      child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
+
+  // Check for potential candidates.
+  OverlayCandidateList candidate_list;
+  OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+  OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+  AggregatedRenderPassList pass_list;
+  AggregatedRenderPass* main_pass = pass.get();
+  pass_list.push_back(std::move(pass));
+  SurfaceDamageRectList surface_damage_rect_list;
+
+  overlay_processor_->ProcessForOverlays(
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_backdrop_filters,
+      std::move(surface_damage_rect_list), nullptr, &candidate_list,
+      &damage_rect_, &content_bounds_);
+
+  // None of the candidates will be promoted.
+  // Since AllowCandidateWithMasksSortedMultiOverlayProcessor will only allow
+  // candidates with rounded-display masks after sorting(i.e only candidates to
+  // pass sorting hubristic), we can skip promoting these candidates.
+  ASSERT_EQ(0U, candidate_list.size());
+  EXPECT_EQ(3U, main_pass->quad_list.size());
+}
+
+TEST_F(TypeAndSizeSortedMultiOverlayTest,
+       PrioritizationWithRoundedDisplayMasks) {
+  enum OverlayCandidateType { kNormal, kHasRoundedDisplayMasks };
+
+  constexpr gfx::Rect kRoundedDisplayMaskRectSmallest(0, 0, 32, 32);
+  constexpr gfx::Rect kRoundedDisplayMaskRectSmall(64, 0, 64, 64);
+  constexpr gfx::Rect kNormalBiggest(128, 0, 256, 256);
+  constexpr gfx::Rect kNormalBig(0, 0, 128, 128);
+  constexpr gfx::Rect kNormalSmallest(128, 0, 32, 32);
+  // Intersects with both mask rects.
+  constexpr gfx::Rect kNormalSmall(128, 64, 64, 64);
+
+  // The draw order of these candidates is scrambled, so we can verify that the
+  // plane_z_orders are are based on draw quad order.
+  constexpr std::pair<gfx::Rect, OverlayCandidateType> kCandidatesInfo[]{
+      {kRoundedDisplayMaskRectSmall,
+       OverlayCandidateType::kHasRoundedDisplayMasks},
+      {kRoundedDisplayMaskRectSmallest,
+       OverlayCandidateType::kHasRoundedDisplayMasks},
+      {kNormalBiggest, OverlayCandidateType::kNormal},
+      {kNormalSmallest, OverlayCandidateType::kNormal},
+      {kNormalBig, OverlayCandidateType::kNormal},
+      {kNormalSmall, OverlayCandidateType::kNormal}};
+
+  constexpr gfx::Rect kAllCands(0, 0, 128, 128);
+  const auto kRoundedDisplayMaskInfo =
+      RoundedDisplayMasksInfo::CreateRoundedDisplayMasksInfo(16, 16);
+
+  damage_rect_ = kAllCands;
+  auto pass = CreateRenderPass();
+
+  for (auto info : kCandidatesInfo) {
+    switch (info.second) {
+      case kNormal:
+        CreateCandidateQuadAt(
+            resource_provider_.get(), child_resource_provider_.get(),
+            child_provider_.get(), pass->shared_quad_state_list.back(),
+            pass.get(), info.first);
+        break;
+      case kHasRoundedDisplayMasks:
+        CreateQuadWithRoundedDisplayMasksAt(
+            resource_provider_.get(), child_resource_provider_.get(),
+            child_provider_.get(), pass->shared_quad_state_list.back(),
+            pass.get(),
+            /*is_overlay_candidate=*/true, info.first, kRoundedDisplayMaskInfo);
+        break;
+    }
+  }
+
+  {
+    // Add something behind them.
+    auto* sqs = pass->CreateAndAppendSharedQuadState();
+    CreateFullscreenOpaqueQuad(resource_provider_.get(), sqs, pass.get());
+  }
+
+  overlay_processor_->AddExpectedRect(kNormalBiggest, true);
+  overlay_processor_->AddExpectedRect(kNormalBig, true);
+
+  // Candidates with masks are appended at the end of the surfaces in
+  // `CheckOverlaySupportImpl()`
+  overlay_processor_->AddExpectedRect(kRoundedDisplayMaskRectSmall, true);
+  overlay_processor_->AddExpectedRect(kRoundedDisplayMaskRectSmallest, true);
+
+  OverlayCandidateList candidate_list;
+  OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+  OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+  SurfaceDamageRectList surface_damage_rect_list;
+  AggregatedRenderPassList pass_list;
+  pass_list.push_back(std::move(pass));
+
+  overlay_processor_->ProcessForOverlays(
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_backdrop_filters,
+      std::move(surface_damage_rect_list), nullptr, &candidate_list,
+      &damage_rect_, &content_bounds_);
+
+  ASSERT_EQ(candidate_list.size(), 4u);
+
+  // We expect the two rounded masks to get promoted regardless of their surface
+  // area. Candidates with rounded masks are followed by candidate with largest
+  // surface area.
+  EXPECT_EQ(gfx::ToRoundedRect(candidate_list[0].display_rect), kNormalBiggest);
+  EXPECT_EQ(candidate_list[0].plane_z_order, 1);
+  EXPECT_EQ(gfx::ToRoundedRect(candidate_list[1].display_rect), kNormalBig);
+  EXPECT_EQ(candidate_list[1].plane_z_order, 1);
+
+  // Candidates with masks are appended at the end of the `candidate_list` in
+  // draw order.
+  EXPECT_EQ(gfx::ToRoundedRect(candidate_list[2].display_rect),
+            kRoundedDisplayMaskRectSmall);
+  EXPECT_EQ(candidate_list[2].plane_z_order, 2);
+  EXPECT_EQ(gfx::ToRoundedRect(candidate_list[3].display_rect),
+            kRoundedDisplayMaskRectSmallest);
+  EXPECT_EQ(candidate_list[3].plane_z_order, 2);
+}
+
+TEST_F(SizeSortedMultiOverlayTest, OverlaysAreSorted) {
+  constexpr gfx::Rect kBiggest(0, 0, 128, 128);
+  constexpr gfx::Rect kBig(128, 28, 100, 100);
+  // kSmall rect intersects with kSmallest rect.
+  constexpr gfx::Rect kSmall(66, 128, 64, 64);
+  constexpr gfx::Rect kSmallest(128, 128, 32, 32);
+  // The draw order of these candidates is scrambled, so we can verify that the
+  // plane_z_orders are are based on draw quad order.
+  constexpr gfx::Rect kCandRects[]{kBiggest, kSmallest, kBig};
+  constexpr gfx::Rect kAllCands(0, 0, 228, 192);
+
+  damage_rect_ = kAllCands;
+  auto pass = CreateRenderPass();
+
+  // Quad with rounded_display mask occluded candidate at `kSmallest`.
+  CreateQuadWithRoundedDisplayMasksAt(
+      resource_provider_.get(), child_resource_provider_.get(),
+      child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+      /*is_overlay_candidate=*/true, kSmall,
+      RoundedDisplayMasksInfo::CreateRoundedDisplayMasksInfo(16, 16));
+
+  for (auto& cand_rect : kCandRects) {
+    CreateCandidateQuadAt(resource_provider_.get(),
+                          child_resource_provider_.get(), child_provider_.get(),
+                          pass->shared_quad_state_list.back(), pass.get(),
+                          cand_rect);
+  }
+  // Candidates will be sorted by surface area. All will be promoted.
+  overlay_processor_->AddExpectedRect(kBiggest, true);
+  overlay_processor_->AddExpectedRect(kBig, true);
+  overlay_processor_->AddExpectedRect(kSmall, true);
+  overlay_processor_->AddExpectedRect(kSmallest, true);
+
+  {
+    // Add something behind them.
+    auto* sqs = pass->CreateAndAppendSharedQuadState();
+    CreateFullscreenOpaqueQuad(resource_provider_.get(), sqs, pass.get());
+  }
+
+  OverlayCandidateList candidate_list;
+  OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+  OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+  SurfaceDamageRectList surface_damage_rect_list;
+  AggregatedRenderPassList pass_list;
+  pass_list.push_back(std::move(pass));
+
+  overlay_processor_->ProcessForOverlays(
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_backdrop_filters,
+      std::move(surface_damage_rect_list), nullptr, &candidate_list,
+      &damage_rect_, &content_bounds_);
+
+  ASSERT_EQ(candidate_list.size(), 4u);
+  // Expect all four are promoted to overlays, and their plane_z_order is based
+  // on draw order.
+  EXPECT_EQ(gfx::ToRoundedRect(candidate_list[0].display_rect), kBiggest);
+  EXPECT_EQ(candidate_list[0].plane_z_order, 1);
+  EXPECT_EQ(gfx::ToRoundedRect(candidate_list[1].display_rect), kBig);
+  EXPECT_EQ(candidate_list[1].plane_z_order, 1);
+  EXPECT_EQ(gfx::ToRoundedRect(candidate_list[2].display_rect), kSmall);
+  EXPECT_EQ(candidate_list[2].plane_z_order, 2);
+  EXPECT_EQ(gfx::ToRoundedRect(candidate_list[3].display_rect), kSmallest);
+  EXPECT_EQ(candidate_list[3].plane_z_order, 1);
+}
+
+TEST_F(SizeSortedMultiUnderlayOverlayTest, UnderlaysAreSorted) {
   constexpr gfx::Rect kBiggest(0, 0, 128, 128);
   constexpr gfx::Rect kBig(128, 28, 100, 100);
   constexpr gfx::Rect kSmall(64, 128, 64, 64);
diff --git a/components/webauthn/android/BUILD.gn b/components/webauthn/android/BUILD.gn
index 7adf60f..eb9ab452 100644
--- a/components/webauthn/android/BUILD.gn
+++ b/components/webauthn/android/BUILD.gn
@@ -82,6 +82,8 @@
     "webauthn_browser_bridge.h",
     "webauthn_client_android.cc",
     "webauthn_client_android.h",
+    "webauthn_cred_man_delegate.cc",
+    "webauthn_cred_man_delegate.h",
   ]
   deps = [
     ":jni_headers",
diff --git a/components/webauthn/android/java/src/org/chromium/components/webauthn/WebAuthnBrowserBridge.java b/components/webauthn/android/java/src/org/chromium/components/webauthn/WebAuthnBrowserBridge.java
index d150b5c..fac34b4a 100644
--- a/components/webauthn/android/java/src/org/chromium/components/webauthn/WebAuthnBrowserBridge.java
+++ b/components/webauthn/android/java/src/org/chromium/components/webauthn/WebAuthnBrowserBridge.java
@@ -50,6 +50,28 @@
     }
 
     /**
+     * Provides the C++ side |hasResults| and |fullAssertion| to be consumed during user interaction
+     * (i.e. focusing login forms).
+     *
+     * @param frameHost The RenderFrameHost for the frame that generated the request.
+     * @param hasResults The response from credMan whether there are credentials for the
+     *         GetAssertion request.
+     * @param fullAssertion The CredMan request to trigger UI for credential selection for the
+     *         completed conditional request.
+     */
+    public void onCredManConditionalRequestPending(
+            RenderFrameHost frameHost, boolean hasResults, Runnable fullAssertion) {
+        if (mNativeWebAuthnBrowserBridge == 0) {
+            mNativeWebAuthnBrowserBridge =
+                    WebAuthnBrowserBridgeJni.get().createNativeWebAuthnBrowserBridge(
+                            WebAuthnBrowserBridge.this);
+        }
+
+        WebAuthnBrowserBridgeJni.get().onCredManConditionalRequestPending(
+                mNativeWebAuthnBrowserBridge, frameHost, hasResults, fullAssertion);
+    }
+
+    /**
      * Cancels an outstanding Conditional UI request that was initiated through
      * onCredentialsDetailsListReceived. This causes the callback to be invoked with an
      * empty credential.
@@ -91,6 +113,8 @@
         void onCredentialsDetailsListReceived(long nativeWebAuthnBrowserBridge,
                 WebAuthnBrowserBridge caller, WebAuthnCredentialDetails[] credentialList,
                 RenderFrameHost frameHost, boolean isConditionalRequest, Callback<byte[]> callback);
+        void onCredManConditionalRequestPending(long nativeWebAuthnBrowserBridge,
+                RenderFrameHost frameHost, boolean hasResults, Runnable fullAssertion);
         void cancelRequest(long nativeWebAuthnBrowserBridge, RenderFrameHost frameHost);
     }
 }
diff --git a/components/webauthn/android/webauthn_browser_bridge.cc b/components/webauthn/android/webauthn_browser_bridge.cc
index 9c1599b..3272455a 100644
--- a/components/webauthn/android/webauthn_browser_bridge.cc
+++ b/components/webauthn/android/webauthn_browser_bridge.cc
@@ -115,6 +115,30 @@
           base::android::ScopedJavaGlobalRef<jobject>(env, jcallback)));
 }
 
+void TriggerFullRequest(
+    const base::android::JavaRef<jobject>& jfull_request_runnable) {
+  base::android::RunRunnableAndroid(jfull_request_runnable);
+}
+
+void WebAuthnBrowserBridge::OnCredManConditionalRequestPending(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& jframe_host,
+    jboolean jhas_results,
+    const base::android::JavaParamRef<jobject>& jfull_request_runnable) {
+  auto* client = components::WebAuthnClientAndroid::GetClient();
+  auto* render_frame_host =
+      content::RenderFrameHost::FromJavaRenderFrameHost(jframe_host);
+  if (!client || !render_frame_host ||
+      !content::WebContents::FromRenderFrameHost(render_frame_host)) {
+    return;
+  }
+  client->OnCredManConditionalRequestPending(
+      render_frame_host, jhas_results,
+      base::BindRepeating(&TriggerFullRequest,
+                          base::android::ScopedJavaGlobalRef<jobject>(
+                              env, jfull_request_runnable)));
+}
+
 void WebAuthnBrowserBridge::CancelRequest(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& jframe_host) const {
diff --git a/components/webauthn/android/webauthn_browser_bridge.h b/components/webauthn/android/webauthn_browser_bridge.h
index 12f6743..4faae5f8 100644
--- a/components/webauthn/android/webauthn_browser_bridge.h
+++ b/components/webauthn/android/webauthn_browser_bridge.h
@@ -29,6 +29,12 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& jframe_host) const;
 
+  void OnCredManConditionalRequestPending(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& jframe_host,
+      jboolean jhas_results,
+      const base::android::JavaParamRef<jobject>& jfull_request_runnable);
+
  private:
   // Java object that owns this WebAuthnBrowserBridge.
   base::android::ScopedJavaGlobalRef<jobject> owner_;
diff --git a/components/webauthn/android/webauthn_client_android.cc b/components/webauthn/android/webauthn_client_android.cc
index 6f1cd3e6..4a38bee 100644
--- a/components/webauthn/android/webauthn_client_android.cc
+++ b/components/webauthn/android/webauthn_client_android.cc
@@ -7,6 +7,8 @@
 #include <memory>
 
 #include "base/check.h"
+#include "components/webauthn/android/webauthn_cred_man_delegate.h"
+#include "content/public/browser/web_contents.h"
 
 namespace components {
 
@@ -29,4 +31,15 @@
   return g_webauthn_client;
 }
 
+void WebAuthnClientAndroid::OnCredManConditionalRequestPending(
+    content::RenderFrameHost* render_frame_host,
+    bool has_results,
+    base::RepeatingClosure full_assertion_request) {
+  auto* cred_man_delegate = WebAuthnCredManDelegate::GetRequestDelegate(
+      content::WebContents::FromRenderFrameHost(render_frame_host));
+  cred_man_delegate->OnCredManConditionalRequestPending(
+      render_frame_host, has_results, std::move(full_assertion_request));
+  return;
+}
+
 }  // namespace components
diff --git a/components/webauthn/android/webauthn_client_android.h b/components/webauthn/android/webauthn_client_android.h
index c72cb7a..687afcc 100644
--- a/components/webauthn/android/webauthn_client_android.h
+++ b/components/webauthn/android/webauthn_client_android.h
@@ -41,6 +41,13 @@
   // Cancels a request if one is outstanding. Revokes the credential list and
   // causes the callback to be called with an empty credential.
   virtual void CancelWebAuthnRequest(content::RenderFrameHost* frame_host) = 0;
+
+  // Called when a pendingGetCredential call is completed. The provided closure
+  // can be used to trigger CredMan UI flows. Android U+ only.
+  void OnCredManConditionalRequestPending(
+      content::RenderFrameHost* render_frame_host,
+      bool has_results,
+      base::RepeatingClosure full_assertion_request);
 };
 
 }  // namespace components
diff --git a/components/webauthn/android/webauthn_cred_man_delegate.cc b/components/webauthn/android/webauthn_cred_man_delegate.cc
new file mode 100644
index 0000000..52317068
--- /dev/null
+++ b/components/webauthn/android/webauthn_cred_man_delegate.cc
@@ -0,0 +1,57 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/webauthn/android/webauthn_cred_man_delegate.h"
+
+#include <memory>
+#include <utility>
+#include "base/functional/callback.h"
+#include "base/logging.h"
+#include "base/memory/raw_ptr.h"
+#include "base/notreached.h"
+#include "base/supports_user_data.h"
+#include "content/public/browser/web_contents.h"
+
+namespace content {
+class RenderFrameHost;
+class WebContents;
+}  // namespace content
+
+WebAuthnCredManDelegate::WebAuthnCredManDelegate(
+    content::WebContents* web_contents) {}
+
+WebAuthnCredManDelegate::~WebAuthnCredManDelegate() = default;
+
+void WebAuthnCredManDelegate::OnCredManConditionalRequestPending(
+    content::RenderFrameHost* render_frame_host,
+    bool has_results,
+    base::RepeatingClosure full_assertion_request) {
+  has_results_ = has_results;
+  full_assertion_request_ = std::move(full_assertion_request);
+}
+
+void WebAuthnCredManDelegate::TriggerFullRequest() {
+  std::move(full_assertion_request_).Run();
+}
+
+bool WebAuthnCredManDelegate::HasResults() {
+  return has_results_;
+}
+
+// static
+WebAuthnCredManDelegate* WebAuthnCredManDelegate::GetRequestDelegate(
+    content::WebContents* web_contents) {
+  static constexpr char kWebAuthnCredManDelegateKey[] = "WebAuthnCredManKey";
+  auto* delegate = static_cast<WebAuthnCredManDelegate*>(
+      web_contents->GetUserData(kWebAuthnCredManDelegateKey));
+  if (!delegate) {
+    auto new_user_data =
+        std::make_unique<WebAuthnCredManDelegate>(web_contents);
+    delegate = new_user_data.get();
+    web_contents->SetUserData(kWebAuthnCredManDelegateKey,
+                              std::move(new_user_data));
+  }
+
+  return delegate;
+}
diff --git a/components/webauthn/android/webauthn_cred_man_delegate.h b/components/webauthn/android/webauthn_cred_man_delegate.h
new file mode 100644
index 0000000..37a6f77
--- /dev/null
+++ b/components/webauthn/android/webauthn_cred_man_delegate.h
@@ -0,0 +1,56 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_WEBAUTHN_ANDROID_WEBAUTHN_CRED_MAN_DELEGATE_H_
+#define COMPONENTS_WEBAUTHN_ANDROID_WEBAUTHN_CRED_MAN_DELEGATE_H_
+
+#include <vector>
+
+#include "base/functional/callback.h"
+#include "base/memory/raw_ptr.h"
+#include "base/supports_user_data.h"
+
+namespace content {
+class RenderFrameHost;
+class WebContents;
+}  // namespace content
+
+// This class is responsible for caching and serving CredMan calls. Android U+
+// only.
+class WebAuthnCredManDelegate : public base::SupportsUserData::Data {
+ public:
+  explicit WebAuthnCredManDelegate(content::WebContents* web_contents);
+
+  WebAuthnCredManDelegate(const WebAuthnCredManDelegate&) = delete;
+  WebAuthnCredManDelegate& operator=(const WebAuthnCredManDelegate&) = delete;
+
+  ~WebAuthnCredManDelegate() override;
+
+  // Called when a Web Authentication Conditional UI request is received. This
+  // caches the callback that will complete the request after user
+  // interaction.
+  void OnCredManConditionalRequestPending(
+      content::RenderFrameHost* render_frame_host,
+      bool has_results,
+      base::RepeatingClosure full_assertion_request);
+
+  // Called when the user focuses a webauthn login form. This will trigger
+  // CredMan UI.
+  void TriggerFullRequest();
+
+  bool HasResults();
+
+  // Returns a delegate associated with the |web_contents|. It creates one if
+  // one does not already exist.
+  // The delegate is destroyed along with the WebContents and so should not be
+  // cached.
+  static WebAuthnCredManDelegate* GetRequestDelegate(
+      content::WebContents* web_contents);
+
+ private:
+  bool has_results_;
+  base::RepeatingClosure full_assertion_request_;
+};
+
+#endif  // COMPONENTS_WEBAUTHN_ANDROID_WEBAUTHN_CRED_MAN_DELEGATE_H_
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index aaf5673..5086de0 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -226,6 +226,7 @@
     "//services/viz/privileged/mojom",
     "//services/viz/public/cpp/gpu",
     "//services/viz/public/mojom",
+    "//services/webnn/public/mojom",
     "//skia",
     "//skia:skia_resources",
     "//skia/public/mojom",
diff --git a/content/browser/accessibility/hit_testing_browsertest.cc b/content/browser/accessibility/hit_testing_browsertest.cc
index 9ef29216..eac6036 100644
--- a/content/browser/accessibility/hit_testing_browsertest.cc
+++ b/content/browser/accessibility/hit_testing_browsertest.cc
@@ -146,9 +146,8 @@
                                             event_to_fire, 0, {});
   EXPECT_TRUE(event_waiter.WaitForNotification());
 
-  RenderFrameHostImpl* target_frame = event_waiter.event_render_frame_host();
   BrowserAccessibilityManager* target_manager =
-      target_frame->browser_accessibility_manager();
+      event_waiter.event_browser_accessibility_manager();
   int event_target_id = event_waiter.event_target_id();
   BrowserAccessibility* hit_node = target_manager->GetFromID(event_target_id);
   return hit_node;
diff --git a/content/browser/android/app_web_message_port.cc b/content/browser/android/app_web_message_port.cc
index 95eddc0..eeff86b 100644
--- a/content/browser/android/app_web_message_port.cc
+++ b/content/browser/android/app_web_message_port.cc
@@ -45,12 +45,13 @@
 // static
 base::android::ScopedJavaLocalRef<jobject> AppWebMessagePort::Create(
     blink::MessagePortDescriptor&& descriptor) {
-  auto ptr = base::WrapUnique(new AppWebMessagePort(std::move(descriptor)));
+  auto app_web_message_port =
+      base::WrapUnique(new AppWebMessagePort(std::move(descriptor)));
   JNIEnv* env = base::android::AttachCurrentThread();
-  auto* raw_ptr = ptr.get();
+  auto* app_web_messge_port_ptr = app_web_message_port.get();
   auto j_obj = Java_AppWebMessagePort_Constructor(
-      env, reinterpret_cast<intptr_t>(ptr.release()));
-  raw_ptr->j_obj_ = JavaObjectWeakGlobalRef(env, j_obj);
+      env, reinterpret_cast<intptr_t>(app_web_message_port.release()));
+  app_web_messge_port_ptr->j_obj_ = JavaObjectWeakGlobalRef(env, j_obj);
   return j_obj;
 }
 
diff --git a/content/browser/back_forward_cache_internal_browsertest.cc b/content/browser/back_forward_cache_internal_browsertest.cc
index 2e7b99d..b157b139 100644
--- a/content/browser/back_forward_cache_internal_browsertest.cc
+++ b/content/browser/back_forward_cache_internal_browsertest.cc
@@ -3573,7 +3573,9 @@
     ExpectRestored(FROM_HERE);
 
     ASSERT_TRUE(waiter_start.WaitForNotification());
-    EXPECT_EQ(waiter_start.event_render_frame_host(), rfh_a.get());
+    auto* waiter_start_rfhi = static_cast<RenderFrameHostImpl*>(
+        waiter_start.event_browser_accessibility_manager()->delegate());
+    EXPECT_EQ(waiter_start_rfhi, rfh_a.get());
   }
 }
 
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index 365dea0..90bd74a 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -216,6 +216,10 @@
 #include "media/mojo/mojom/fuchsia_media.mojom.h"
 #endif
 
+#if !BUILDFLAG(IS_CHROMEOS)
+#include "services/webnn/public/mojom/webnn_service.mojom.h"
+#endif
+
 namespace blink {
 class StorageKey;
 }  // namespace blink
@@ -264,6 +268,26 @@
   GetShapeDetectionService()->BindTextDetection(std::move(receiver));
 }
 
+#if !BUILDFLAG(IS_CHROMEOS)
+webnn::mojom::WebNNService* GetWebNNService() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  static base::NoDestructor<mojo::Remote<webnn::mojom::WebNNService>> remote;
+  if (!*remote) {
+    auto* gpu = GpuProcessHost::Get();
+    if (gpu) {
+      gpu->RunService(remote->BindNewPipeAndPassReceiver());
+    }
+  }
+
+  return remote->get();
+}
+
+void BindWebNNContextProvider(
+    mojo::PendingReceiver<webnn::mojom::WebNNContextProvider> receiver) {
+  GetWebNNService()->BindWebNNContextProvider(std::move(receiver));
+}
+#endif
+
 #if BUILDFLAG(IS_MAC)
 void BindTextInputHost(
     mojo::PendingReceiver<blink::mojom::TextInputHost> receiver) {
@@ -880,6 +904,14 @@
         base::BindRepeating(&CreateMLService));
   }
 
+#if !BUILDFLAG(IS_CHROMEOS)
+  if (base::FeatureList::IsEnabled(
+          blink::features::kEnableMachineLearningNeuralNetworkService)) {
+    map->Add<webnn::mojom::WebNNContextProvider>(
+        base::BindRepeating(&BindWebNNContextProvider));
+  }
+#endif
+
   if (base::FeatureList::IsEnabled(blink::features::kPendingBeaconAPI)) {
     map->Add<blink::mojom::PendingBeaconHost>(base::BindRepeating(
         &RenderFrameHostImpl::GetPendingBeaconHost, base::Unretained(host)));
diff --git a/content/browser/indexed_db/indexed_db_callback_helpers.h b/content/browser/indexed_db/indexed_db_callback_helpers.h
index ddfb76c..d5659716 100644
--- a/content/browser/indexed_db/indexed_db_callback_helpers.h
+++ b/content/browser/indexed_db/indexed_db_callback_helpers.h
@@ -110,13 +110,14 @@
 // the weak pointer is invalidated then we just return a default (success).
 template <typename T, typename Functor, typename... Args>
 IndexedDBTransaction::Operation BindWeakOperation(Functor&& functor,
-                                                  base::WeakPtr<T> ptr,
+                                                  base::WeakPtr<T> weak_ptr,
                                                   Args&&... args) {
-  DCHECK(ptr);
-  T* raw_ptr = ptr.get();
+  DCHECK(weak_ptr);
+  T* ptr = weak_ptr.get();
   return base::BindOnce(
-      &indexed_db_callback_helpers_internal::InvokeOrSucceed<T>, std::move(ptr),
-      base::BindOnce(std::forward<Functor>(functor), base::Unretained(raw_ptr),
+      &indexed_db_callback_helpers_internal::InvokeOrSucceed<T>,
+      std::move(weak_ptr),
+      base::BindOnce(std::forward<Functor>(functor), base::Unretained(ptr),
                      std::forward<Args>(args)...));
 }
 
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 849a7be..a0ed9f6d 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -5,6 +5,7 @@
 #include <stdint.h>
 
 #include <memory>
+#include <variant>
 
 #include "base/command_line.h"
 #include "base/containers/contains.h"
@@ -29,6 +30,7 @@
 #include "content/browser/browser_url_handler_impl.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/renderer_host/navigation_request.h"
+#include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/content_navigation_policy.h"
 #include "content/common/features.h"
@@ -92,6 +94,7 @@
 #include "services/network/public/mojom/url_loader.mojom.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/loader/url_loader_throttle.h"
+#include "third_party/blink/public/mojom/frame/sudden_termination_disabler_type.mojom-shared.h"
 #include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
 #include "url/url_util.h"
@@ -6278,4 +6281,209 @@
   EXPECT_EQ(console_observer.messages().size(), 0u);
 }
 
+// We may have an unload handler in the main frame or a subframe or nowhere.
+enum class UnloadFrameType {
+  kMainFrame,
+  kSubFrame,
+  kNone,
+};
+
+static std::string ToString(UnloadFrameType v) {
+  switch (v) {
+    case UnloadFrameType::kMainFrame:
+      return "MainFrame";
+    case UnloadFrameType::kSubFrame:
+      return "SubFrame";
+    case UnloadFrameType::kNone:
+      return "None";
+  }
+}
+
+// We may navigate the main frame, the subframe that may have an unload handler
+// or another subframe that will never have an unload handler.
+enum class NavigateFrameType {
+  kMainFrame,
+  kSubFrame,
+  kOther,
+};
+
+static std::string ToString(NavigateFrameType v) {
+  switch (v) {
+    case NavigateFrameType::kMainFrame:
+      return "MainFrame";
+    case NavigateFrameType::kSubFrame:
+      return "SubFrame";
+    case NavigateFrameType::kOther:
+      return "Other";
+  }
+}
+
+void AddUnloadHandler(RenderFrameHostImpl* rfh) {
+  ASSERT_TRUE(ExecJs(rfh, "addEventListener('unload', () => {})"));
+  ASSERT_TRUE(rfh->GetSuddenTerminationDisablerState(
+      blink::mojom::SuddenTerminationDisablerType::kUnloadHandler));
+}
+
+class NavigationSuddenTerminationDisablerTypeBrowserTest
+    : public NavigationBrowserTest,
+      public ::testing::WithParamInterface<
+          std::tuple<UnloadFrameType, NavigateFrameType>> {
+ public:
+  static std::string DescribeParams(
+      const ::testing::TestParamInfo<ParamType>& info) {
+    return "Unload" + ToString(std::get<0>(info.param)) + "Navigate" +
+           ToString(std::get<1>(info.param));
+  }
+
+ protected:
+  UnloadFrameType GetUnloadFrameType() { return std::get<0>(GetParam()); }
+  NavigateFrameType GetNavigateFrameType() { return std::get<1>(GetParam()); }
+
+  void MaybeAddUnloadHandler() {
+    RenderFrameHostImpl* rfh = nullptr;
+    switch (GetUnloadFrameType()) {
+      case UnloadFrameType::kMainFrame:
+        rfh = current_frame_host();
+        break;
+      case UnloadFrameType::kSubFrame:
+        rfh = DescendantRenderFrameHostImplAt(current_frame_host(), {0});
+        break;
+      case UnloadFrameType::kNone:
+        break;
+    }
+    if (rfh) {
+      AddUnloadHandler(rfh);
+    }
+  }
+
+  RenderFrameHostImpl* GetFrameToNavigate() {
+    switch (GetNavigateFrameType()) {
+      case NavigateFrameType::kMainFrame:
+        return current_frame_host();
+      case NavigateFrameType::kSubFrame:
+        return DescendantRenderFrameHostImplAt(current_frame_host(), {0});
+      case NavigateFrameType::kOther:
+        return DescendantRenderFrameHostImplAt(current_frame_host(), {1});
+    }
+  }
+
+  bool NavigatedFrameHasUnload() {
+    switch (GetNavigateFrameType()) {
+      case NavigateFrameType::kOther:
+        // It never has unload.
+        return false;
+      case NavigateFrameType::kMainFrame:
+        // Navigating the main will have unload if there is any unload.
+        return GetUnloadFrameType() != UnloadFrameType::kNone;
+      case NavigateFrameType::kSubFrame:
+        // Navigating the subframe will have unload if the subframe has unload.
+        return GetUnloadFrameType() == UnloadFrameType::kSubFrame;
+    }
+  }
+};
+
+// Set up a page with 2 subframes. The main frame or one of the subframes may
+// have an unload handler. Then navigate one of the frames and verify that we
+// correctly record which type of frame navigates combined with whether it
+// involved an unload handler.
+IN_PROC_BROWSER_TEST_P(NavigationSuddenTerminationDisablerTypeBrowserTest,
+                       RecordUma) {
+  ASSERT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(
+                   "a.com", "/cross_site_iframe_factory.html?a(a,a)")));
+
+  // Set up the unload handler if needed.
+  MaybeAddUnloadHandler();
+
+  // Navigate the relevant frame and capture histograms.
+  base::HistogramTester histograms;
+  ASSERT_TRUE(NavigateFrameToURL(GetFrameToNavigate()->frame_tree_node(),
+                                 GURL("about:blank")));
+
+  // Check that we got the expected histogram value.
+  uint32_t expected_histogram_value = 0;
+  if (GetNavigateFrameType() == NavigateFrameType::kMainFrame) {
+    expected_histogram_value |= RenderFrameHostImpl::
+        NavigationSuddenTerminationDisablerType::kMainFrame;
+  }
+  if (NavigatedFrameHasUnload()) {
+    expected_histogram_value |=
+        RenderFrameHostImpl::NavigationSuddenTerminationDisablerType::kUnload;
+  }
+  histograms.ExpectUniqueSample(
+      "Navigation.SuddenTerminationDisabler.AllOrigins",
+      expected_histogram_value, 1);
+  histograms.ExpectUniqueSample(
+      "Navigation.SuddenTerminationDisabler.SameOrigin",
+      expected_histogram_value, 1);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    NavigationSuddenTerminationDisablerTypeBrowserTest,
+    ::testing::Combine(::testing::Values(UnloadFrameType::kMainFrame,
+                                         UnloadFrameType::kSubFrame,
+                                         UnloadFrameType::kNone),
+                       ::testing::Values(NavigateFrameType::kMainFrame,
+                                         NavigateFrameType::kSubFrame,
+                                         NavigateFrameType::kOther)),
+    &NavigationSuddenTerminationDisablerTypeBrowserTest::DescribeParams);
+
+// Test that "SameOrigin" only considers frames that have an unbroken path of
+// same-origin frames from the frame that navigates.
+IN_PROC_BROWSER_TEST_F(
+    NavigationBrowserTest,
+    NavigationSuddenTerminationDisablerTypeRecordUmaSameOrigin) {
+  ASSERT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(
+                   "a.com", "/cross_site_iframe_factory.html?a(b(a))")));
+
+  // Set up the unload handler in the a.com subframe.
+  AddUnloadHandler(
+      DescendantRenderFrameHostImplAt(current_frame_host(), {0, 0}));
+  // Navigate the main frame and capture histograms.
+  base::HistogramTester histograms;
+  ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
+
+  histograms.ExpectUniqueSample(
+      "Navigation.SuddenTerminationDisabler.AllOrigins",
+      RenderFrameHostImpl::NavigationSuddenTerminationDisablerType::kMainFrame |
+          RenderFrameHostImpl::NavigationSuddenTerminationDisablerType::kUnload,
+      1);
+  histograms.ExpectUniqueSample(
+      "Navigation.SuddenTerminationDisabler.SameOrigin",
+      RenderFrameHostImpl::NavigationSuddenTerminationDisablerType::kMainFrame,
+      1);
+}
+
+// Test that we record when the navigation involves restoring from BFCache.
+// This is tested because the code path for a navigation involving activation
+// is different from one involving a pageload.
+IN_PROC_BROWSER_TEST_F(
+    NavigationBrowserTest,
+    NavigationSuddenTerminationDisablerTypeRecordUmaActivation) {
+  ASSERT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
+
+  ASSERT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
+
+  // Set up the unload handler in the b.com page.
+  AddUnloadHandler(current_frame_host());
+  // Navigate the main frame and capture histograms.
+  base::HistogramTester histograms;
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+
+  histograms.ExpectUniqueSample(
+      "Navigation.SuddenTerminationDisabler.AllOrigins",
+      RenderFrameHostImpl::NavigationSuddenTerminationDisablerType::kMainFrame |
+          RenderFrameHostImpl::NavigationSuddenTerminationDisablerType::kUnload,
+      1);
+  histograms.ExpectUniqueSample(
+      "Navigation.SuddenTerminationDisabler.SameOrigin",
+      RenderFrameHostImpl::NavigationSuddenTerminationDisablerType::kMainFrame |
+          RenderFrameHostImpl::NavigationSuddenTerminationDisablerType::kUnload,
+      1);
+}
+
 }  // namespace content
diff --git a/content/browser/preloading/prerender/prerender_browsertest.cc b/content/browser/preloading/prerender/prerender_browsertest.cc
index d569d37..6551313 100644
--- a/content/browser/preloading/prerender/prerender_browsertest.cc
+++ b/content/browser/preloading/prerender/prerender_browsertest.cc
@@ -7742,18 +7742,6 @@
                                     ui::PAGE_TRANSITION_FROM_ADDRESS_BAR),
           nullptr);
   EXPECT_TRUE(prerender_handle);
-
-  // Navigate to `kInitialUrl` on the primary page. This should make
-  // SpeculationHostImpl destructed.
-  NavigatePrimaryPage(kInitialUrl);
-  ASSERT_EQ(web_contents()->GetLastCommittedURL(), kInitialUrl);
-
-  // The metric is recorded after SpeculationHostImpl is destructed or a primary
-  // page is updated.
-  histogram_tester().ExpectUniqueSample(
-      "Prerender.Experimental.CancellationPercentageByExcessiveMemoryUsage."
-      "SpeculationRule",
-      0, 1);
 }
 
 // Tests that PrerenderHostRegistry can't start any prerenderings if the
@@ -7798,18 +7786,6 @@
                                     ui::PAGE_TRANSITION_FROM_ADDRESS_BAR),
           nullptr);
   EXPECT_TRUE(prerender_handle);
-
-  // Navigate to `kInitialUrl` on the primary page. This should make
-  // SpeculationHostImpl destructed.
-  NavigatePrimaryPage(kInitialUrl);
-  ASSERT_EQ(web_contents()->GetLastCommittedURL(), kInitialUrl);
-
-  // The metric is recorded after SpeculationHostImpl is destructed or a primary
-  // page is updated.
-  histogram_tester().ExpectUniqueSample(
-      "Prerender.Experimental.CancellationPercentageByExcessiveMemoryUsage."
-      "SpeculationRule",
-      count_of_memory_limit_exceeded * 100 / MaxNumOfRunningPrerenders(), 1);
 }
 
 // Tests that PrerenderHostRegistry can start prerendering when the DevTools is
diff --git a/content/browser/preloading/prerender/prerender_host.h b/content/browser/preloading/prerender/prerender_host.h
index 123b592..a04cc62 100644
--- a/content/browser/preloading/prerender/prerender_host.h
+++ b/content/browser/preloading/prerender/prerender_host.h
@@ -82,6 +82,8 @@
     kMaxValue = kRequestDestination,
   };
 
+  // Observes a triggered prerender. Note that the observer should overlive the
+  // prerender host instance, or be removed properly upon destruction.
   class Observer : public base::CheckedObserver {
    public:
     // Called on the page activation.
diff --git a/content/browser/preloading/prerenderer_impl.cc b/content/browser/preloading/prerenderer_impl.cc
index 359f4da7..673581d 100644
--- a/content/browser/preloading/prerenderer_impl.cc
+++ b/content/browser/preloading/prerenderer_impl.cc
@@ -16,38 +16,6 @@
 
 namespace content {
 
-class PrerendererImpl::PrerenderHostObserver : public PrerenderHost::Observer {
- public:
-  explicit PrerenderHostObserver(PrerenderHost* prerender_host);
-  ~PrerenderHostObserver() override;
-
-  // PrerenderHost::Observer implementation:
-  void OnHostDestroyed(PrerenderFinalStatus final_status) override;
-
-  bool destroyed_by_memory_limit_exceeded() const {
-    return destroyed_by_memory_limit_exceeded_;
-  }
-
- private:
-  bool destroyed_by_memory_limit_exceeded_ = false;
-  base::ScopedObservation<PrerenderHost, PrerenderHost::Observer> observation_{
-      this};
-};
-
-PrerendererImpl::PrerenderHostObserver::PrerenderHostObserver(
-    PrerenderHost* prerender_host) {
-  if (prerender_host)
-    observation_.Observe(prerender_host);
-}
-PrerendererImpl::PrerenderHostObserver::~PrerenderHostObserver() = default;
-
-void PrerendererImpl::PrerenderHostObserver::OnHostDestroyed(
-    PrerenderFinalStatus final_status) {
-  observation_.Reset();
-  if (final_status == PrerenderFinalStatus::kMemoryLimitExceeded)
-    destroyed_by_memory_limit_exceeded_ = true;
-}
-
 struct PrerendererImpl::PrerenderInfo {
   GURL url;
   Referrer referrer;
@@ -61,6 +29,7 @@
   auto& rfhi = static_cast<RenderFrameHostImpl&>(render_frame_host);
   registry_ = rfhi.delegate()->GetPrerenderHostRegistry()->GetWeakPtr();
 }
+
 PrerendererImpl::~PrerendererImpl() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   CancelStartedPrerenders();
@@ -270,19 +239,6 @@
                                    {.url = candidate->url,
                                     .referrer = referrer,
                                     .prerender_host_id = prerender_host_id});
-
-        // TODO(crbug.com/1350676): Observe PrerenderHost created for
-        // prerendering in a new tab like the kNoHint and kSelf cases.
-        // TODO(crbug.com/1350676): Update the counter of
-        // `count_started_same_tab_prerenders_`. We cannot update this counter
-        // at this point because the counter is used to calculate the
-        // percentage of started prerenders that failed due to
-        // kMemoryLimitExceeded, which is done by observing PrerenderHosts,
-        // but this class cannot observe the started new-tab prerender at this
-        // moment. Rational: COUNT(kMemoryLimitExceeded && non-new-tab) /
-        // COUNT(non-new-tab) should be close to COUNT(kMemoryLimitExceeded) /
-        // COUNT(*), but COUNT(kMemoryLimitExceeded && non-new-tab) / COUNT(*)
-        // would follow another distribution.
         break;
       }
       // Handle the rule as kNoHint if the prerender-in-new-tab is not
@@ -296,11 +252,6 @@
       started_prerenders_.insert(end, {.url = candidate->url,
                                        .referrer = referrer,
                                        .prerender_host_id = prerender_host_id});
-      count_started_same_tab_prerenders_++;
-      // Start to observe PrerenderHost to get the information about
-      // FinalStatus.
-      observers_.push_back(std::make_unique<PrerenderHostObserver>(
-          registry_->FindNonReservedHostById(prerender_host_id)));
       break;
     }
   }
@@ -320,26 +271,6 @@
 }
 
 void PrerendererImpl::CancelStartedPrerenders() {
-  // This function can be called twice and the histogram should be recorded in
-  // the first call. Also, skip recording the histogram when no prerendering
-  // starts.
-  if (count_started_same_tab_prerenders_ == 0) {
-    DCHECK(observers_.empty());
-    return;
-  }
-
-  // Record the percentage of destroyed prerenders due to the excessive memory
-  // usage.
-  // The closer the value is to 0, the less prerenders are cancelled by
-  // FinalStatus::kMemoryLimitExceeded. The result depends on Finch params
-  // `max_num_of_running_speculation_rules` and
-  // `acceptable_percent_of_system_memory`.
-  base::UmaHistogramPercentage(
-      "Prerender.Experimental.CancellationPercentageByExcessiveMemoryUsage."
-      "SpeculationRule",
-      GetNumberOfDestroyedByMemoryExceeded() * 100 /
-          count_started_same_tab_prerenders_);
-
   if (registry_) {
     std::vector<int> started_prerender_ids;
     for (auto& prerender_info : started_prerenders_) {
@@ -351,17 +282,6 @@
   }
 
   started_prerenders_.clear();
-  count_started_same_tab_prerenders_ = 0;
-  observers_.clear();
-}
-
-int PrerendererImpl::GetNumberOfDestroyedByMemoryExceeded() {
-  int destroyed_prerenders_by_memory_limit_exceeded = 0;
-  for (auto& observer : observers_) {
-    if (observer->destroyed_by_memory_limit_exceeded())
-      destroyed_prerenders_by_memory_limit_exceeded++;
-  }
-  return destroyed_prerenders_by_memory_limit_exceeded;
 }
 
 }  // namespace content
diff --git a/content/browser/preloading/prerenderer_impl.h b/content/browser/preloading/prerenderer_impl.h
index c6dfc8b..0a185c65 100644
--- a/content/browser/preloading/prerenderer_impl.h
+++ b/content/browser/preloading/prerenderer_impl.h
@@ -37,27 +37,14 @@
  private:
   void CancelStartedPrerenders();
 
-  // Iterates started prerenders and counts how many of them were canceled
-  // due to the excessive memory usage.
-  int GetNumberOfDestroyedByMemoryExceeded();
-
   // TODO(https://crbug.com/1197133): Cancel started prerenders when candidates
   // are updated.
   // This is kept sorted by URL.
   struct PrerenderInfo;
-
-  // Counts the historical non-new-tab prerenders.
-  // TODO(crbug.com/1350676): Observe PrerenderHost created for
-  // prerendering in a new tab so that this counter can take new-tab prerender
-  // into account.
-  int count_started_same_tab_prerenders_ = 0;
   std::vector<PrerenderInfo> started_prerenders_;
 
   base::WeakPtr<PrerenderHostRegistry> registry_;
 
-  class PrerenderHostObserver;
-  std::vector<std::unique_ptr<PrerenderHostObserver>> observers_;
-
   // content::PreloadingDecider, which inherits content::DocumentUserData, owns
   // `this`, so `this` can access `render_frame_host_` safely.
   const raw_ref<RenderFrameHost> render_frame_host_;
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 98e187b..fefa84881 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -5577,6 +5577,12 @@
     }
   }
 
+  if (!NavigationTypeUtils::IsSameDocument(common_params_->navigation_type)) {
+    // We want to record this for the frame that we are navigating away from.
+    frame_tree_node_->render_manager()
+        ->current_frame_host()
+        ->RecordNavigationSuddenTerminationHandlers();
+  }
   if (IsServedFromBackForwardCache() || IsPrerenderedPageActivation()) {
     CommitPageActivation();
     return;
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index dd265ea..823c3b4 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 
+#include <cstdint>
 #include <memory>
 #include <tuple>
 #include <unordered_map>
@@ -9390,6 +9391,45 @@
   }
 }
 
+uint32_t RenderFrameHostImpl::FindSuddenTerminationHandlers(bool same_origin) {
+  uint32_t navigation_termination = 0;
+  // Search this frame and subframes for sudden termination disablers
+  ForEachRenderFrameHostWithAction([this, same_origin, &navigation_termination](
+                                       RenderFrameHost* rfh) {
+    if (same_origin &&
+        GetLastCommittedOrigin() != rfh->GetLastCommittedOrigin()) {
+      return FrameIterationAction::kSkipChildren;
+    }
+    if (rfh->GetSuddenTerminationDisablerState(
+            blink::mojom::SuddenTerminationDisablerType::kUnloadHandler)) {
+      navigation_termination = navigation_termination |
+                               NavigationSuddenTerminationDisablerType::kUnload;
+      // We can stop when we find the first unload handler. If we ever start
+      // reporting other types of sudden termination handler, we will need to
+      // continue.
+      return FrameIterationAction::kStop;
+    }
+    return FrameIterationAction::kContinue;
+  });
+  return navigation_termination;
+}
+
+void RenderFrameHostImpl::RecordNavigationSuddenTerminationHandlers() {
+  uint32_t navigation_termination =
+      is_main_frame() ? NavigationSuddenTerminationDisablerType::kMainFrame : 0;
+
+  base::UmaHistogramExactLinear(
+      "Navigation.SuddenTerminationDisabler.AllOrigins",
+      navigation_termination |
+          FindSuddenTerminationHandlers(/*same_origin=*/false),
+      NavigationSuddenTerminationDisablerType::kMaxValue * 2);
+  base::UmaHistogramExactLinear(
+      "Navigation.SuddenTerminationDisabler.SameOrigin",
+      navigation_termination |
+          FindSuddenTerminationHandlers(/*same_origin=*/true),
+      NavigationSuddenTerminationDisablerType::kMaxValue * 2);
+}
+
 void RenderFrameHostImpl::CommitNavigation(
     NavigationRequest* navigation_request,
     blink::mojom::CommonNavigationParamsPtr common_params,
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index 40c8eeb..e9ea753 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -2910,6 +2910,10 @@
   void SetResourceCacheRemote(
       mojo::PendingRemote<blink::mojom::ResourceCache> pending_remote);
 
+  // Records metrics on sudden termination handlers found in this frame and
+  // subframes.
+  void RecordNavigationSuddenTerminationHandlers();
+
  protected:
   friend class RenderFrameHostFactory;
 
@@ -3116,6 +3120,15 @@
                            EvictionInBFCache);
   FRIEND_TEST_ALL_PREFIXES(RenderFrameHostImplPrerenderBrowserTest,
                            KeepPrerenderRFHOwnerAfterActivation);
+  FRIEND_TEST_ALL_PREFIXES(NavigationSuddenTerminationDisablerTypeBrowserTest,
+                           RecordUma);
+  FRIEND_TEST_ALL_PREFIXES(
+      NavigationBrowserTest,
+      NavigationSuddenTerminationDisablerTypeRecordUmaSameOrigin);
+  FRIEND_TEST_ALL_PREFIXES(
+      NavigationBrowserTest,
+      NavigationSuddenTerminationDisablerTypeRecordUmaActivation);
+
   class SubresourceLoaderFactoriesConfig;
 
   FrameTreeNode* GetSibling(int relative_offset) const;
@@ -3626,6 +3639,23 @@
   // report to be routed to the Reporting API.
   void MaybeGenerateCrashReport(base::TerminationStatus status, int exit_code);
 
+  // Bitfield values for recording navigation frame-type (main or subframe)
+  // combined with whether a sudden termination disabler is present. Currently
+  // it only covers unload.
+  enum NavigationSuddenTerminationDisablerType : uint32_t {
+    kMainFrame = 1 << 0,
+    kUnload = 1 << 1,
+    kMaxValue = kUnload,
+  };
+  // Returns information to be recoreded in UMA about sudden termination
+  // disablers presence.
+  // The return value is ORed values from
+  // `NavigationSuddenTerminationDisablerType`.
+  // If `same_origin` is true, the tree traversal will only recurse into frames
+  // that are the same origin as `this`. E.g. a(b(a)) will not find the second
+  // a.
+  uint32_t FindSuddenTerminationHandlers(bool same_origin);
+
   // The reason for calling StartPendingDeletionOnSubtree() / what is causing
   // the RenderFrameHost to enter the "pending deletion" stage.
   enum class PendingDeletionReason {
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index d68ed217..bb4a936 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -80,6 +80,7 @@
 #include "content/public/test/fenced_frame_test_util.h"
 #include "content/public/test/mock_client_hints_controller_delegate.h"
 #include "content/public/test/navigation_handle_observer.h"
+#include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
 #include "content/public/test/url_loader_interceptor.h"
 #include "content/shell/browser/shell.h"
@@ -5061,26 +5062,32 @@
         [](const net::test_server::HttpRequest& request)
             -> std::unique_ptr<net::test_server::HttpResponse> {
           if (!base::Contains(request.GetURL().path(),
-                              "/service_worker/slow")) {
+                              "/service_worker/mock_response")) {
             return nullptr;
           }
 
-          auto http_response =
-              std::make_unique<net::test_server::DelayedHttpResponse>(
-                  base::Seconds(2));
+          const bool is_slow =
+              base::Contains(request.GetURL().query(), "server_slow");
 
-          if (base::Contains(request.GetURL().query(), "notfound")) {
+          auto http_response =
+              is_slow ? std::make_unique<net::test_server::DelayedHttpResponse>(
+                            base::Seconds(2))
+                      : std::make_unique<net::test_server::BasicHttpResponse>();
+          http_response->set_content_type("text/plain");
+
+          if (base::Contains(request.GetURL().query(), "server_notfound")) {
             http_response->set_code(net::HTTP_NOT_FOUND);
-            http_response->set_content_type("text/plain");
-            http_response->set_content("Not found");
+            http_response->set_content(
+                "[ServiceWorkerRaceNetworkRequest] Not found");
             return http_response;
           }
 
           http_response->set_code(net::HTTP_OK);
-          http_response->set_content_type("text/html");
-          http_response->set_content(
-              "<body>[ServiceWorkerRaceNetworkRequest] Slow response from the "
-              "network</body>");
+          http_response->set_content(is_slow
+                                         ? "[ServiceWorkerRaceNetworkRequest] "
+                                           "Slow response from the network"
+                                         : "[ServiceWorkerRaceNetworkRequest] "
+                                           "Response from the network");
           return http_response;
         }));
   }
@@ -5093,8 +5100,7 @@
   SetupAndRegisterServiceWorker();
   // Capture the response head.
   const GURL test_url = embedded_test_server()->GetURL(
-      "/service_worker/"
-      "race_network_request.html?timeout&respond_from_fetch_handler");
+      "/service_worker/mock_response?sw_slow&sw_respond");
 
   NavigationHandleObserver observer(web_contents(), test_url);
   NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
@@ -5117,8 +5123,7 @@
   SetupAndRegisterServiceWorker();
   NavigateToURLBlockUntilNavigationsComplete(
       shell(),
-      embedded_test_server()->GetURL(
-          "/service_worker/race_network_request.html?timeout"),
+      embedded_test_server()->GetURL("/service_worker/mock_response?sw_slow"),
       1);
 
   // ServiceWorker will respond after the delay, so we expect the response from
@@ -5137,16 +5142,57 @@
   NavigateToURLBlockUntilNavigationsComplete(
       shell(),
       embedded_test_server()->GetURL(
-          "/service_worker/not_exist.html?timeout&respond_from_fetch_handler"),
+          "/service_worker/"
+          "mock_response?server_notfound&sw_slow&sw_respond"),
       1);
   EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Response from the fetch handler",
             GetInnerText());
 
   // If the fallback request is not found. Then expect 404.
   NavigateToURLBlockUntilNavigationsComplete(
-      shell(), embedded_test_server()->GetURL("/service_worker/not_exist.html"),
+      shell(),
+      embedded_test_server()->GetURL("/service_worker/"
+                                     "mock_response?server_notfound"),
       1);
-  EXPECT_EQ("Server returned HTTP status 404", GetInnerText());
+  EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Not found", GetInnerText());
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
+                       NetworkRequest_Wins_FetchHandler_Fallback) {
+  SetupAndRegisterServiceWorker();
+  // This test works in the following steps.
+  // 1. Start RaceNetworkRequest.
+  // 2. Start service worker, and trigger fetch handler that fallback to
+  //    network.
+  // 3. Cancel RaceNetworkRequest.
+  // 4. Start fallback network request, neither RaceNetworkRequest nor the fetch
+  //    handler is involved.
+  // 5. Get the response from the fallback network request.
+  const GURL slow_url = embedded_test_server()->GetURL(
+      "/service_worker/mock_response?sw_fallback&sw_slow");
+  NavigateToURLBlockUntilNavigationsComplete(shell(), slow_url, 1);
+  EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Response from the network",
+            GetInnerText());
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
+                       NetworkRequest_Wins_Post) {
+  SetupAndRegisterServiceWorker();
+  const std::string action = "/service_worker/mock_response?sw_slow&sw_respond";
+  EXPECT_TRUE(ExecJs(GetPrimaryMainFrame(),
+                     "document.body.innerHTML = '<form action=\"" + action +
+                         "\" method=\"POST\"><button "
+                         "type=\"submit\">submit</button></form>'"));
+
+  TestNavigationObserver observer(web_contents());
+  EXPECT_TRUE(
+      ExecJs(GetPrimaryMainFrame(), "document.querySelector('form').submit()"));
+  observer.Wait();
+
+  // RaceNetworkRequest only supports GET method. So the fetch handler is always
+  // involved for the navigation via POST.
+  EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Response from the fetch handler",
+            GetInnerText());
 }
 
 IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
@@ -5154,7 +5200,7 @@
   SetupAndRegisterServiceWorker();
   // Need to navigate to the page with slow response.
   const GURL slow_url = embedded_test_server()->GetURL(
-      "/service_worker/slow?respond_from_fetch_handler");
+      "/service_worker/mock_response?server_slow&sw_respond");
 
   NavigationHandleObserver observer(web_contents(), slow_url);
   NavigateToURLBlockUntilNavigationsComplete(shell(), slow_url, 1);
@@ -5175,8 +5221,8 @@
   SetupAndRegisterServiceWorker();
   // Fetch handler will fallback. This case the response from the default
   // fallback requset will be used. RaceNetworkRequset is not involved.
-  const GURL slow_url =
-      embedded_test_server()->GetURL("/service_worker/slow?fallback");
+  const GURL slow_url = embedded_test_server()->GetURL(
+      "/service_worker/mock_response?server_slow&sw_fallback");
   NavigateToURLBlockUntilNavigationsComplete(shell(), slow_url, 1);
   EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Slow response from the network",
             GetInnerText());
@@ -5185,12 +5231,144 @@
 IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
                        FetchHandler_Wins_NotFound) {
   SetupAndRegisterServiceWorker();
-  const GURL slow_url =
-      embedded_test_server()->GetURL("/service_worker/slow?fallback&notfound");
+  const GURL slow_url = embedded_test_server()->GetURL(
+      "/service_worker/mock_response?server_slow&server_notfound&sw_fallback");
 
   // Fetch handler is fallback but the response is 404. In this case
   // RaceNetworkRequest is not involved with the navigation.
   EXPECT_TRUE(NavigateToURL(shell(), slow_url));
-  EXPECT_EQ("Not found", GetInnerText());
+  EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Not found", GetInnerText());
+}
+
+// TODO(crbug.com/1431421): Flaky on Fuchsia.
+#if BUILDFLAG(IS_FUCHSIA)
+#define MAYBE_Subresource_NetworkRequest_Wins \
+  DISABLED_Subresource_NetworkRequest_Wins
+#else
+#define MAYBE_Subresource_NetworkRequest_Wins Subresource_NetworkRequest_Wins
+#endif
+IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
+                       MAYBE_Subresource_NetworkRequest_Wins) {
+  SetupAndRegisterServiceWorker();
+  WorkerRunningStatusObserver observer(public_context());
+  ReloadBlockUntilNavigationsComplete(shell(), 1);
+  observer.WaitUntilRunning();
+  // Fetch something from the service worker.
+  EXPECT_EQ(
+      "[ServiceWorkerRaceNetworkRequest] Response from the network",
+      EvalJs(GetPrimaryMainFrame(),
+             "fetch('/service_worker/mock_response?sw_slow').then(response "
+             "=> response.text())"));
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
+                       Subresource_NetworkRequest_Wins_Fetch_No_Respond) {
+  SetupAndRegisterServiceWorker();
+  WorkerRunningStatusObserver observer(public_context());
+  ReloadBlockUntilNavigationsComplete(shell(), 1);
+  observer.WaitUntilRunning();
+  EXPECT_EQ(
+      "[ServiceWorkerRaceNetworkRequest] Response from the network",
+      EvalJs(GetPrimaryMainFrame(),
+             "fetch('/service_worker/mock_response?sw_slow').then(response "
+             "=> response.text())"));
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
+                       Subresource_NetworkRequest_Wins_NotFound) {
+  SetupAndRegisterServiceWorker();
+  WorkerRunningStatusObserver observer(public_context());
+  ReloadBlockUntilNavigationsComplete(shell(), 1);
+  observer.WaitUntilRunning();
+
+  // Network request is faster, but the response is not found.
+  // If the fetch handler respondWith a meaningful response (i.e. 200 response
+  // from the cache API), then expect the response from the fetch handler.
+  EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Response from the fetch handler",
+            EvalJs(GetPrimaryMainFrame(),
+                   "fetch('/service_worker/"
+                   "mock_response?sw_respond&server_notfound').then(response "
+                   "=> response.text())"));
+
+  // If the fallback request is not found. Then expect 404.
+  EXPECT_EQ(404, EvalJs(GetPrimaryMainFrame(),
+                        "fetch('/service_worker/mock_response?"
+                        "server_notfound').then(response => response.status)"));
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
+                       Subresource_NetworkRequest_Wins_FetchHandler_Fallback) {
+  SetupAndRegisterServiceWorker();
+  // Network request is faster, and the fetch handler will fallback.
+  // This case the response from RaceNetworkRequset is used.
+  EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Response from the network",
+            EvalJs(GetPrimaryMainFrame(),
+                   "fetch('/service_worker/mock_response?"
+                   "sw_fallback&sw_slow').then(response => "
+                   "response.text())"));
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
+                       Subresource_NetworkRequest_Wins_Post) {
+  SetupAndRegisterServiceWorker();
+  ReloadBlockUntilNavigationsComplete(shell(), 1);
+
+  // RaceNetworkRequest only supports GET method. So the fetch handler is always
+  // involved for the request via POST.
+  const std::string script = R"(
+    const option = {
+      method: 'POST',
+      body: 'fake body text'
+    };
+    fetch('service_worker/mock_response?sw_slow&sw_respond', option)
+      .then(response => response.text());
+  )";
+  EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Response from the fetch handler",
+            EvalJs(GetPrimaryMainFrame(), script));
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
+                       Subresource_FetchHandler_Wins) {
+  SetupAndRegisterServiceWorker();
+  WorkerRunningStatusObserver observer(public_context());
+  ReloadBlockUntilNavigationsComplete(shell(), 1);
+  observer.WaitUntilRunning();
+  // RaceNetworkRequest takes long time, but the fetch handler should respond
+  // from the cache.
+  EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Response from the fetch handler",
+            EvalJs(GetPrimaryMainFrame(),
+                   "fetch('/service_worker/mock_response?"
+                   "server_slow&sw_respond').then(response => "
+                   "response.text())"));
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
+                       Subresource_FetchHandler_Wins_Fallback) {
+  SetupAndRegisterServiceWorker();
+  WorkerRunningStatusObserver observer(public_context());
+  ReloadBlockUntilNavigationsComplete(shell(), 1);
+  observer.WaitUntilRunning();
+  // Fetch handler will fallback. This case the response from the default
+  // fallback requset will be used. RaceNetworkRequset is not involved.
+  EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Slow response from the network",
+            EvalJs(GetPrimaryMainFrame(),
+                   "fetch('/service_worker/mock_response?"
+                   "server_slow&sw_fallback').then(response => "
+                   "response.text())"));
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
+                       Subresource_FetchHandler_Wins_NotFound) {
+  SetupAndRegisterServiceWorker();
+  WorkerRunningStatusObserver observer(public_context());
+  ReloadBlockUntilNavigationsComplete(shell(), 1);
+  observer.WaitUntilRunning();
+  // Fetch handler is fallback but the response is 404. In this case
+  // RaceNetworkRequest is not involved.
+  EXPECT_EQ(404,
+            EvalJs(GetPrimaryMainFrame(),
+                   "fetch('/service_worker/mock_response?"
+                   "server_slow&sw_fallback&server_notfound').then(response => "
+                   "response.status)"));
 }
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_main_resource_loader.cc b/content/browser/service_worker/service_worker_main_resource_loader.cc
index 4d33567..999f4ea 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader.cc
+++ b/content/browser/service_worker/service_worker_main_resource_loader.cc
@@ -27,6 +27,7 @@
 #include "content/common/service_worker/service_worker_resource_loader.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_features.h"
+#include "net/http/http_request_headers.h"
 #include "net/http/http_status_code.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/timing_allow_origin_parser.h"
@@ -225,6 +226,11 @@
     return false;
   }
 
+  // RaceNetworkRequest only supports GET method.
+  if (resource_request_.method != net::HttpRequestHeaders::kGetMethod) {
+    return false;
+  }
+
   // Create URLLoader related assets to handle the request triggered by
   // RaceNetworkRequset.
   auto race_network_request_url_loader_client =
@@ -356,6 +362,14 @@
   if (fetch_response_from() == FetchResponseFrom::kWithoutServiceWorker) {
     return;
   }
+  // Use the response from ServiceWorker fetch handler, and cancel the
+  // connection for RaceNetworkRequest.
+  // TODO(crbug.com/1420517) RaceNetworkRequrest doesn't support fallback case.
+  // If the response from the fetch handler is fallback, the fallback resource
+  // fetch will start separately without using RaceNetworkRequest's result.
+  set_fetch_response_from(FetchResponseFrom::kServiceWorker);
+  race_network_request_url_loader_.reset();
+
   DCHECK_EQ(status_, Status::kStarted);
 
   ServiceWorkerMetrics::RecordFetchEventStatus(true /* is_main_resource */,
@@ -417,9 +431,6 @@
   DCHECK_EQ(fetch_result,
             ServiceWorkerFetchDispatcher::FetchEventResult::kGotResponse);
 
-  // Use the response from ServiceWorker fetch handler.
-  set_fetch_response_from(FetchResponseFrom::kServiceWorker);
-
   // A response with status code 0 is Blink telling us to respond with
   // network error.
   if (response->status_code == 0) {
diff --git a/content/browser/shared_storage/shared_storage_browsertest.cc b/content/browser/shared_storage/shared_storage_browsertest.cc
index ad50172..c44e03f 100644
--- a/content/browser/shared_storage/shared_storage_browsertest.cc
+++ b/content/browser/shared_storage/shared_storage_browsertest.cc
@@ -192,16 +192,8 @@
   return msg.log_level == blink::mojom::ConsoleMessageLevel::kError;
 }
 
-auto describe_shared_storage_worklet_impl_param = [](const auto& info) {
-  return base::StrCat(
-      {(info.param ? "BlinkStyle" : "Legacy"), "WorkletImplementation"});
-};
-
-auto describe_combined_param = [](const auto& info) {
-  return base::StrCat({"ResolveSelectURLTo",
-                       std::get<0>(info.param) ? "Config" : "URN",
-                       std::get<1>(info.param) ? "_BlinkStyle" : "_Legacy",
-                       "WorkletImplementation"});
+auto describe_param = [](const auto& info) {
+  return base::StrCat({"ResolveSelectURLTo", info.param ? "Config" : "URN"});
 };
 
 }  // namespace
@@ -796,7 +788,6 @@
   }
 
   virtual bool ResolveSelectURLToConfig() { return false; }
-  virtual bool BlinkStyleWorkletImplementation() { return false; }
 
   StoragePartition* GetStoragePartition() {
     return shell()
@@ -1103,33 +1094,19 @@
   std::unique_ptr<TestSharedStorageObserver> observer_;
 };
 
-class SharedStorageBrowserTest
-    : public SharedStorageBrowserTestBase,
-      public testing::WithParamInterface<std::tuple<bool, bool>> {
+class SharedStorageBrowserTest : public SharedStorageBrowserTestBase,
+                                 public testing::WithParamInterface<bool> {
  public:
   SharedStorageBrowserTest() {
-    shared_storage_feature_.InitWithFeaturesAndParameters(
-        /*enabled_features=*/
-        {{blink::features::kSharedStorageAPI,
-          {{"SharedStorageBitBudget", base::NumberToString(kBudgetAllowed)},
-           {"SharedStorageStalenessThreshold",
-            TimeDeltaToString(base::Days(kStalenessThresholdDays))},
-           {"SharedStorageWorkletImplementationType",
-            BlinkStyleWorkletImplementation() ? "blink_style" : "legacy"}}}},
-        /*disabled_features=*/{});
     fenced_frame_api_change_feature_.InitWithFeatureState(
         blink::features::kFencedFramesAPIChanges, ResolveSelectURLToConfig());
   }
 
-  bool ResolveSelectURLToConfig() override { return std::get<0>(GetParam()); }
-  bool BlinkStyleWorkletImplementation() override {
-    return std::get<1>(GetParam());
-  }
+  bool ResolveSelectURLToConfig() override { return GetParam(); }
 
   ~SharedStorageBrowserTest() override = default;
 
  private:
-  base::test::ScopedFeatureList shared_storage_feature_;
   base::test::ScopedFeatureList fenced_frame_api_change_feature_;
 };
 
@@ -4549,37 +4526,23 @@
 
 INSTANTIATE_TEST_SUITE_P(All,
                          SharedStorageBrowserTest,
-                         testing::Combine(testing::Bool(), testing::Bool()),
-                         describe_combined_param);
+                         testing::Bool(),
+                         describe_param);
 
 class SharedStorageAllowURNsInIframesBrowserTest
     : public SharedStorageBrowserTestBase,
-      public testing::WithParamInterface<std::tuple<bool, bool>> {
+      public testing::WithParamInterface<bool> {
  public:
   SharedStorageAllowURNsInIframesBrowserTest() {
-    shared_storage_feature_.InitWithFeaturesAndParameters(
-        /*enabled_features=*/
-        {{blink::features::kSharedStorageAPI,
-          {{"SharedStorageBitBudget", base::NumberToString(kBudgetAllowed)},
-           {"SharedStorageStalenessThreshold",
-            TimeDeltaToString(base::Days(kStalenessThresholdDays))},
-           {"SharedStorageWorkletImplementationType",
-            BlinkStyleWorkletImplementation() ? "blink_style" : "legacy"}}}},
-        /*disabled_features=*/{});
-
     allow_urns_in_frames_feature_.InitAndEnableFeature(
         blink::features::kAllowURNsInIframes);
     fenced_frame_api_change_feature_.InitWithFeatureState(
         blink::features::kFencedFramesAPIChanges, ResolveSelectURLToConfig());
   }
 
-  bool ResolveSelectURLToConfig() override { return std::get<0>(GetParam()); }
-  bool BlinkStyleWorkletImplementation() override {
-    return std::get<1>(GetParam());
-  }
+  bool ResolveSelectURLToConfig() override { return GetParam(); }
 
  private:
-  base::test::ScopedFeatureList shared_storage_feature_;
   base::test::ScopedFeatureList allow_urns_in_frames_feature_;
   base::test::ScopedFeatureList fenced_frame_api_change_feature_;
 };
@@ -4617,8 +4580,8 @@
 
 INSTANTIATE_TEST_SUITE_P(All,
                          SharedStorageAllowURNsInIframesBrowserTest,
-                         testing::Combine(testing::Bool(), testing::Bool()),
-                         describe_combined_param);
+                         testing::Bool(),
+                         describe_param);
 
 class SharedStorageFencedFrameInteractionBrowserTestBase
     : public SharedStorageBrowserTestBase {
@@ -4682,29 +4645,12 @@
 };
 
 class SharedStorageFencedFrameInteractionBrowserTest
-    : public SharedStorageFencedFrameInteractionBrowserTestBase,
-      public testing::WithParamInterface<bool> {
+    : public SharedStorageFencedFrameInteractionBrowserTestBase {
  public:
-  SharedStorageFencedFrameInteractionBrowserTest() {
-    shared_storage_feature_.InitWithFeaturesAndParameters(
-        /*enabled_features=*/
-        {{blink::features::kSharedStorageAPI,
-          {{"SharedStorageBitBudget", base::NumberToString(kBudgetAllowed)},
-           {"SharedStorageStalenessThreshold",
-            TimeDeltaToString(base::Days(kStalenessThresholdDays))},
-           {"SharedStorageWorkletImplementationType",
-            BlinkStyleWorkletImplementation() ? "blink_style" : "legacy"}}}},
-        /*disabled_features=*/{});
-  }
-
   bool ResolveSelectURLToConfig() override { return true; }
-  bool BlinkStyleWorkletImplementation() override { return GetParam(); }
-
- protected:
-  base::test::ScopedFeatureList shared_storage_feature_;
 };
 
-IN_PROC_BROWSER_TEST_P(SharedStorageFencedFrameInteractionBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageFencedFrameInteractionBrowserTest,
                        SelectURL_FinishBeforeStartingFencedFrameNavigation) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -4833,7 +4779,7 @@
                                      1);
 }
 
-IN_PROC_BROWSER_TEST_P(SharedStorageFencedFrameInteractionBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageFencedFrameInteractionBrowserTest,
                        SelectURL_FinishAfterStartingFencedFrameNavigation) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -4976,7 +4922,7 @@
 
 // Tests that the URN from SelectURL() is valid in different
 // context in the page, but it's not valid in a new page.
-IN_PROC_BROWSER_TEST_P(SharedStorageFencedFrameInteractionBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageFencedFrameInteractionBrowserTest,
                        SelectURL_URNLifetime) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -5015,7 +4961,7 @@
 
 // Tests that if the URN mapping is not finished before the keep-alive timeout,
 // the mapping will be considered to be failed when the timeout is reached.
-IN_PROC_BROWSER_TEST_P(SharedStorageFencedFrameInteractionBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageFencedFrameInteractionBrowserTest,
                        SelectURL_NotFinishBeforeKeepAliveTimeout) {
   // The test assumes pages get deleted after navigation. To ensure this,
   // disable back/forward cache.
@@ -5173,7 +5119,7 @@
   EXPECT_EQ(fenced_frame_config->urn_uuid_, observed_urn_uuid.value());
 }
 
-IN_PROC_BROWSER_TEST_P(SharedStorageFencedFrameInteractionBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageFencedFrameInteractionBrowserTest,
                        SelectURL_WorkletReturnInvalidIndex) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -5284,7 +5230,7 @@
                                      1);
 }
 
-IN_PROC_BROWSER_TEST_P(SharedStorageFencedFrameInteractionBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageFencedFrameInteractionBrowserTest,
                        SelectURL_DuplicateUrl) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -5396,7 +5342,7 @@
                                      1);
 }
 
-IN_PROC_BROWSER_TEST_P(SharedStorageFencedFrameInteractionBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageFencedFrameInteractionBrowserTest,
                        FencedFrameNavigateSelf_NoBudgetWithdrawal) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -5428,7 +5374,7 @@
                                      1);
 }
 
-IN_PROC_BROWSER_TEST_P(SharedStorageFencedFrameInteractionBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageFencedFrameInteractionBrowserTest,
                        FencedFrameNavigateTop_BudgetWithdrawal) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -5465,7 +5411,7 @@
                                      1);
 }
 
-IN_PROC_BROWSER_TEST_P(
+IN_PROC_BROWSER_TEST_F(
     SharedStorageFencedFrameInteractionBrowserTest,
     FencedFrameNavigateFromParentToRegularURLAndThenOpenPopup_NoBudgetWithdrawal) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
@@ -5513,7 +5459,7 @@
                                      1);
 }
 
-IN_PROC_BROWSER_TEST_P(
+IN_PROC_BROWSER_TEST_F(
     SharedStorageFencedFrameInteractionBrowserTest,
     FencedFrameNavigateSelfAndThenNavigateTop_BudgetWithdrawal) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
@@ -5564,7 +5510,7 @@
 
 // TODO(crbug.com/1347953): Reenable this test when it is possible to create a
 // nested fenced frame with no reporting metadata, that can call _unfencedTop.
-IN_PROC_BROWSER_TEST_P(SharedStorageFencedFrameInteractionBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageFencedFrameInteractionBrowserTest,
                        DISABLED_NestedFencedFrameNavigateTop_BudgetWithdrawal) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -5605,7 +5551,7 @@
                                      1);
 }
 
-IN_PROC_BROWSER_TEST_P(
+IN_PROC_BROWSER_TEST_F(
     SharedStorageFencedFrameInteractionBrowserTest,
     NestedFencedFrameNavigateTop_BudgetWithdrawalFromTwoMetadata) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
@@ -5644,7 +5590,7 @@
                    kBudgetAllowed - 3);
 }
 
-IN_PROC_BROWSER_TEST_P(
+IN_PROC_BROWSER_TEST_F(
     SharedStorageFencedFrameInteractionBrowserTest,
     SelectURLNotAllowedInFencedFrameNotOriginatedFromSharedStorage) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
@@ -5687,7 +5633,7 @@
           "from shared storage."));
 }
 
-IN_PROC_BROWSER_TEST_P(SharedStorageFencedFrameInteractionBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageFencedFrameInteractionBrowserTest,
                        SelectURLNotAllowedInNestedFencedFrame) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -5735,7 +5681,7 @@
                   "depth (2) exceeding the maximum allowed number (1)."));
 }
 
-IN_PROC_BROWSER_TEST_P(SharedStorageFencedFrameInteractionBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageFencedFrameInteractionBrowserTest,
                        IframeInFencedFrameNavigateTop_BudgetWithdrawal) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -5776,7 +5722,7 @@
                                      1);
 }
 
-IN_PROC_BROWSER_TEST_P(SharedStorageFencedFrameInteractionBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageFencedFrameInteractionBrowserTest,
                        FencedFrame_PopupTwice_BudgetWithdrawalOnce) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -5815,7 +5761,7 @@
                                      1);
 }
 
-IN_PROC_BROWSER_TEST_P(
+IN_PROC_BROWSER_TEST_F(
     SharedStorageFencedFrameInteractionBrowserTest,
     TwoFencedFrames_DifferentURNs_EachPopupOnce_BudgetWithdrawalTwice) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
@@ -5945,7 +5891,7 @@
                                      2);
 }
 
-IN_PROC_BROWSER_TEST_P(
+IN_PROC_BROWSER_TEST_F(
     SharedStorageFencedFrameInteractionBrowserTest,
     TwoFencedFrames_SameURNs_EachPopupOnce_BudgetWithdrawalOnce) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
@@ -5985,7 +5931,7 @@
                                      1);
 }
 
-IN_PROC_BROWSER_TEST_P(SharedStorageFencedFrameInteractionBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageFencedFrameInteractionBrowserTest,
                        SelectURL_InsufficientBudget) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -6114,7 +6060,7 @@
 
 // When number of urn mappings limit has been reached, subsequent `selectURL()`
 // calls will fail.
-IN_PROC_BROWSER_TEST_P(SharedStorageFencedFrameInteractionBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageFencedFrameInteractionBrowserTest,
                        SelectURL_Fails_ExceedNumOfUrnMappingsLimit) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -6180,11 +6126,6 @@
   EXPECT_EQ(expected_error, extra_result.error);
 }
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         SharedStorageFencedFrameInteractionBrowserTest,
-                         testing::Bool(),
-                         describe_shared_storage_worklet_impl_param);
-
 class SharedStorageSelectURLNotAllowedInFencedFrameBrowserTest
     : public SharedStorageFencedFrameInteractionBrowserTest {
  public:
@@ -6193,9 +6134,7 @@
         /*enabled_features=*/
         {{blink::features::kSharedStorageAPI,
           {{"SharedStorageBitBudget", base::NumberToString(kBudgetAllowed)},
-           {"SharedStorageMaxAllowedFencedFrameDepthForSelectURL", "0"},
-           {"SharedStorageWorkletImplementationType",
-            BlinkStyleWorkletImplementation() ? "blink_style" : "legacy"}}}},
+           {"SharedStorageMaxAllowedFencedFrameDepthForSelectURL", "0"}}}},
         /*disabled_features=*/{});
   }
 
@@ -6203,7 +6142,7 @@
   base::test::ScopedFeatureList shared_storage_feature_;
 };
 
-IN_PROC_BROWSER_TEST_P(SharedStorageSelectURLNotAllowedInFencedFrameBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageSelectURLNotAllowedInFencedFrameBrowserTest,
                        SelectURLNotAllowedInFencedFrame) {
   GURL main_frame_url = https_server()->GetURL("a.test", kSimplePagePath);
 
@@ -6246,12 +6185,6 @@
                   "depth (1) exceeding the maximum allowed number (0)."));
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    SharedStorageSelectURLNotAllowedInFencedFrameBrowserTest,
-    testing::Bool(),
-    describe_shared_storage_worklet_impl_param);
-
 class SharedStorageReportEventBrowserTest
     : public SharedStorageFencedFrameInteractionBrowserTest {
   void FinishSetup() override {
@@ -6260,7 +6193,7 @@
   }
 };
 
-IN_PROC_BROWSER_TEST_P(SharedStorageReportEventBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageReportEventBrowserTest,
                        SelectURL_ReportEvent) {
   net::test_server::ControllableHttpResponse response1(
       https_server(), "/fenced_frames/report1.html");
@@ -6362,34 +6295,19 @@
                                      1);
 }
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         SharedStorageReportEventBrowserTest,
-                         testing::Bool(),
-                         describe_shared_storage_worklet_impl_param);
-
 class SharedStoragePrivateAggregationDisabledBrowserTest
-    : public SharedStorageBrowserTestBase,
-      public testing::WithParamInterface<bool> {
+    : public SharedStorageBrowserTestBase {
  public:
   SharedStoragePrivateAggregationDisabledBrowserTest() {
-    shared_storage_feature_.InitWithFeaturesAndParameters(
-        /*enabled_features=*/
-        {{blink::features::kSharedStorageAPI,
-          {{"SharedStorageWorkletImplementationType",
-            BlinkStyleWorkletImplementation() ? "blink_style" : "legacy"}}}},
-        /*disabled_features=*/{});
     private_aggregation_feature_.InitAndDisableFeature(
         blink::features::kPrivateAggregationApi);
   }
 
-  bool BlinkStyleWorkletImplementation() override { return GetParam(); }
-
  private:
-  base::test::ScopedFeatureList shared_storage_feature_;
   base::test::ScopedFeatureList private_aggregation_feature_;
 };
 
-IN_PROC_BROWSER_TEST_P(SharedStoragePrivateAggregationDisabledBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStoragePrivateAggregationDisabledBrowserTest,
                        PrivateAggregationNotDefined) {
   EXPECT_TRUE(NavigateToURL(shell(),
                             https_server()->GetURL("a.test", kSimplePagePath)));
@@ -6409,35 +6327,20 @@
             console_observer.messages()[0].log_level);
 }
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         SharedStoragePrivateAggregationDisabledBrowserTest,
-                         testing::Bool(),
-                         describe_shared_storage_worklet_impl_param);
-
 class SharedStoragePrivateAggregationDisabledForSharedStorageOnlyBrowserTest
-    : public SharedStorageBrowserTestBase,
-      public testing::WithParamInterface<bool> {
+    : public SharedStorageBrowserTestBase {
  public:
   SharedStoragePrivateAggregationDisabledForSharedStorageOnlyBrowserTest() {
-    shared_storage_feature_.InitWithFeaturesAndParameters(
-        /*enabled_features=*/
-        {{blink::features::kSharedStorageAPI,
-          {{"SharedStorageWorkletImplementationType",
-            BlinkStyleWorkletImplementation() ? "blink_style" : "legacy"}}}},
-        /*disabled_features=*/{});
     private_aggregation_feature_.InitAndEnableFeatureWithParameters(
         blink::features::kPrivateAggregationApi,
         {{"enabled_in_shared_storage", "false"}});
   }
 
-  bool BlinkStyleWorkletImplementation() override { return GetParam(); }
-
  private:
-  base::test::ScopedFeatureList shared_storage_feature_;
   base::test::ScopedFeatureList private_aggregation_feature_;
 };
 
-IN_PROC_BROWSER_TEST_P(
+IN_PROC_BROWSER_TEST_F(
     SharedStoragePrivateAggregationDisabledForSharedStorageOnlyBrowserTest,
     PrivateAggregationNotDefined) {
   EXPECT_TRUE(NavigateToURL(shell(),
@@ -6458,15 +6361,8 @@
             console_observer.messages()[0].log_level);
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    SharedStoragePrivateAggregationDisabledForSharedStorageOnlyBrowserTest,
-    testing::Bool(),
-    describe_shared_storage_worklet_impl_param);
-
 class SharedStoragePrivateAggregationEnabledBrowserTest
-    : public SharedStorageBrowserTestBase,
-      public testing::WithParamInterface<bool> {
+    : public SharedStorageBrowserTestBase {
  public:
   // TODO(alexmt): Consider factoring out along with FLEDGE definition.
   class TestPrivateAggregationManagerImpl
@@ -6481,12 +6377,6 @@
   };
 
   SharedStoragePrivateAggregationEnabledBrowserTest() {
-    shared_storage_feature_.InitWithFeaturesAndParameters(
-        /*enabled_features=*/
-        {{blink::features::kSharedStorageAPI,
-          {{"SharedStorageWorkletImplementationType",
-            BlinkStyleWorkletImplementation() ? "blink_style" : "legacy"}}}},
-        /*disabled_features=*/{});
     private_aggregation_feature_.InitAndEnableFeature(
         blink::features::kPrivateAggregationApi);
   }
@@ -6526,15 +6416,12 @@
     return *browser_client_;
   }
 
-  bool BlinkStyleWorkletImplementation() override { return GetParam(); }
-
  protected:
   url::Origin a_test_origin_;
 
  private:
   raw_ptr<PrivateAggregationHost, DanglingUntriaged> private_aggregation_host_;
 
-  base::test::ScopedFeatureList shared_storage_feature_;
   base::test::ScopedFeatureList private_aggregation_feature_;
 
   base::MockRepeatingCallback<void(AggregatableReportRequest,
@@ -6545,7 +6432,7 @@
       browser_client_;
 };
 
-IN_PROC_BROWSER_TEST_P(SharedStoragePrivateAggregationEnabledBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStoragePrivateAggregationEnabledBrowserTest,
                        BasicTest) {
   WebContentsConsoleObserver console_observer(shell()->web_contents());
 
@@ -6589,7 +6476,7 @@
   run_loop.Run();
 }
 
-IN_PROC_BROWSER_TEST_P(SharedStoragePrivateAggregationEnabledBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStoragePrivateAggregationEnabledBrowserTest,
                        RejectedTest) {
   WebContentsConsoleObserver console_observer(shell()->web_contents());
 
@@ -6614,21 +6501,15 @@
                          &out_script_url);
 
   ASSERT_EQ(1u, console_observer.messages().size());
-
-  if (BlinkStyleWorkletImplementation()) {
-    EXPECT_THAT(
-        base::UTF16ToUTF8(console_observer.messages()[0].message),
-        testing::HasSubstr(
-            "contribution['bucket'] is negative or does not fit in 128 bits"));
-  } else {
-    EXPECT_EQ("TypeError: BigInt must be non-negative",
-              base::UTF16ToUTF8(console_observer.messages()[0].message));
-  }
+  EXPECT_THAT(
+      base::UTF16ToUTF8(console_observer.messages()[0].message),
+      testing::HasSubstr(
+          "contribution['bucket'] is negative or does not fit in 128 bits"));
   EXPECT_EQ(blink::mojom::ConsoleMessageLevel::kError,
             console_observer.messages()[0].log_level);
 }
 
-IN_PROC_BROWSER_TEST_P(SharedStoragePrivateAggregationEnabledBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStoragePrivateAggregationEnabledBrowserTest,
                        MultipleRequests) {
   WebContentsConsoleObserver console_observer(shell()->web_contents());
 
@@ -6675,7 +6556,7 @@
   run_loop.Run();
 }
 
-IN_PROC_BROWSER_TEST_P(SharedStoragePrivateAggregationEnabledBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStoragePrivateAggregationEnabledBrowserTest,
                        PrivateAggregationPermissionsPolicyNone) {
   GURL url = https_server()->GetURL(
       "a.test",
@@ -6713,7 +6594,7 @@
 }
 
 // This is a regression test for crbug.com/1428110.
-IN_PROC_BROWSER_TEST_P(SharedStoragePrivateAggregationEnabledBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStoragePrivateAggregationEnabledBrowserTest,
                        SimultaneousOperationsReportsArentBatchedTogether) {
   WebContentsConsoleObserver console_observer(shell()->web_contents());
 
@@ -6779,26 +6660,11 @@
   EXPECT_EQ(num_one_contribution_reports, 1);
 }
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         SharedStoragePrivateAggregationEnabledBrowserTest,
-                         testing::Bool(),
-                         describe_shared_storage_worklet_impl_param);
-
 class SharedStorageSelectURLLimitBrowserTest
     : public SharedStorageBrowserTestBase,
-      public testing::WithParamInterface<std::tuple<bool, bool, bool>> {
+      public testing::WithParamInterface<std::tuple<bool, bool>> {
  public:
   SharedStorageSelectURLLimitBrowserTest() {
-    shared_storage_feature_.InitWithFeaturesAndParameters(
-        /*enabled_features=*/
-        {{blink::features::kSharedStorageAPI,
-          {{"SharedStorageBitBudget", base::NumberToString(kBudgetAllowed)},
-           {"SharedStorageStalenessThreshold",
-            TimeDeltaToString(base::Days(kStalenessThresholdDays))},
-           {"SharedStorageWorkletImplementationType",
-            BlinkStyleWorkletImplementation() ? "blink_style" : "legacy"}}}},
-        /*disabled_features=*/{});
-
     if (LimitSelectURLCalls()) {
       select_url_limit_feature_list_.InitWithFeaturesAndParameters(
           /*enabled_features=*/
@@ -6821,10 +6687,6 @@
 
   bool ResolveSelectURLToConfig() override { return std::get<1>(GetParam()); }
 
-  bool BlinkStyleWorkletImplementation() override {
-    return std::get<2>(GetParam());
-  }
-
   // Precondition: `addModule('shared_storage/simple_module.js')` has been
   // called in the main frame.
   void RunSuccessfulSelectURLInMainFrame(
@@ -6951,23 +6813,21 @@
     return result;
   }
 
-  base::test::ScopedFeatureList shared_storage_feature_;
   base::test::ScopedFeatureList select_url_limit_feature_list_;
   base::test::ScopedFeatureList fenced_frame_api_change_feature_;
 };
 
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    SharedStorageSelectURLLimitBrowserTest,
-    testing::Combine(testing::Bool(), testing::Bool(), testing::Bool()),
-    [](const auto& info) {
-      return base::StrCat({"LimitSelectURLCalls",
-                           std::get<0>(info.param) ? "Enabled" : "Disabled",
-                           "_ResolveSelectURLTo",
-                           std::get<1>(info.param) ? "Config" : "URN",
-                           std::get<2>(info.param) ? "_BlinkStyle" : "_Legacy",
-                           "WorkletImplementation"});
-    });
+INSTANTIATE_TEST_SUITE_P(All,
+                         SharedStorageSelectURLLimitBrowserTest,
+                         testing::Combine(testing::Bool(), testing::Bool()),
+                         [](const auto& info) {
+                           return base::StrCat(
+                               {"LimitSelectURLCalls",
+                                std::get<0>(info.param) ? "Enabled"
+                                                        : "Disabled",
+                                "_ResolveSelectURLTo",
+                                std::get<1>(info.param) ? "Config" : "URN"});
+                         });
 
 IN_PROC_BROWSER_TEST_P(SharedStorageSelectURLLimitBrowserTest,
                        SelectURL_MainFrame_SameEntropy_OriginLimitReached) {
@@ -7416,27 +7276,15 @@
 }
 
 class SharedStorageContextBrowserTest
-    : public SharedStorageFencedFrameInteractionBrowserTestBase,
-      public testing::WithParamInterface<bool> {
+    : public SharedStorageFencedFrameInteractionBrowserTestBase {
  public:
   SharedStorageContextBrowserTest() {
-    shared_storage_feature_.InitWithFeaturesAndParameters(
-        /*enabled_features=*/
-        {{blink::features::kSharedStorageAPI,
-          {{"SharedStorageBitBudget", base::NumberToString(kBudgetAllowed)},
-           {"SharedStorageStalenessThreshold",
-            TimeDeltaToString(base::Days(kStalenessThresholdDays))},
-           {"SharedStorageWorkletImplementationType",
-            BlinkStyleWorkletImplementation() ? "blink_style" : "legacy"}}}},
-        /*disabled_features=*/{});
     fenced_frame_api_change_feature_.InitAndEnableFeature(
         blink::features::kFencedFramesAPIChanges);
   }
 
   ~SharedStorageContextBrowserTest() override = default;
 
-  bool BlinkStyleWorkletImplementation() override { return GetParam(); }
-
   void GenerateFencedFrameConfig(std::string hostname,
                                  bool keep_alive_after_operation = true) {
     EXPECT_TRUE(ExecJs(shell(), JsReplace("window.keepWorklet = $1;",
@@ -7495,14 +7343,13 @@
   }
 
  private:
-  base::test::ScopedFeatureList shared_storage_feature_;
   base::test::ScopedFeatureList fenced_frame_api_change_feature_;
 };
 
 // Tests that `blink::FencedFrameConfig::context` can be set and then accessed
 // via `sharedStorage.context`. The context must be set prior to fenced frame
 // navigation to the config.
-IN_PROC_BROWSER_TEST_P(SharedStorageContextBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageContextBrowserTest,
                        EmbedderContextSetBeforeNavigation_Defined) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -7576,7 +7423,7 @@
 
 // Tests that `blink::FencedFrameConfig::context`, when not set and then
 // accessed via `sharedStorage.context`, will be undefined.
-IN_PROC_BROWSER_TEST_P(SharedStorageContextBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageContextBrowserTest,
                        EmbedderContextSetAfterNavigation_Undefined) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -7620,7 +7467,7 @@
 // Tests that `blink::FencedFrameConfig::context`, when set after a first
 // navigation to the config and before a second fenced frame navigation to the
 // same config, is updated, as seen via `sharedStorage.context`.
-IN_PROC_BROWSER_TEST_P(SharedStorageContextBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageContextBrowserTest,
                        EmbedderContextNavigateTwice_ContextUpdated) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -7681,7 +7528,7 @@
 // Tests that `blink::FencedFrameConfig::context` can be set and then accessed
 // via `sharedStorage.context`, but that any context string exceeding the length
 // limit is truncated.
-IN_PROC_BROWSER_TEST_P(SharedStorageContextBrowserTest,
+IN_PROC_BROWSER_TEST_F(SharedStorageContextBrowserTest,
                        EmbedderContextExceedsLengthLimit_Truncated) {
   GURL main_url = https_server()->GetURL("a.test", kSimplePagePath);
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -7720,9 +7567,4 @@
             base::UTF16ToUTF8(console_observer.messages().back().message));
 }
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         SharedStorageContextBrowserTest,
-                         testing::Bool(),
-                         describe_shared_storage_worklet_impl_param);
-
 }  // namespace content
diff --git a/content/common/service_worker/race_network_request_url_loader_client.cc b/content/common/service_worker/race_network_request_url_loader_client.cc
index b49bff75..a7ecaf7 100644
--- a/content/common/service_worker/race_network_request_url_loader_client.cc
+++ b/content/common/service_worker/race_network_request_url_loader_client.cc
@@ -103,13 +103,13 @@
       sender: "ServiceWorkerRaceNetworkRequest"
       description:
         "This request is issued by a navigation to fetch the content of the "
-        "page that is being navigated to, in the case where a service worker "
-        "has been registered for the page and the "
-        "ServiceWorkerBypassFetchHandler feature and the RaceNetworkRequest "
-        "param are enabled."
+        "page that is being navigated to, or by a renderer to fetch "
+        "subresources in the case where a service worker has been registered "
+        "for the page and the ServiceWorkerBypassFetchHandler feature and the "
+        "RaceNetworkRequest param are enabled."
       trigger:
         "Navigating Chrome (by clicking on a link, bookmark, history item, "
-        "using session restore, etc)."
+        "using session restore, etc) and subsequent resource loading."
       data:
         "Arbitrary site-controlled data can be included in the URL, HTTP "
         "headers, and request body. Requests may include cookies and "
@@ -123,7 +123,7 @@
       user_data {
         type: ARBITRARY_DATA
       }
-      last_reviewed: "2023-03-11"
+      last_reviewed: "2023-03-22"
     }
     policy {
       cookies_allowed: YES
diff --git a/content/gpu/BUILD.gn b/content/gpu/BUILD.gn
index 9f5f303..93559f6 100644
--- a/content/gpu/BUILD.gn
+++ b/content/gpu/BUILD.gn
@@ -76,6 +76,8 @@
     "//services/service_manager/public/mojom",
     "//services/tracing/public/cpp",
     "//services/viz/privileged/mojom",
+    "//services/webnn",
+    "//services/webnn/public/mojom",
     "//skia",
     "//third_party/angle:angle_gpu_info_util",
     "//ui/gfx/ipc",
diff --git a/content/gpu/DEPS b/content/gpu/DEPS
index b131fcc..de996eb 100644
--- a/content/gpu/DEPS
+++ b/content/gpu/DEPS
@@ -12,6 +12,7 @@
   "+services/tracing/public/cpp",
   "+services/viz/privileged/mojom",
   "+services/viz/service",
+  "+services/webnn",
   "+sandbox",
   "+skia",
 ]
diff --git a/content/gpu/gpu_child_thread_receiver_bindings.cc b/content/gpu/gpu_child_thread_receiver_bindings.cc
index ec164289..00c2a6a 100644
--- a/content/gpu/gpu_child_thread_receiver_bindings.cc
+++ b/content/gpu/gpu_child_thread_receiver_bindings.cc
@@ -21,6 +21,13 @@
 #include "media/mojo/mojom/media_service.mojom.h"
 #endif
 
+#if !BUILDFLAG(IS_CHROMEOS)
+#include "base/task/single_thread_task_runner.h"
+#include "base/task/thread_pool.h"
+#include "services/webnn/public/mojom/webnn_service.mojom.h"
+#include "services/webnn/webnn_service.h"
+#endif
+
 namespace content {
 
 void GpuChildThread::BindServiceInterface(
@@ -52,6 +59,22 @@
     return;
   }
 #endif
+
+#if !BUILDFLAG(IS_CHROMEOS)
+  if (auto webnn_receiver = receiver.As<webnn::mojom::WebNNService>()) {
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+        base::SingleThreadTaskRunner::GetCurrentDefault();
+    task_runner->PostTask(
+        FROM_HERE, base::BindOnce(
+                       [](mojo::PendingReceiver<webnn::mojom::WebNNService>
+                              webnn_receiver) {
+                         static base::NoDestructor<webnn::WebNNService> service{
+                             std::move(webnn_receiver)};
+                       },
+                       std::move(webnn_receiver)));
+    return;
+  }
+#endif
 }
 
 }  // namespace content
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
index 7af9fa0..a399e1b 100644
--- a/content/gpu/gpu_main.cc
+++ b/content/gpu/gpu_main.cc
@@ -62,6 +62,7 @@
 #include "ui/events/platform/platform_event_source.h"
 #include "ui/gfx/switches.h"
 #include "ui/gl/gl_context.h"
+#include "ui/gl/gl_features.h"
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_surface.h"
 #include "ui/gl/gl_switches.h"
@@ -98,6 +99,7 @@
 #if BUILDFLAG(IS_MAC)
 #include "base/message_loop/message_pump_mac.h"
 #include "components/metal_util/device_removal.h"
+#include "gpu/ipc/service/built_in_shader_cache_loader.h"
 #include "media/gpu/mac/vt_video_decode_accelerator_mac.h"
 #include "sandbox/mac/seatbelt.h"
 #endif
@@ -189,6 +191,14 @@
 #endif
 };
 
+void LoadMetalShaderCacheIfNecessary() {
+#if BUILDFLAG(IS_MAC)
+  if (base::FeatureList::IsEnabled(features::kUseBuiltInMetalShaderCache)) {
+    gpu::BuiltInShaderCacheLoader::StartLoading();
+  }
+#endif
+}
+
 }  // namespace
 
 // Main function for starting the Gpu process.
@@ -201,6 +211,10 @@
 
   const base::CommandLine& command_line = *parameters.command_line;
 
+  // Start this early on as it reads from a file (in the background) and full
+  // startup is gated by this completing.
+  LoadMetalShaderCacheIfNecessary();
+
   gpu::GpuPreferences gpu_preferences;
   if (command_line.HasSwitch(switches::kGpuPreferences)) {
     std::string value =
diff --git a/content/public/test/accessibility_notification_waiter.cc b/content/public/test/accessibility_notification_waiter.cc
index 9c94cc5..c11bd0e 100644
--- a/content/public/test/accessibility_notification_waiter.cc
+++ b/content/public/test/accessibility_notification_waiter.cc
@@ -165,7 +165,8 @@
   if (event_to_wait_for_ == ax::mojom::Event::kNone ||
       event_to_wait_for_ == event_type) {
     event_target_id_ = event_target_id;
-    event_render_frame_host_ = rfhi;
+    event_browser_accessibility_manager_ =
+        rfhi ? rfhi->GetOrCreateBrowserAccessibilityManager() : nullptr;
     notification_received_ = true;
 
     loop_runner_quit_closure_.Run();
@@ -205,7 +206,8 @@
 
   if (generated_event_to_wait_for_ == event) {
     event_target_id_ = event_target_id;
-    event_render_frame_host_ = render_frame_host;
+    event_browser_accessibility_manager_ =
+        render_frame_host->GetOrCreateBrowserAccessibilityManager();
     notification_received_ = true;
     loop_runner_quit_closure_.Run();
   }
diff --git a/content/public/test/accessibility_notification_waiter.h b/content/public/test/accessibility_notification_waiter.h
index 43268af0..a2721ff 100644
--- a/content/public/test/accessibility_notification_waiter.h
+++ b/content/public/test/accessibility_notification_waiter.h
@@ -22,6 +22,7 @@
 
 namespace content {
 
+class BrowserAccessibilityManager;
 class RenderFrameHost;
 class RenderFrameHostImpl;
 class WebContents;
@@ -70,9 +71,9 @@
   bool notification_received() const { return notification_received_; }
 
   // After WaitForNotification returns, use this to retrieve the
-  // RenderFrameHostImpl that was the target of the event.
-  RenderFrameHostImpl* event_render_frame_host() const {
-    return event_render_frame_host_;
+  // `BrowserAccessibilityManager` that was the target of the event.
+  BrowserAccessibilityManager* event_browser_accessibility_manager() const {
+    return event_browser_accessibility_manager_;
   }
 
   // WebContentsObserver override:
@@ -132,8 +133,8 @@
   std::unique_ptr<base::RunLoop> loop_runner_;
   base::RepeatingClosure loop_runner_quit_closure_;
   int event_target_id_ = 0;
-  raw_ptr<RenderFrameHostImpl, DanglingUntriaged> event_render_frame_host_ =
-      nullptr;
+  raw_ptr<BrowserAccessibilityManager, DanglingUntriaged>
+      event_browser_accessibility_manager_ = nullptr;
   bool notification_received_ = false;
 
   base::WeakPtrFactory<AccessibilityNotificationWaiter> weak_factory_{this};
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 3ec54c2..487c06d 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -259,7 +259,6 @@
     "//content/gpu:gpu_sources",
     "//content/public/child:child_sources",
     "//content/services/auction_worklet:auction_worklet",
-    "//content/services/shared_storage_worklet",
     "//crypto",
     "//device/base/synchronization",
     "//device/gamepad/public/cpp:shared_with_blink",
diff --git a/content/renderer/DEPS b/content/renderer/DEPS
index 5b7bdf0..f68ea733 100644
--- a/content/renderer/DEPS
+++ b/content/renderer/DEPS
@@ -19,7 +19,6 @@
   "+content/public/child",
   "+content/public/renderer",
   "+content/child",
-  "+content/services/shared_storage_worklet",
   "+content/services/auction_worklet",
   "+device/base/synchronization",
   "+device/gamepad/public/cpp",
diff --git a/content/renderer/agent_scheduling_group.cc b/content/renderer/agent_scheduling_group.cc
index 909157d..5f8bd24 100644
--- a/content/renderer/agent_scheduling_group.cc
+++ b/content/renderer/agent_scheduling_group.cc
@@ -19,7 +19,6 @@
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_thread_impl.h"
-#include "content/services/shared_storage_worklet/shared_storage_worklet_service_impl.h"
 #include "ipc/ipc_channel_mojo.h"
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_sync_channel.h"
@@ -96,50 +95,6 @@
   void OnDestruct() override { delete this; }
 };
 
-// A thread for running shared storage worklet operations. It hosts a worklet
-// environment belonging to one Document. The object owns itself, cleaning up
-// when the worklet has shut down.
-class LegacySelfOwnedSharedStorageWorkletThread {
- public:
-  LegacySelfOwnedSharedStorageWorkletThread(
-      scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
-      mojo::PendingReceiver<blink::mojom::SharedStorageWorkletService> receiver)
-      : main_thread_runner_(std::move(main_thread_runner)) {
-    DCHECK(main_thread_runner_->BelongsToCurrentThread());
-
-    auto disconnect_handler = base::BindPostTask(
-        main_thread_runner_,
-        base::BindOnce(&LegacySelfOwnedSharedStorageWorkletThread::
-                           OnSharedStorageWorkletServiceDestroyed,
-                       weak_factory_.GetWeakPtr()));
-
-    auto task_runner = base::ThreadPool::CreateSingleThreadTaskRunner(
-        {base::TaskPriority::BEST_EFFORT,
-         base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-        base::SingleThreadTaskRunnerThreadMode::DEDICATED);
-
-    // Initialize the worklet service in a new thread.
-    worklet_thread_ = base::SequenceBound<
-        shared_storage_worklet::SharedStorageWorkletServiceImpl>(
-        task_runner, std::move(receiver), std::move(disconnect_handler));
-  }
-
- private:
-  void OnSharedStorageWorkletServiceDestroyed() {
-    DCHECK(main_thread_runner_->BelongsToCurrentThread());
-    worklet_thread_.Reset();
-    delete this;
-  }
-
-  scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner_;
-
-  base::SequenceBound<shared_storage_worklet::SharedStorageWorkletServiceImpl>
-      worklet_thread_;
-
-  base::WeakPtrFactory<LegacySelfOwnedSharedStorageWorkletThread> weak_factory_{
-      this};
-};
-
 }  // namespace
 
 AgentSchedulingGroup::ReceiverData::ReceiverData(
@@ -451,16 +406,8 @@
 
 void AgentSchedulingGroup::CreateSharedStorageWorkletService(
     mojo::PendingReceiver<blink::mojom::SharedStorageWorkletService> receiver) {
-  switch (blink::features::kSharedStorageWorkletImplementationType.Get()) {
-    case blink::features::SharedStorageWorkletImplementationType::kLegacy:
-      new LegacySelfOwnedSharedStorageWorkletThread(
-          agent_group_scheduler_->DefaultTaskRunner(), std::move(receiver));
-      break;
-    case blink::features::SharedStorageWorkletImplementationType::kBlinkStyle:
-      blink::WebSharedStorageWorkletThread::Start(
-          agent_group_scheduler_->DefaultTaskRunner(), std::move(receiver));
-      break;
-  }
+  blink::WebSharedStorageWorkletThread::Start(
+      agent_group_scheduler_->DefaultTaskRunner(), std::move(receiver));
 }
 
 void AgentSchedulingGroup::BindAssociatedInterfaces(
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.cc b/content/renderer/service_worker/service_worker_subresource_loader.cc
index e33a460..49f1f8c3 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader.cc
@@ -6,14 +6,19 @@
 
 #include "base/atomic_sequence_num.h"
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
+#include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notreached.h"
 #include "base/strings/strcat.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/trace_event/trace_event.h"
 #include "content/common/fetch/fetch_request_type_converters.h"
+#include "content/common/service_worker/race_network_request_url_loader_client.h"
+#include "content/public/common/content_features.h"
 #include "content/renderer/renderer_blink_platform_impl.h"
 #include "content/renderer/service_worker/controller_service_worker_connector.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
@@ -21,6 +26,7 @@
 #include "net/url_request/redirect_util.h"
 #include "net/url_request/url_request.h"
 #include "services/network/public/cpp/record_ontransfersizeupdate_utils.h"
+#include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/mojom/early_hints.mojom.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
@@ -155,7 +161,6 @@
   base::UmaHistogramBoolean(kMetricsName, true);
   return timing;
 }
-
 }  // namespace
 
 // A ServiceWorkerStreamCallback implementation which waits for completion of
@@ -186,6 +191,56 @@
   mojo::Receiver<blink::mojom::ServiceWorkerStreamCallback> receiver_;
 };
 
+bool ServiceWorkerSubresourceLoader::MaybeStartRaceNetworkRequest() {
+  if (!base::FeatureList::IsEnabled(
+          features::kServiceWorkerBypassFetchHandler)) {
+    return false;
+  }
+  if (features::kServiceWorkerBypassFetchHandlerTarget.Get() !=
+      features::ServiceWorkerBypassFetchHandlerTarget::
+          kAllWithRaceNetworkRequest) {
+    return false;
+  }
+
+  // If the fetch event is restarted for some reason, stop dispatching
+  // RaceNetworkRequest to avoid making the race condition complex.
+  if (fetch_request_restarted_) {
+    return false;
+  }
+
+  // RaceNetworkRequest only supports GET method.
+  if (resource_request_.method != net::HttpRequestHeaders::kGetMethod) {
+    return false;
+  }
+
+  DCHECK(!race_network_request_loader_client_);
+  race_network_request_loader_client_.emplace(resource_request_,
+                                              weak_factory_.GetWeakPtr());
+  mojo::PendingRemote<network::mojom::URLLoaderClient> client_to_pass;
+  race_network_request_loader_client_->Bind(&client_to_pass);
+
+  scoped_refptr<network::SharedURLLoaderFactory> factory =
+      network::SharedURLLoaderFactory::Create(fallback_factory_->Clone());
+  mojo::PendingRemote<network::mojom::URLLoader> url_loader;
+
+  factory->CreateLoaderAndStart(
+      url_loader.InitWithNewPipeAndPassReceiver(), request_id_,
+      network::mojom::kURLLoadOptionNone, resource_request_,
+      std::move(client_to_pass),
+      net::MutableNetworkTrafficAnnotationTag(
+          ServiceWorkerRaceNetworkRequestURLLoaderClient::
+              NetworkTrafficAnnotationTag()));
+
+  // Keep the URL loader related assets alive while the FetchEvent is ongoing
+  // in the service worker.
+  DCHECK(!race_network_request_url_loader_factory_);
+  DCHECK(!race_network_request_url_loader_);
+  race_network_request_url_loader_factory_ = std::move(factory);
+  race_network_request_url_loader_ = std::move(url_loader);
+
+  return true;
+}
+
 // ServiceWorkerSubresourceLoader -------------------------------------------
 
 ServiceWorkerSubresourceLoader::ServiceWorkerSubresourceLoader(
@@ -308,6 +363,9 @@
     }
   }
 
+  // Dispatch RaceNetworkRequest if enabled.
+  did_start_race_network_request_ = MaybeStartRaceNetworkRequest();
+
   DispatchFetchEventForSubresource();
 }
 
@@ -369,7 +427,7 @@
       // TODO(falken): This seems racy. respondWith() may have been called
       // already and we could have an outstanding stream or blob in progress,
       // and we might hit CommitCompleted() twice once that settles.
-      CommitCompleted(net::ERR_FAILED);
+      CommitCompleted(net::ERR_FAILED, "Fetch event dispatch did not complete");
   }
 }
 
@@ -383,7 +441,13 @@
   if (fetch_request_restarted_) {
     SettleFetchEventDispatch(
         blink::ServiceWorkerStatusCode::kErrorStartWorkerFailed);
-    CommitCompleted(net::ERR_FAILED);
+    // If the fetch request is already handled by RaceNetworkRequest, no need to
+    // call CommitCompleted here.
+    if (fetch_response_from() == FetchResponseFrom::kWithoutServiceWorker) {
+      return;
+    }
+    set_fetch_response_from(FetchResponseFrom::kServiceWorker);
+    CommitCompleted(net::ERR_FAILED, "Disconnected before completed");
     return;
   }
   fetch_request_restarted_ = true;
@@ -449,6 +513,17 @@
                           TRACE_ID_LOCAL(request_id_)),
       TRACE_EVENT_FLAG_FLOW_IN);
 
+  // If the fetch response is handled by RaceNetworkRequest, the new fallback
+  // request is not dispatched. OnFallback doesn't delete the instance and flip
+  // the status. Those are handled in the process of RaceNetworkRequest
+  // handling.
+  // TODO(crbug.com/1432075) Fallback response shoudld be handled as a fallback.
+  // The response from RaceNetworkRequest is currently handled by the code path
+  // for the non-fallback case.
+  if (fetch_response_from() == FetchResponseFrom::kWithoutServiceWorker) {
+    return;
+  }
+
   // Hand over to the network loader.
   mojo::PendingRemote<network::mojom::URLLoaderClient> client;
   auto client_impl = std::make_unique<HeaderRewritingURLLoaderClient>(
@@ -497,10 +572,16 @@
 void ServiceWorkerSubresourceLoader::StartResponse(
     blink::mojom::FetchAPIResponsePtr response,
     blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream) {
+  // If the response already came from RaceNetworkRequest, do nothing.
+  if (fetch_response_from() == FetchResponseFrom::kWithoutServiceWorker) {
+    return;
+  }
+  set_fetch_response_from(FetchResponseFrom::kServiceWorker);
+
   // A response with status code 0 is Blink telling us to respond with network
   // error.
   if (response->status_code == 0) {
-    CommitCompleted(net::ERR_FAILED);
+    CommitCompleted(net::ERR_FAILED, "Zero response status");
     return;
   }
 
@@ -522,7 +603,7 @@
       resource_request_, *response_head_);
   if (redirect_info_) {
     if (redirect_limit_-- == 0) {
-      CommitCompleted(net::ERR_TOO_MANY_REDIRECTS);
+      CommitCompleted(net::ERR_TOO_MANY_REDIRECTS, "Too many redirects");
       return;
     }
     response_head_->encoded_data_length = 0;
@@ -533,7 +614,7 @@
   }
 
   // We have a non-redirect response. Send the headers to the client.
-  CommitResponseHeaders();
+  CommitResponseHeaders(response_head_);
 
   bool body_stream_is_valid =
       !body_as_stream.is_null() && body_as_stream->stream.is_valid();
@@ -567,7 +648,7 @@
     // start buffering in the pipe while the side data is read.
     int error = StartBlobReading(&data_pipe);
     if (error != net::OK) {
-      CommitCompleted(error);
+      CommitCompleted(error, "Failed to read blob body");
       return;
     }
   }
@@ -594,17 +675,24 @@
                             absl::optional<mojo_base::BigBuffer>());
 }
 
-void ServiceWorkerSubresourceLoader::CommitResponseHeaders() {
-  TransitionToStatus(Status::kSentHeader);
+void ServiceWorkerSubresourceLoader::CommitResponseHeaders(
+    const network::mojom::URLResponseHeadPtr& response_head) {
   DCHECK(url_loader_client_.is_bound());
+  TRACE_EVENT_WITH_FLOW2(
+      "ServiceWorker", "ServiceWorkerSubesourceLoader::CommitResponseHeaders",
+      this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+      "response_code", response_head->headers->response_code(), "status_text",
+      response_head->headers->GetStatusText());
+  TransitionToStatus(Status::kSentHeader);
 }
 
 void ServiceWorkerSubresourceLoader::CommitResponseBody(
+    const network::mojom::URLResponseHeadPtr& response_head,
     mojo::ScopedDataPipeConsumerHandle response_body,
     absl::optional<mojo_base::BigBuffer> cached_metadata) {
   TransitionToStatus(Status::kSentBody);
   // TODO(kinuko): Fill the ssl_info.
-  url_loader_client_->OnReceiveResponse(response_head_.Clone(),
+  url_loader_client_->OnReceiveResponse(response_head.Clone(),
                                         std::move(response_body),
                                         std::move(cached_metadata));
 }
@@ -614,25 +702,38 @@
   mojo::ScopedDataPipeConsumerHandle consumer_handle;
   if (CreateDataPipe(nullptr, producer_handle, consumer_handle) !=
       MOJO_RESULT_OK) {
-    CommitCompleted(net::ERR_INSUFFICIENT_RESOURCES);
+    CommitCompleted(net::ERR_INSUFFICIENT_RESOURCES,
+                    "Can't create empty data pipe");
     return;
   }
 
   producer_handle.reset();  // The data pipe is empty.
-  CommitResponseBody(std::move(consumer_handle), absl::nullopt);
-  CommitCompleted(net::OK);
+  CommitResponseBody(response_head_, std::move(consumer_handle), absl::nullopt);
+  CommitCompleted(net::OK, "No body exists");
 }
 
-void ServiceWorkerSubresourceLoader::CommitCompleted(int error_code) {
-  TRACE_EVENT_WITH_FLOW1(
+void ServiceWorkerSubresourceLoader::CommitCompleted(int error_code,
+                                                     const char* reason) {
+  TRACE_EVENT_WITH_FLOW2(
       "ServiceWorker", "ServiceWorkerSubresourceLoader::CommitCompleted",
       TRACE_ID_WITH_SCOPE(kServiceWorkerSubresourceLoaderScope,
                           TRACE_ID_LOCAL(request_id_)),
-      TRACE_EVENT_FLAG_FLOW_IN, "error_code", net::ErrorToString(error_code));
+      TRACE_EVENT_FLAG_FLOW_IN, "error_code", net::ErrorToString(error_code),
+      "reason", TRACE_STR_COPY(reason));
 
   TransitionToStatus(Status::kCompleted);
   if (error_code == net::OK) {
-    RecordTimingMetricsForFetchHandlerHandledCase();
+    switch (fetch_response_from()) {
+      case FetchResponseFrom::kNoResponseYet:
+        NOTREACHED();
+        break;
+      case FetchResponseFrom::kServiceWorker:
+        RecordTimingMetricsForFetchHandlerHandledCase();
+        break;
+      case FetchResponseFrom::kWithoutServiceWorker:
+        RecordTimingMetricsForRaceNetworkReqestCase();
+        break;
+    }
   }
 
   DCHECK(url_loader_client_.is_bound());
@@ -658,6 +759,7 @@
   RecordWorkerReadyToFetchHandlerEndTiming(response_head_->load_timing);
   RecordFetchHandlerEndToResponseReceivedTiming(response_head_->load_timing);
   RecordResponseReceivedToCompletedTiming(response_head_->load_timing);
+  RecordStartToCompletedTiming(response_head_->load_timing);
 }
 
 void ServiceWorkerSubresourceLoader::
@@ -669,11 +771,22 @@
   RecordForwardServiceWorkerToWorkerReadyTiming(response_head_->load_timing);
   RecordWorkerReadyToFetchHandlerEndTiming(response_head_->load_timing);
   RecordFetchHandlerEndToFallbackNetworkTiming(response_head_->load_timing);
+  RecordStartToCompletedTiming(response_head_->load_timing);
+}
+
+void ServiceWorkerSubresourceLoader::
+    RecordTimingMetricsForRaceNetworkReqestCase() {
+  DCHECK(race_network_request_loader_client_);
+  if (!InitRecordTimingMetricsIfEligible(
+          race_network_request_loader_client_->GetLoadTimingInfo())) {
+    return;
+  }
+  RecordStartToCompletedTiming(
+      race_network_request_loader_client_->GetLoadTimingInfo());
 }
 
 bool ServiceWorkerSubresourceLoader::InitRecordTimingMetricsIfEligible(
     const net::LoadTimingInfo& load_timing) {
-  DCHECK(fetch_event_timing_);
   // |devtools_request_id| is set when DevTools is attached. Don't record
   // metrics when DevTools is attached to reduce noise.
   if (resource_request_.devtools_request_id.has_value()) {
@@ -689,7 +802,7 @@
 
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP1(
       "ServiceWorker", "ServiceWorker.LoadTiming.Subresource", this,
-      load_timing.service_worker_start_time, "url", resource_request_.url);
+      load_timing.request_start, "url", resource_request_.url);
   TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
       "ServiceWorker", "ServiceWorker.LoadTiming.Subresource", this,
       completion_time_);
@@ -785,6 +898,13 @@
       completion_time_);
 }
 
+void ServiceWorkerSubresourceLoader::RecordStartToCompletedTiming(
+    const net::LoadTimingInfo& load_timing) {
+  base::UmaHistogramMediumTimes(
+      "ServiceWorker.LoadTiming.Subresource.StartToCompleted",
+      completion_time_ - load_timing.request_start);
+}
+
 // ServiceWorkerSubresourceLoader: URLLoader implementation -----------------
 
 void ServiceWorkerSubresourceLoader::FollowRedirect(
@@ -804,7 +924,7 @@
   // https://crbug.com/1162035
   if (!redirect_info_) {
     if (status_ != Status::kCompleted)
-      CommitCompleted(net::ERR_INVALID_REDIRECT);
+      CommitCompleted(net::ERR_INVALID_REDIRECT, "Invalid redirect");
     return;
   }
 
@@ -841,6 +961,7 @@
   TransitionToStatus(Status::kNotStarted);
   redirect_info_.reset();
   response_callback_receiver_.reset();
+  reset_fetch_response_from();
   StartRequest(resource_request_);
 }
 
@@ -885,7 +1006,7 @@
   side_data_reading_complete_ = true;
 
   DCHECK(data_pipe.is_valid());
-  CommitResponseBody(std::move(data_pipe), std::move(metadata));
+  CommitResponseBody(response_head_, std::move(data_pipe), std::move(metadata));
 
   // If the blob reading completed before the side data reading, then we
   // must manually finalize the blob reading now.
@@ -909,7 +1030,7 @@
   // Abort immediately on error.
   if (!side_data_reading_complete_ && net_error == net::OK)
     return;
-  CommitCompleted(net_error);
+  CommitCompleted(net_error, "Body reading completed");
 }
 
 // ServiceWorkerSubresourceLoaderFactory ------------------------------------
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.h b/content/renderer/service_worker/service_worker_subresource_loader.h
index 6355ef28..a9dabbae 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader.h
+++ b/content/renderer/service_worker/service_worker_subresource_loader.h
@@ -10,6 +10,8 @@
 #include "base/scoped_observation.h"
 #include "base/task/sequenced_task_runner.h"
 #include "content/common/content_export.h"
+#include "content/common/service_worker/race_network_request_url_loader_client.h"
+#include "content/common/service_worker/service_worker_resource_loader.h"
 #include "content/renderer/service_worker/controller_service_worker_connector.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -21,6 +23,7 @@
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/public/mojom/url_response_head.mojom-forward.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom-forward.h"
@@ -45,7 +48,8 @@
 class CONTENT_EXPORT ServiceWorkerSubresourceLoader
     : public network::mojom::URLLoader,
       public blink::mojom::ServiceWorkerFetchResponseCallback,
-      public ControllerServiceWorkerConnector::Observer {
+      public ControllerServiceWorkerConnector::Observer,
+      public ServiceWorkerResourceLoader {
  public:
   // See the comments for ServiceWorkerSubresourceLoaderFactory's ctor (below)
   // to see how each parameter is used.
@@ -136,20 +140,23 @@
                                  absl::optional<mojo_base::BigBuffer> metadata);
   void OnBodyReadingComplete(int net_error);
 
-  void CommitResponseHeaders();
+  void CommitResponseHeaders(
+      const network::mojom::URLResponseHeadPtr&) override;
 
-  // Calls url_loader_client_->OnReceiveResponse() with |response_head_|,
+  // Calls url_loader_client_->OnReceiveResponse() with given |response_head|,
   // |response_body|, and |cached_metadata|.
-  void CommitResponseBody(mojo::ScopedDataPipeConsumerHandle response_body,
-                          absl::optional<mojo_base::BigBuffer> cached_metadata);
+  void CommitResponseBody(
+      const network::mojom::URLResponseHeadPtr& response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
+      absl::optional<mojo_base::BigBuffer> cached_metadata) override;
 
   // Creates and sends an empty response's body with the net::OK status.
   // Sends net::ERR_INSUFFICIENT_RESOURCES when it can't be created.
-  void CommitEmptyResponseAndComplete();
+  void CommitEmptyResponseAndComplete() override;
 
   // Calls url_loader_client_->OnComplete(). Expected to be called after
   // CommitResponseHeaders (i.e. status_ == kSentHeader).
-  void CommitCompleted(int error_code);
+  void CommitCompleted(int error_code, const char* reason) override;
 
   // Record loading milestones. Called after a response is completed or
   // a request is fall back to network. Never called when an error is
@@ -161,6 +168,9 @@
   // Called when the fetch handler doesn't handle the requset (i.e. network
   // fallback case).
   void RecordTimingMetricsForNetworkFallbackCase();
+  // Called when the response from RaceNetworkRequest is faster than the
+  // response from the fetch handler.
+  void RecordTimingMetricsForRaceNetworkReqestCase();
   // Time between the request is made and the request is routed to this loader.
   void RecordStartToForwardServiceWorkerTiming(
       const net::LoadTimingInfo& load_timing);
@@ -183,11 +193,17 @@
   // Renderer -> Browser IPC delay (network fallback case).
   void RecordFetchHandlerEndToFallbackNetworkTiming(
       const net::LoadTimingInfo& load_timing);
+  // Time between the request is made and complete reading response body.
+  void RecordStartToCompletedTiming(const net::LoadTimingInfo& load_timing);
 
   base::TimeTicks completion_time_;
 
   void TransitionToStatus(Status new_status);
 
+  // If eligible, dispatch the network request which races the ServiceWorker
+  // fetch handler.
+  bool MaybeStartRaceNetworkRequest();
+
   network::mojom::URLResponseHeadPtr response_head_;
   absl::optional<net::RedirectInfo> redirect_info_;
   int redirect_limit_;
@@ -242,6 +258,16 @@
   blink::mojom::ServiceWorkerFetchEventTimingPtr fetch_event_timing_;
   network::mojom::FetchResponseSource response_source_;
 
+  // True when RaceNetworkRequest is triggered regardless of its result.
+  bool did_start_race_network_request_ = false;
+
+  scoped_refptr<network::SharedURLLoaderFactory>
+      race_network_request_url_loader_factory_;
+  mojo::PendingRemote<network::mojom::URLLoader>
+      race_network_request_url_loader_;
+  absl::optional<ServiceWorkerRaceNetworkRequestURLLoaderClient>
+      race_network_request_loader_client_;
+
   base::WeakPtrFactory<ServiceWorkerSubresourceLoader> weak_factory_{this};
 };
 
diff --git a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
index 75688d77..e55a3a5 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
@@ -15,7 +15,9 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
+#include "content/public/common/content_features.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/renderer/service_worker/controller_service_worker_connector.h"
 #include "content/test/fake_network_url_loader_factory.h"
@@ -965,6 +967,71 @@
   }
 }
 
+TEST_F(ServiceWorkerSubresourceLoaderTest,
+       DropController_RestartFetchEvent_RaceNetworkRequest) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeatureWithParameters(
+      features::kServiceWorkerBypassFetchHandler,
+      {{"strategy", "opt-in"},
+       {"bypass_for", "all_with_race_network_request"}});
+
+  mojo::Remote<network::mojom::URLLoaderFactory> factory =
+      CreateSubresourceLoaderFactory();
+
+  {
+    network::ResourceRequest request =
+        CreateRequest(GURL("https://www.example.com/foo.png"));
+    mojo::Remote<network::mojom::URLLoader> loader;
+    std::unique_ptr<network::TestURLLoaderClient> client;
+    StartRequest(factory, request, &loader, &client);
+    fake_controller_.RunUntilFetchEvent();
+
+    EXPECT_EQ(request.url, fake_controller_.fetch_event_request().url);
+    EXPECT_EQ(request.method, fake_controller_.fetch_event_request().method);
+    EXPECT_EQ(1, fake_controller_.fetch_event_count());
+    EXPECT_EQ(1, fake_container_host_.get_controller_service_worker_count());
+  }
+
+  // Loading another resource reuses the existing connection to the
+  // ControllerServiceWorker (i.e. it doesn't increase the get controller
+  // service worker count).
+  {
+    network::ResourceRequest request =
+        CreateRequest(GURL("https://www.example.com/foo2.png"));
+    mojo::Remote<network::mojom::URLLoader> loader;
+    std::unique_ptr<network::TestURLLoaderClient> client;
+    StartRequest(factory, request, &loader, &client);
+    fake_controller_.RunUntilFetchEvent();
+
+    EXPECT_EQ(request.url, fake_controller_.fetch_event_request().url);
+    EXPECT_EQ(request.method, fake_controller_.fetch_event_request().method);
+    EXPECT_EQ(2, fake_controller_.fetch_event_count());
+    EXPECT_EQ(1, fake_container_host_.get_controller_service_worker_count());
+    client->RunUntilComplete();
+  }
+
+  base::HistogramTester histogram_tester;
+
+  network::ResourceRequest request =
+      CreateRequest(GURL("https://www.example.com/foo3.png"));
+  mojo::Remote<network::mojom::URLLoader> loader;
+  std::unique_ptr<network::TestURLLoaderClient> client;
+  StartRequest(factory, request, &loader, &client);
+
+  // Drop the connection to the ControllerServiceWorker.
+  fake_controller_.ClearReceivers();
+  base::RunLoop().RunUntilIdle();
+
+  // If connection is closed during fetch event, it's restarted and successfully
+  // finishes.
+  EXPECT_EQ(request.url, fake_controller_.fetch_event_request().url);
+  EXPECT_EQ(request.method, fake_controller_.fetch_event_request().method);
+  EXPECT_EQ(3, fake_controller_.fetch_event_count());
+  EXPECT_EQ(2, fake_container_host_.get_controller_service_worker_count());
+  histogram_tester.ExpectUniqueSample(kHistogramSubresourceFetchEvent,
+                                      blink::ServiceWorkerStatusCode::kOk, 1);
+}
+
 TEST_F(ServiceWorkerSubresourceLoaderTest, StreamResponse) {
   base::HistogramTester histogram_tester;
 
diff --git a/content/services/shared_storage_worklet/BUILD.gn b/content/services/shared_storage_worklet/BUILD.gn
deleted file mode 100644
index e5a2ce9..0000000
--- a/content/services/shared_storage_worklet/BUILD.gn
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//v8/gni/v8.gni")
-
-source_set("shared_storage_worklet") {
-  sources = [
-    "console.cc",
-    "console.h",
-    "private_aggregation.cc",
-    "private_aggregation.h",
-    "shared_storage.cc",
-    "shared_storage.h",
-    "shared_storage_iterator.cc",
-    "shared_storage_iterator.h",
-    "shared_storage_worklet_global_scope.cc",
-    "shared_storage_worklet_global_scope.h",
-    "shared_storage_worklet_service_impl.cc",
-    "shared_storage_worklet_service_impl.h",
-    "unnamed_operation_handler.cc",
-    "unnamed_operation_handler.h",
-    "url_selection_operation_handler.cc",
-    "url_selection_operation_handler.h",
-    "worklet_v8_helper.cc",
-    "worklet_v8_helper.h",
-  ]
-
-  configs += [
-    "//build/config/compiler:wexit_time_destructors",
-    "//content:content_implementation",
-    "//v8:external_startup_data",
-  ]
-
-  deps = [
-    "//base",
-    "//content:export",
-    "//content/services/worklet_utils",
-    "//gin",
-    "//mojo/public/cpp/bindings",
-    "//services/network/public/cpp",
-    "//third_party/blink/public/common",
-    "//url",
-    "//v8",
-  ]
-
-  public_deps = [ "//content/common:mojo_bindings" ]
-}
-
-# See comment at the top of //content/BUILD.gn for how this works.
-group("for_content_tests") {
-  visibility = [ "//content/test/*" ]
-  if (!is_component_build) {
-    public_deps = [ ":shared_storage_worklet" ]
-  }
-}
diff --git a/content/services/shared_storage_worklet/DEPS b/content/services/shared_storage_worklet/DEPS
deleted file mode 100644
index 76498c1..0000000
--- a/content/services/shared_storage_worklet/DEPS
+++ /dev/null
@@ -1,9 +0,0 @@
-include_rules = [
-  "+gin",
-  "+services/network/public",
-  "+third_party/blink/public/common/mime_util",
-  "+v8",
-  "+services/network/test",
-  "+components/services/storage/shared_storage/public/mojom",
-  "+third_party/blink/public/common/shared_storage/shared_storage_utils.h",
-]
diff --git a/content/services/shared_storage_worklet/OWNERS b/content/services/shared_storage_worklet/OWNERS
deleted file mode 100644
index 2051ea7c..0000000
--- a/content/services/shared_storage_worklet/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-yaoxia@chromium.org
-cammie@chromium.org
diff --git a/content/services/shared_storage_worklet/console.cc b/content/services/shared_storage_worklet/console.cc
deleted file mode 100644
index c4cb901..0000000
--- a/content/services/shared_storage_worklet/console.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/services/shared_storage_worklet/console.h"
-
-#include "base/logging.h"
-#include "content/services/shared_storage_worklet/worklet_v8_helper.h"
-#include "gin/arguments.h"
-
-namespace shared_storage_worklet {
-
-Console::Console(blink::mojom::SharedStorageWorkletServiceClient* client)
-    : client_(client) {}
-
-Console::~Console() = default;
-
-gin::WrapperInfo Console::kWrapperInfo = {gin::kEmbedderNativeGin};
-
-gin::ObjectTemplateBuilder Console::GetObjectTemplateBuilder(
-    v8::Isolate* isolate) {
-  return Wrappable<Console>::GetObjectTemplateBuilder(isolate).SetMethod(
-      "log", &Console::Log);
-}
-
-const char* Console::GetTypeName() {
-  return "Console";
-}
-
-void Console::Log(gin::Arguments* args) {
-  v8::Isolate* isolate = args->isolate();
-
-  std::vector<v8::Local<v8::Value>> argument_list = args->GetAll();
-
-  std::string result;
-  for (size_t i = 0; i < argument_list.size(); ++i) {
-    v8::String::Utf8Value val_utf8(isolate, argument_list[i]);
-    if (i != 0)
-      result += ' ';
-    if (*val_utf8)
-      result += std::string(*val_utf8, val_utf8.length());
-  }
-
-  client_->ConsoleLog(result);
-}
-
-}  // namespace shared_storage_worklet
diff --git a/content/services/shared_storage_worklet/console.h b/content/services/shared_storage_worklet/console.h
deleted file mode 100644
index 1ba5adb..0000000
--- a/content/services/shared_storage_worklet/console.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_SERVICES_SHARED_STORAGE_WORKLET_CONSOLE_H_
-#define CONTENT_SERVICES_SHARED_STORAGE_WORKLET_CONSOLE_H_
-
-#include "base/memory/raw_ptr.h"
-#include "gin/object_template_builder.h"
-#include "gin/wrappable.h"
-#include "third_party/blink/public/mojom/shared_storage/shared_storage_worklet_service.mojom.h"
-
-namespace gin {
-class Arguments;
-}  // namespace gin
-
-namespace shared_storage_worklet {
-
-class Console final : public gin::Wrappable<Console> {
- public:
-  explicit Console(blink::mojom::SharedStorageWorkletServiceClient* client);
-  ~Console() override;
-
-  static gin::WrapperInfo kWrapperInfo;
-
-  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override;
-
-  const char* GetTypeName() override;
-
- private:
-  void Log(gin::Arguments* args);
-
-  raw_ptr<blink::mojom::SharedStorageWorkletServiceClient> client_;
-
-  base::WeakPtrFactory<Console> weak_ptr_factory_{this};
-};
-
-}  // namespace shared_storage_worklet
-
-#endif  // CONTENT_SERVICES_SHARED_STORAGE_WORKLET_CONSOLE_H_
diff --git a/content/services/shared_storage_worklet/private_aggregation.cc b/content/services/shared_storage_worklet/private_aggregation.cc
deleted file mode 100644
index 2ec336e..0000000
--- a/content/services/shared_storage_worklet/private_aggregation.cc
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/services/shared_storage_worklet/private_aggregation.h"
-
-#include <stdint.h>
-
-#include <iterator>
-#include <map>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/check.h"
-#include "base/containers/contains.h"
-#include "base/ranges/algorithm.h"
-#include "content/services/shared_storage_worklet/shared_storage_worklet_global_scope.h"
-#include "content/services/worklet_utils/private_aggregation_utils.h"
-#include "gin/arguments.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "third_party/blink/public/mojom/private_aggregation/aggregatable_report.mojom.h"
-#include "third_party/blink/public/mojom/private_aggregation/private_aggregation_host.mojom.h"
-#include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom-shared.h"
-#include "v8/include/v8-isolate.h"
-#include "v8/include/v8-primitive.h"
-
-namespace shared_storage_worklet {
-
-struct PrivateAggregation::OperationState {
-  // Defaults to debug mode being disabled.
-  blink::mojom::DebugModeDetails debug_mode_details;
-
-  // Pending contributions
-  std::vector<blink::mojom::AggregatableReportHistogramContributionPtr>
-      private_aggregation_contributions;
-
-  mojo::Remote<blink::mojom::PrivateAggregationHost> private_aggregation_host;
-};
-
-PrivateAggregation::PrivateAggregation(
-    blink::mojom::SharedStorageWorkletServiceClient& client,
-    bool private_aggregation_permissions_policy_allowed,
-    SharedStorageWorkletGlobalScope& global_scope)
-    : client_(client),
-      private_aggregation_permissions_policy_allowed_(
-          private_aggregation_permissions_policy_allowed),
-      global_scope_(global_scope) {}
-
-PrivateAggregation::~PrivateAggregation() {
-  // Ensure any unfinished operations are properly handled.
-  std::vector<int64_t> remaining_operation_ids;
-  remaining_operation_ids.reserve(operation_states_.size());
-  base::ranges::transform(operation_states_,
-                          std::back_inserter(remaining_operation_ids),
-                          [](auto& elem) { return elem.first; });
-
-  base::ranges::for_each(remaining_operation_ids, [this](int64_t operation_id) {
-    OnOperationFinished(operation_id);
-  });
-  CHECK(operation_states_.empty());
-}
-
-gin::WrapperInfo PrivateAggregation::kWrapperInfo = {gin::kEmbedderNativeGin};
-
-gin::ObjectTemplateBuilder PrivateAggregation::GetObjectTemplateBuilder(
-    v8::Isolate* isolate) {
-  return Wrappable<PrivateAggregation>::GetObjectTemplateBuilder(isolate)
-      .SetMethod("sendHistogramReport",
-                 &PrivateAggregation::SendHistogramReport)
-      .SetMethod("enableDebugMode", &PrivateAggregation::EnableDebugMode);
-}
-
-const char* PrivateAggregation::GetTypeName() {
-  return "PrivateAggregation";
-}
-
-void PrivateAggregation::OnOperationStarted(
-    int64_t operation_id,
-    mojo::PendingRemote<blink::mojom::PrivateAggregationHost>
-        private_aggregation_host) {
-  CHECK(!base::Contains(operation_states_, operation_id));
-  CHECK(private_aggregation_host);
-
-  operation_states_[operation_id].private_aggregation_host.Bind(
-      std::move(private_aggregation_host));
-}
-
-void PrivateAggregation::OnOperationFinished(int64_t operation_id) {
-  CHECK(base::Contains(operation_states_, operation_id));
-  OperationState& operation_state = operation_states_[operation_id];
-
-  if (!operation_state.private_aggregation_contributions.empty()) {
-    operation_state.private_aggregation_host->SendHistogramReport(
-        std::move(operation_state.private_aggregation_contributions),
-        // TODO(alexmt): consider allowing this to be set
-        blink::mojom::AggregationServiceMode::kDefault,
-        operation_state.debug_mode_details.Clone());
-  }
-
-  operation_states_.erase(operation_id);
-}
-
-void PrivateAggregation::SendHistogramReport(gin::Arguments* args) {
-  EnsureUseCountersAreRecorded();
-
-  blink::mojom::AggregatableReportHistogramContributionPtr contribution =
-      worklet_utils::ParseSendHistogramReportArguments(
-          *args, private_aggregation_permissions_policy_allowed_);
-  if (contribution.is_null()) {
-    // Indicates an exception was thrown.
-    return;
-  }
-
-  int64_t operation_id = global_scope_->GetCurrentOperationId();
-  CHECK(base::Contains(operation_states_, operation_id));
-  OperationState& operation_state = operation_states_[operation_id];
-
-  operation_state.private_aggregation_contributions.push_back(
-      std::move(contribution));
-}
-
-void PrivateAggregation::EnableDebugMode(gin::Arguments* args) {
-  EnsureUseCountersAreRecorded();
-
-  int64_t operation_id = global_scope_->GetCurrentOperationId();
-  CHECK(base::Contains(operation_states_, operation_id));
-  OperationState& operation_state = operation_states_[operation_id];
-
-  worklet_utils::ParseAndApplyEnableDebugModeArguments(
-      *args, private_aggregation_permissions_policy_allowed_,
-      operation_state.debug_mode_details);
-}
-
-void PrivateAggregation::EnsureUseCountersAreRecorded() {
-  if (!has_recorded_use_counters_) {
-    has_recorded_use_counters_ = true;
-    client_->RecordUseCounters(
-        {blink::mojom::WebFeature::kPrivateAggregationApiAll,
-         blink::mojom::WebFeature::kPrivateAggregationApiSharedStorage});
-  }
-}
-
-}  // namespace shared_storage_worklet
diff --git a/content/services/shared_storage_worklet/private_aggregation.h b/content/services/shared_storage_worklet/private_aggregation.h
deleted file mode 100644
index a955ef6..0000000
--- a/content/services/shared_storage_worklet/private_aggregation.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_SERVICES_SHARED_STORAGE_WORKLET_PRIVATE_AGGREGATION_H_
-#define CONTENT_SERVICES_SHARED_STORAGE_WORKLET_PRIVATE_AGGREGATION_H_
-
-#include <stdint.h>
-
-#include <map>
-
-#include "base/memory/raw_ref.h"
-#include "content/services/shared_storage_worklet/shared_storage_worklet_global_scope.h"
-#include "gin/object_template_builder.h"
-#include "gin/wrappable.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "third_party/blink/public/mojom/private_aggregation/private_aggregation_host.mojom-forward.h"
-#include "third_party/blink/public/mojom/shared_storage/shared_storage_worklet_service.mojom.h"
-
-namespace gin {
-class Arguments;
-}  // namespace gin
-
-namespace shared_storage_worklet {
-
-class PrivateAggregation final : public gin::Wrappable<PrivateAggregation> {
- public:
-  PrivateAggregation(blink::mojom::SharedStorageWorkletServiceClient& client,
-                     bool private_aggregation_permissions_policy_allowed,
-                     SharedStorageWorkletGlobalScope& global_scope);
-  ~PrivateAggregation() override;
-
-  static gin::WrapperInfo kWrapperInfo;
-
-  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override;
-
-  const char* GetTypeName() override;
-
-  void OnOperationStarted(
-      int64_t operation_id,
-      mojo::PendingRemote<blink::mojom::PrivateAggregationHost>
-          private_aggregation_host);
-  void OnOperationFinished(int64_t operation_id);
-
- private:
-  struct OperationState;
-
-  void SendHistogramReport(gin::Arguments* args);
-  void EnableDebugMode(gin::Arguments* args);
-
-  void EnsureUseCountersAreRecorded();
-
-  raw_ref<blink::mojom::SharedStorageWorkletServiceClient> client_;
-
-  bool private_aggregation_permissions_policy_allowed_;
-
-  raw_ref<SharedStorageWorkletGlobalScope> global_scope_;
-
-  bool has_recorded_use_counters_ = false;
-
-  // Keyed by a per-invocation operation ID.
-  std::map<int64_t, OperationState> operation_states_;
-};
-
-}  // namespace shared_storage_worklet
-
-#endif  // CONTENT_SERVICES_SHARED_STORAGE_WORKLET_PRIVATE_AGGREGATION_H_
diff --git a/content/services/shared_storage_worklet/shared_storage.cc b/content/services/shared_storage_worklet/shared_storage.cc
deleted file mode 100644
index 547d908..0000000
--- a/content/services/shared_storage_worklet/shared_storage.cc
+++ /dev/null
@@ -1,452 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/services/shared_storage_worklet/shared_storage.h"
-
-#include "base/logging.h"
-#include "base/metrics/histogram_functions.h"
-#include "content/services/shared_storage_worklet/shared_storage_iterator.h"
-#include "content/services/shared_storage_worklet/worklet_v8_helper.h"
-#include "gin/arguments.h"
-#include "gin/dictionary.h"
-#include "gin/handle.h"
-#include "third_party/blink/public/common/shared_storage/shared_storage_utils.h"
-#include "v8/include/v8-exception.h"
-
-namespace shared_storage_worklet {
-
-namespace {
-
-// Convert ECMAScript value to IDL DOMString:
-// https://webidl.spec.whatwg.org/#es-DOMString
-bool ToIDLDOMString(v8::Isolate* isolate,
-                    v8::Local<v8::Value> val,
-                    std::u16string& out) {
-  v8::Local<v8::Context> context = isolate->GetCurrentContext();
-
-  WorkletV8Helper::HandleScope scope(isolate);
-  v8::TryCatch try_catch(isolate);
-
-  v8::Local<v8::String> str;
-  if (!val->ToString(context).ToLocal(&str))
-    return false;
-
-  return gin::ConvertFromV8<std::u16string>(isolate, str, &out);
-}
-
-void LogTimingHistogramForVoidOperation(
-    blink::SharedStorageVoidOperation caller,
-    base::TimeTicks start_time) {
-  base::TimeDelta elapsed_time = base::TimeTicks::Now() - start_time;
-  switch (caller) {
-    case blink::SharedStorageVoidOperation::kSet:
-      base::UmaHistogramMediumTimes("Storage.SharedStorage.Worklet.Timing.Set",
-                                    elapsed_time);
-      break;
-    case blink::SharedStorageVoidOperation::kAppend:
-      base::UmaHistogramMediumTimes(
-          "Storage.SharedStorage.Worklet.Timing.Append", elapsed_time);
-      break;
-    case blink::SharedStorageVoidOperation::kDelete:
-      base::UmaHistogramMediumTimes(
-          "Storage.SharedStorage.Worklet.Timing.Delete", elapsed_time);
-      break;
-    case blink::SharedStorageVoidOperation::kClear:
-      base::UmaHistogramMediumTimes(
-          "Storage.SharedStorage.Worklet.Timing.Clear", elapsed_time);
-      break;
-    default:
-      NOTREACHED();
-  }
-}
-
-}  // namespace
-
-SharedStorage::SharedStorage(
-    blink::mojom::SharedStorageWorkletServiceClient* client,
-    const absl::optional<std::u16string>& embedder_context)
-    : client_(client), embedder_context_(embedder_context) {}
-
-SharedStorage::~SharedStorage() = default;
-
-gin::WrapperInfo SharedStorage::kWrapperInfo = {gin::kEmbedderNativeGin};
-
-gin::ObjectTemplateBuilder SharedStorage::GetObjectTemplateBuilder(
-    v8::Isolate* isolate) {
-  return Wrappable<SharedStorage>::GetObjectTemplateBuilder(isolate)
-      .SetMethod("set", &SharedStorage::Set)
-      .SetMethod("append", &SharedStorage::Append)
-      .SetMethod("delete", &SharedStorage::Delete)
-      .SetMethod("clear", &SharedStorage::Clear)
-      .SetMethod("get", &SharedStorage::Get)
-      .SetMethod("keys", &SharedStorage::Keys)
-      .SetMethod("entries", &SharedStorage::Entries)
-      .SetMethod("length", &SharedStorage::Length)
-      .SetMethod("remainingBudget", &SharedStorage::RemainingBudget)
-      .SetProperty("context", &SharedStorage::Context);
-}
-
-const char* SharedStorage::GetTypeName() {
-  return "SharedStorage";
-}
-
-v8::Local<v8::Promise> SharedStorage::Set(gin::Arguments* args) {
-  base::TimeTicks start_time = base::TimeTicks::Now();
-  v8::Isolate* isolate = args->isolate();
-
-  v8::Local<v8::Promise::Resolver> resolver =
-      v8::Promise::Resolver::New(args->GetHolderCreationContext())
-          .ToLocalChecked();
-
-  v8::Local<v8::Promise> promise = resolver->GetPromise();
-
-  std::vector<v8::Local<v8::Value>> v8_args = args->GetAll();
-
-  std::u16string arg0_key;
-  if (v8_args.size() < 1 || !ToIDLDOMString(isolate, v8_args[0], arg0_key) ||
-      !blink::IsValidSharedStorageKeyStringLength(arg0_key.size())) {
-    resolver
-        ->Reject(
-            args->GetHolderCreationContext(),
-            gin::StringToV8(
-                isolate,
-                "Missing or invalid \"key\" argument in sharedStorage.set()"))
-        .ToChecked();
-    return promise;
-  }
-
-  std::u16string arg1_value;
-  if (v8_args.size() < 2 || !ToIDLDOMString(isolate, v8_args[1], arg1_value) ||
-      !blink::IsValidSharedStorageValueStringLength(arg1_value.size())) {
-    resolver
-        ->Reject(
-            args->GetHolderCreationContext(),
-            gin::StringToV8(
-                isolate,
-                "Missing or invalid \"value\" argument in sharedStorage.set()"))
-        .ToChecked();
-    return promise;
-  }
-
-  gin::Dictionary arg2_options_dict = gin::Dictionary::CreateEmpty(isolate);
-
-  if (v8_args.size() > 2) {
-    if (!gin::ConvertFromV8(isolate, v8_args[2], &arg2_options_dict)) {
-      resolver
-          ->Reject(args->GetHolderCreationContext(),
-                   gin::StringToV8(
-                       isolate,
-                       "Invalid \"options\" argument in sharedStorage.set()"))
-          .ToChecked();
-      return promise;
-    }
-  }
-
-  bool ignore_if_present = false;
-  arg2_options_dict.Get<bool>("ignoreIfPresent", &ignore_if_present);
-
-  client_->SharedStorageSet(
-      arg0_key, arg1_value, ignore_if_present,
-      base::BindOnce(&SharedStorage::OnVoidOperationFinished,
-                     weak_ptr_factory_.GetWeakPtr(), isolate,
-                     v8::Global<v8::Promise::Resolver>(isolate, resolver),
-                     blink::SharedStorageVoidOperation::kSet, start_time));
-
-  return promise;
-}
-
-v8::Local<v8::Promise> SharedStorage::Append(gin::Arguments* args) {
-  base::TimeTicks start_time = base::TimeTicks::Now();
-  v8::Isolate* isolate = args->isolate();
-
-  v8::Local<v8::Promise::Resolver> resolver =
-      v8::Promise::Resolver::New(args->GetHolderCreationContext())
-          .ToLocalChecked();
-
-  v8::Local<v8::Promise> promise = resolver->GetPromise();
-
-  std::vector<v8::Local<v8::Value>> v8_args = args->GetAll();
-
-  std::u16string arg0_key;
-  if (v8_args.size() < 1 || !ToIDLDOMString(isolate, v8_args[0], arg0_key) ||
-      !blink::IsValidSharedStorageKeyStringLength(arg0_key.size())) {
-    resolver
-        ->Reject(args->GetHolderCreationContext(),
-                 gin::StringToV8(isolate,
-                                 "Missing or invalid \"key\" argument in "
-                                 "sharedStorage.append()"))
-        .ToChecked();
-    return promise;
-  }
-
-  std::u16string arg1_value;
-  if (v8_args.size() < 2 || !ToIDLDOMString(isolate, v8_args[1], arg1_value) ||
-      !blink::IsValidSharedStorageValueStringLength(arg1_value.size())) {
-    resolver
-        ->Reject(args->GetHolderCreationContext(),
-                 gin::StringToV8(isolate,
-                                 "Missing or invalid \"value\" argument in "
-                                 "sharedStorage.append()"))
-        .ToChecked();
-    return promise;
-  }
-
-  client_->SharedStorageAppend(
-      arg0_key, arg1_value,
-      base::BindOnce(&SharedStorage::OnVoidOperationFinished,
-                     weak_ptr_factory_.GetWeakPtr(), isolate,
-                     v8::Global<v8::Promise::Resolver>(isolate, resolver),
-                     blink::SharedStorageVoidOperation::kAppend, start_time));
-
-  return promise;
-}
-
-v8::Local<v8::Promise> SharedStorage::Delete(gin::Arguments* args) {
-  base::TimeTicks start_time = base::TimeTicks::Now();
-  v8::Isolate* isolate = args->isolate();
-
-  v8::Local<v8::Promise::Resolver> resolver =
-      v8::Promise::Resolver::New(args->GetHolderCreationContext())
-          .ToLocalChecked();
-
-  v8::Local<v8::Promise> promise = resolver->GetPromise();
-
-  std::vector<v8::Local<v8::Value>> v8_args = args->GetAll();
-
-  std::u16string arg0_key;
-  if (v8_args.size() < 1 || !ToIDLDOMString(isolate, v8_args[0], arg0_key) ||
-      !blink::IsValidSharedStorageKeyStringLength(arg0_key.size())) {
-    resolver
-        ->Reject(args->GetHolderCreationContext(),
-                 gin::StringToV8(isolate,
-                                 "Missing or invalid \"key\" argument in "
-                                 "sharedStorage.delete()"))
-        .ToChecked();
-    return promise;
-  }
-
-  client_->SharedStorageDelete(
-      arg0_key,
-      base::BindOnce(&SharedStorage::OnVoidOperationFinished,
-                     weak_ptr_factory_.GetWeakPtr(), isolate,
-                     v8::Global<v8::Promise::Resolver>(isolate, resolver),
-                     blink::SharedStorageVoidOperation::kDelete, start_time));
-
-  return promise;
-}
-
-v8::Local<v8::Promise> SharedStorage::Clear(gin::Arguments* args) {
-  base::TimeTicks start_time = base::TimeTicks::Now();
-  v8::Isolate* isolate = args->isolate();
-
-  v8::Local<v8::Promise::Resolver> resolver =
-      v8::Promise::Resolver::New(args->GetHolderCreationContext())
-          .ToLocalChecked();
-
-  v8::Local<v8::Promise> promise = resolver->GetPromise();
-
-  client_->SharedStorageClear(base::BindOnce(
-      &SharedStorage::OnVoidOperationFinished, weak_ptr_factory_.GetWeakPtr(),
-      isolate, v8::Global<v8::Promise::Resolver>(isolate, resolver),
-      blink::SharedStorageVoidOperation::kClear, start_time));
-
-  return promise;
-}
-
-v8::Local<v8::Promise> SharedStorage::Get(gin::Arguments* args) {
-  base::TimeTicks start_time = base::TimeTicks::Now();
-  v8::Isolate* isolate = args->isolate();
-
-  v8::Local<v8::Promise::Resolver> resolver =
-      v8::Promise::Resolver::New(args->GetHolderCreationContext())
-          .ToLocalChecked();
-
-  v8::Local<v8::Promise> promise = resolver->GetPromise();
-
-  std::vector<v8::Local<v8::Value>> v8_args = args->GetAll();
-
-  std::u16string arg0_key;
-  if (v8_args.size() < 1 || !ToIDLDOMString(isolate, v8_args[0], arg0_key) ||
-      !blink::IsValidSharedStorageKeyStringLength(arg0_key.size())) {
-    resolver
-        ->Reject(
-            args->GetHolderCreationContext(),
-            gin::StringToV8(
-                isolate,
-                "Missing or invalid \"key\" argument in sharedStorage.get()"))
-        .ToChecked();
-    return promise;
-  }
-
-  client_->SharedStorageGet(
-      arg0_key,
-      base::BindOnce(&SharedStorage::OnStringRetrievalOperationFinished,
-                     weak_ptr_factory_.GetWeakPtr(), isolate,
-                     v8::Global<v8::Promise::Resolver>(isolate, resolver),
-                     start_time));
-  return promise;
-}
-
-v8::Local<v8::Object> SharedStorage::Keys(gin::Arguments* args) {
-  return (new SharedStorageIterator(SharedStorageIterator::Mode::kKey, client_))
-      ->GetWrapper(args->isolate())
-      .ToLocalChecked();
-}
-
-v8::Local<v8::Object> SharedStorage::Entries(gin::Arguments* args) {
-  return (new SharedStorageIterator(SharedStorageIterator::Mode::kKeyValue,
-                                    client_))
-      ->GetWrapper(args->isolate())
-      .ToLocalChecked();
-}
-
-v8::Local<v8::Promise> SharedStorage::Length(gin::Arguments* args) {
-  base::TimeTicks start_time = base::TimeTicks::Now();
-  v8::Isolate* isolate = args->isolate();
-
-  v8::Local<v8::Promise::Resolver> resolver =
-      v8::Promise::Resolver::New(args->GetHolderCreationContext())
-          .ToLocalChecked();
-
-  v8::Local<v8::Promise> promise = resolver->GetPromise();
-
-  client_->SharedStorageLength(base::BindOnce(
-      &SharedStorage::OnLengthOperationFinished, weak_ptr_factory_.GetWeakPtr(),
-      isolate, v8::Global<v8::Promise::Resolver>(isolate, resolver),
-      start_time));
-
-  return promise;
-}
-
-v8::Local<v8::Promise> SharedStorage::RemainingBudget(gin::Arguments* args) {
-  base::TimeTicks start_time = base::TimeTicks::Now();
-  v8::Isolate* isolate = args->isolate();
-
-  v8::Local<v8::Promise::Resolver> resolver =
-      v8::Promise::Resolver::New(args->GetHolderCreationContext())
-          .ToLocalChecked();
-
-  v8::Local<v8::Promise> promise = resolver->GetPromise();
-
-  client_->SharedStorageRemainingBudget(base::BindOnce(
-      &SharedStorage::OnBudgetOperationFinished, weak_ptr_factory_.GetWeakPtr(),
-      isolate, v8::Global<v8::Promise::Resolver>(isolate, resolver),
-      start_time));
-
-  return promise;
-}
-
-v8::Local<v8::Value> SharedStorage::Context(gin::Arguments* args) {
-  v8::Isolate* isolate = args->isolate();
-
-  if (!embedder_context_) {
-    base::UmaHistogramBoolean("Storage.SharedStorage.Worklet.Context.IsDefined",
-                              false);
-    return v8::Undefined(isolate);
-  }
-
-  base::UmaHistogramBoolean("Storage.SharedStorage.Worklet.Context.IsDefined",
-                            true);
-  return gin::ConvertToV8(isolate, embedder_context_.value());
-}
-
-void SharedStorage::OnVoidOperationFinished(
-    v8::Isolate* isolate,
-    v8::Global<v8::Promise::Resolver> global_resolver,
-    blink::SharedStorageVoidOperation caller,
-    base::TimeTicks start_time,
-    bool success,
-    const std::string& error_message) {
-  WorkletV8Helper::HandleScope scope(isolate);
-  v8::Local<v8::Promise::Resolver> resolver = global_resolver.Get(isolate);
-  v8::Local<v8::Context> context = resolver->GetCreationContextChecked();
-
-  if (success) {
-    resolver->Resolve(context, v8::Undefined(isolate)).ToChecked();
-    LogTimingHistogramForVoidOperation(caller, start_time);
-    return;
-  }
-
-  resolver->Reject(context, gin::StringToV8(isolate, error_message))
-      .ToChecked();
-}
-
-void SharedStorage::OnStringRetrievalOperationFinished(
-    v8::Isolate* isolate,
-    v8::Global<v8::Promise::Resolver> global_resolver,
-    base::TimeTicks start_time,
-    blink::mojom::SharedStorageGetStatus status,
-    const std::string& error_message,
-    const std::u16string& result) {
-  WorkletV8Helper::HandleScope scope(isolate);
-  v8::Local<v8::Promise::Resolver> resolver = global_resolver.Get(isolate);
-  v8::Local<v8::Context> context = resolver->GetCreationContextChecked();
-  base::TimeDelta elapsed_time = base::TimeTicks::Now() - start_time;
-
-  if (status == blink::mojom::SharedStorageGetStatus::kSuccess) {
-    resolver->Resolve(context, gin::ConvertToV8(isolate, result)).ToChecked();
-    base::UmaHistogramMediumTimes("Storage.SharedStorage.Worklet.Timing.Get",
-                                  elapsed_time);
-    return;
-  }
-
-  if (status == blink::mojom::SharedStorageGetStatus::kNotFound) {
-    resolver->Resolve(context, v8::Undefined(isolate)).ToChecked();
-    base::UmaHistogramMediumTimes("Storage.SharedStorage.Worklet.Timing.Get",
-                                  elapsed_time);
-    return;
-  }
-
-  resolver->Reject(context, gin::StringToV8(isolate, error_message))
-      .ToChecked();
-}
-
-void SharedStorage::OnLengthOperationFinished(
-    v8::Isolate* isolate,
-    v8::Global<v8::Promise::Resolver> global_resolver,
-    base::TimeTicks start_time,
-    bool success,
-    const std::string& error_message,
-    uint32_t length) {
-  WorkletV8Helper::HandleScope scope(isolate);
-  v8::Local<v8::Promise::Resolver> resolver = global_resolver.Get(isolate);
-  v8::Local<v8::Context> context = resolver->GetCreationContextChecked();
-
-  if (success) {
-    resolver->Resolve(context, gin::Converter<uint32_t>::ToV8(isolate, length))
-        .ToChecked();
-    base::UmaHistogramMediumTimes("Storage.SharedStorage.Worklet.Timing.Length",
-                                  base::TimeTicks::Now() - start_time);
-    return;
-  }
-
-  resolver->Reject(context, gin::StringToV8(isolate, error_message))
-      .ToChecked();
-}
-
-void SharedStorage::OnBudgetOperationFinished(
-    v8::Isolate* isolate,
-    v8::Global<v8::Promise::Resolver> global_resolver,
-    base::TimeTicks start_time,
-    bool success,
-    const std::string& error_message,
-    double bits) {
-  WorkletV8Helper::HandleScope scope(isolate);
-  v8::Local<v8::Promise::Resolver> resolver = global_resolver.Get(isolate);
-  v8::Local<v8::Context> context = resolver->GetCreationContextChecked();
-
-  if (success) {
-    resolver->Resolve(context, gin::Converter<double>::ToV8(isolate, bits))
-        .ToChecked();
-    base::UmaHistogramMediumTimes(
-        "Storage.SharedStorage.Worklet.Timing.RemainingBudget",
-        base::TimeTicks::Now() - start_time);
-    return;
-  }
-
-  resolver->Reject(context, gin::StringToV8(isolate, error_message))
-      .ToChecked();
-}
-
-}  // namespace shared_storage_worklet
diff --git a/content/services/shared_storage_worklet/shared_storage.h b/content/services/shared_storage_worklet/shared_storage.h
deleted file mode 100644
index ee54af0..0000000
--- a/content/services/shared_storage_worklet/shared_storage.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_SERVICES_SHARED_STORAGE_WORKLET_SHARED_STORAGE_H_
-#define CONTENT_SERVICES_SHARED_STORAGE_WORKLET_SHARED_STORAGE_H_
-
-#include "base/memory/raw_ptr.h"
-#include "base/time/time.h"
-#include "gin/object_template_builder.h"
-#include "gin/wrappable.h"
-#include "third_party/blink/public/common/shared_storage/shared_storage_utils.h"
-#include "third_party/blink/public/mojom/shared_storage/shared_storage_worklet_service.mojom.h"
-
-namespace gin {
-class Arguments;
-}  // namespace gin
-
-namespace shared_storage_worklet {
-
-class SharedStorage final : public gin::Wrappable<SharedStorage> {
- public:
-  SharedStorage(blink::mojom::SharedStorageWorkletServiceClient* client,
-                const absl::optional<std::u16string>& embedder_context);
-  ~SharedStorage() override;
-
-  static gin::WrapperInfo kWrapperInfo;
-
-  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override;
-
-  const char* GetTypeName() override;
-
- private:
-  v8::Local<v8::Promise> Set(gin::Arguments* args);
-  v8::Local<v8::Promise> Append(gin::Arguments* args);
-  v8::Local<v8::Promise> Delete(gin::Arguments* args);
-  v8::Local<v8::Promise> Clear(gin::Arguments* args);
-  v8::Local<v8::Promise> Get(gin::Arguments* args);
-  v8::Local<v8::Object> Keys(gin::Arguments* args);
-  v8::Local<v8::Object> Entries(gin::Arguments* args);
-  v8::Local<v8::Promise> Length(gin::Arguments* args);
-  v8::Local<v8::Promise> RemainingBudget(gin::Arguments* args);
-  v8::Local<v8::Value> Context(gin::Arguments* args);
-
-  void OnVoidOperationFinished(
-      v8::Isolate* isolate,
-      v8::Global<v8::Promise::Resolver> global_resolver,
-      blink::SharedStorageVoidOperation caller,
-      base::TimeTicks start_time,
-      bool success,
-      const std::string& error_message);
-
-  void OnStringRetrievalOperationFinished(
-      v8::Isolate* isolate,
-      v8::Global<v8::Promise::Resolver> global_resolver,
-      base::TimeTicks start_time,
-      blink::mojom::SharedStorageGetStatus status,
-      const std::string& error_message,
-      const std::u16string& result);
-
-  void OnLengthOperationFinished(
-      v8::Isolate* isolate,
-      v8::Global<v8::Promise::Resolver> global_resolver,
-      base::TimeTicks start_time,
-      bool success,
-      const std::string& error_message,
-      uint32_t length);
-
-  void OnBudgetOperationFinished(
-      v8::Isolate* isolate,
-      v8::Global<v8::Promise::Resolver> global_resolver,
-      base::TimeTicks start_time,
-      bool success,
-      const std::string& error_message,
-      double bits);
-
-  raw_ptr<blink::mojom::SharedStorageWorkletServiceClient> client_;
-
-  // If this worklet is inside a fenced frame or a URN iframe,
-  // `embedder_context_` represents any contextual information written to the
-  // frame's `blink::FencedFrameConfig` by the embedder before navigation to the
-  // config. `embedder_context_` is passed to the worklet upon initialization.
-  absl::optional<std::u16string> embedder_context_;
-
-  base::WeakPtrFactory<SharedStorage> weak_ptr_factory_{this};
-};
-
-}  // namespace shared_storage_worklet
-
-#endif  // CONTENT_SERVICES_SHARED_STORAGE_WORKLET_SHARED_STORAGE_H_
diff --git a/content/services/shared_storage_worklet/shared_storage_iterator.cc b/content/services/shared_storage_worklet/shared_storage_iterator.cc
deleted file mode 100644
index 3d392e9..0000000
--- a/content/services/shared_storage_worklet/shared_storage_iterator.cc
+++ /dev/null
@@ -1,249 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/services/shared_storage_worklet/shared_storage_iterator.h"
-
-#include "base/metrics/histogram_functions.h"
-#include "base/numerics/checked_math.h"
-#include "base/task/single_thread_task_runner.h"
-#include "content/services/shared_storage_worklet/worklet_v8_helper.h"
-#include "gin/arguments.h"
-#include "gin/dictionary.h"
-#include "v8/include/v8-context.h"
-#include "v8/include/v8-primitive.h"
-#include "v8/include/v8-promise.h"
-
-namespace shared_storage_worklet {
-
-const int kSharedStorageIteratorBenchmarkStep = 10;
-
-SharedStorageIterator::SharedStorageIterator(
-    Mode mode,
-    blink::mojom::SharedStorageWorkletServiceClient* client)
-    : mode_(mode) {
-  base::UmaHistogramExactLinear(
-      "Storage.SharedStorage.AsyncIterator.IteratedEntriesBenchmarks", 0, 101);
-  switch (mode_) {
-    case Mode::kKey:
-      client->SharedStorageKeys(receiver_.BindNewPipeAndPassRemote(
-          base::SingleThreadTaskRunner::GetCurrentDefault()));
-      break;
-    case Mode::kKeyValue:
-      client->SharedStorageEntries(receiver_.BindNewPipeAndPassRemote(
-          base::SingleThreadTaskRunner::GetCurrentDefault()));
-      break;
-  }
-}
-
-SharedStorageIterator::~SharedStorageIterator() = default;
-
-gin::WrapperInfo SharedStorageIterator::kWrapperInfo = {
-    gin::kEmbedderNativeGin};
-
-gin::ObjectTemplateBuilder SharedStorageIterator::GetObjectTemplateBuilder(
-    v8::Isolate* isolate) {
-  return Wrappable<SharedStorageIterator>::GetObjectTemplateBuilder(isolate)
-      .SetMethod(v8::Symbol::GetAsyncIterator(isolate),
-                 &SharedStorageIterator::GetThisObject)
-      .SetMethod("next", &SharedStorageIterator::Next);
-}
-
-const char* SharedStorageIterator::GetTypeName() {
-  return "SharedStorageIterator";
-}
-
-v8::Local<v8::Object> SharedStorageIterator::GetThisObject(
-    gin::Arguments* args) {
-  return GetWrapper(args->isolate()).ToLocalChecked();
-}
-
-v8::Local<v8::Promise> SharedStorageIterator::Next(gin::Arguments* args) {
-  next_start_times_.push(base::TimeTicks::Now());
-  v8::Isolate* isolate = args->isolate();
-  v8::Local<v8::Context> context = args->GetHolderCreationContext();
-
-  v8::Local<v8::Promise::Resolver> resolver =
-      v8::Promise::Resolver::New(context).ToLocalChecked();
-
-  return NextHelper(isolate, resolver);
-}
-
-v8::Local<v8::Promise> SharedStorageIterator::NextHelper(
-    v8::Isolate* isolate,
-    v8::Local<v8::Promise::Resolver> resolver) {
-  v8::Local<v8::Context> context = resolver->GetCreationContextChecked();
-  v8::Local<v8::Promise> promise = resolver->GetPromise();
-
-  if (has_error_) {
-    resolver->Reject(context, gin::StringToV8(isolate, error_message_))
-        .ToChecked();
-
-    // We only record timing histograms when there is no error. Discard the
-    // start time for this call.
-    DCHECK(!next_start_times_.empty());
-    next_start_times_.pop();
-    return promise;
-  }
-
-  if (!pending_entries_.empty()) {
-    blink::mojom::SharedStorageKeyAndOrValuePtr next_entry =
-        std::move(pending_entries_.front());
-    pending_entries_.pop_front();
-
-    resolver->Resolve(context, CreateIteratorResult(isolate, next_entry))
-        .ToChecked();
-
-    base::CheckedNumeric<int> count = entries_iterated_;
-    entries_iterated_ = (++count).ValueOrDie();
-
-    while (next_benchmark_for_iteration_ <= 100 &&
-           MeetsBenchmark(entries_iterated_, next_benchmark_for_iteration_)) {
-      base::UmaHistogramExactLinear(
-          "Storage.SharedStorage.AsyncIterator.IteratedEntriesBenchmarks",
-          next_benchmark_for_iteration_, 101);
-      next_benchmark_for_iteration_ += kSharedStorageIteratorBenchmarkStep;
-    }
-
-    LogElapsedTime();
-    return promise;
-  }
-
-  if (waiting_for_more_entries_) {
-    pending_resolvers_.emplace_back(
-        v8::Global<v8::Promise::Resolver>(isolate, resolver));
-    DCHECK(!isolate_for_pending_resolvers_ ||
-           isolate_for_pending_resolvers_ == isolate);
-    isolate_for_pending_resolvers_ = isolate;
-    return promise;
-  }
-
-  DCHECK(pending_resolvers_.empty());
-  resolver->Resolve(context, CreateIteratorResultDone(isolate)).ToChecked();
-  LogElapsedTime();
-  return promise;
-}
-
-void SharedStorageIterator::DidReadEntries(
-    bool success,
-    const std::string& error_message,
-    std::vector<blink::mojom::SharedStorageKeyAndOrValuePtr> entries,
-    bool has_more_entries,
-    int total_queued_to_send) {
-  DCHECK(waiting_for_more_entries_);
-  DCHECK(!has_error_);
-  DCHECK(!(success && entries.empty() && has_more_entries));
-
-  if (!success) {
-    has_error_ = true;
-    error_message_ = error_message;
-  }
-
-  if (!total_entries_queued_) {
-    total_entries_queued_ = total_queued_to_send;
-    base::UmaHistogramCounts10000(
-        "Storage.SharedStorage.AsyncIterator.EntriesQueuedCount",
-        total_entries_queued_);
-  }
-
-  base::CheckedNumeric<int> count = entries_received_;
-  count += entries.size();
-  entries_received_ = count.ValueOrDie();
-
-  while (next_benchmark_for_receipt_ <= 100 &&
-         MeetsBenchmark(entries_received_, next_benchmark_for_receipt_)) {
-    base::UmaHistogramExactLinear(
-        "Storage.SharedStorage.AsyncIterator.ReceivedEntriesBenchmarks",
-        next_benchmark_for_receipt_, 101);
-    next_benchmark_for_receipt_ += kSharedStorageIteratorBenchmarkStep;
-  }
-
-  pending_entries_.insert(pending_entries_.end(),
-                          std::make_move_iterator(entries.begin()),
-                          std::make_move_iterator(entries.end()));
-
-  waiting_for_more_entries_ = has_more_entries;
-
-  while (
-      !pending_resolvers_.empty() &&
-      (!pending_entries_.empty() || has_error_ || !waiting_for_more_entries_)) {
-    v8::Isolate* isolate = isolate_for_pending_resolvers_;
-    DCHECK(isolate);
-
-    v8::Global<v8::Promise::Resolver> global_resolver =
-        std::move(pending_resolvers_.front());
-    pending_resolvers_.pop_front();
-
-    WorkletV8Helper::HandleScope scope(isolate);
-    v8::Local<v8::Promise::Resolver> next_resolver =
-        global_resolver.Get(isolate);
-    global_resolver.Reset();
-
-    v8::Local<v8::Context> context = next_resolver->GetCreationContextChecked();
-    v8::Context::Scope context_scope(context);
-
-    NextHelper(isolate, next_resolver);
-  }
-
-  if (pending_resolvers_.empty())
-    isolate_for_pending_resolvers_ = nullptr;
-}
-
-v8::Local<v8::Object> SharedStorageIterator::CreateIteratorResult(
-    v8::Isolate* isolate,
-    const blink::mojom::SharedStorageKeyAndOrValuePtr& entry) {
-  v8::Local<v8::Object> obj = v8::Object::New(isolate);
-  gin::Dictionary dict(isolate, obj);
-  dict.Set<bool>("done", false);
-
-  switch (mode_) {
-    case Mode::kKey:
-      dict.Set<std::u16string>("value", entry->key);
-      break;
-    case Mode::kKeyValue:
-      dict.Set<std::vector<std::u16string>>("value",
-                                            {entry->key, entry->value});
-      break;
-  }
-  return obj;
-}
-
-v8::Local<v8::Object> SharedStorageIterator::CreateIteratorResultDone(
-    v8::Isolate* isolate) {
-  v8::Local<v8::Object> obj = v8::Object::New(isolate);
-  gin::Dictionary dict(isolate, obj);
-  dict.Set<bool>("done", true);
-  return obj;
-}
-
-bool SharedStorageIterator::MeetsBenchmark(int value, int benchmark) {
-  DCHECK_GE(benchmark, 0);
-  DCHECK_LE(benchmark, 100);
-  DCHECK_EQ(benchmark % kSharedStorageIteratorBenchmarkStep, 0);
-  DCHECK_GE(total_entries_queued_, 0);
-
-  if (benchmark == 0 || (total_entries_queued_ == 0 && value == 0))
-    return true;
-
-  DCHECK_GT(total_entries_queued_, 0);
-  return (100 * value) / total_entries_queued_ >= benchmark;
-}
-
-void SharedStorageIterator::LogElapsedTime() {
-  DCHECK(!next_start_times_.empty());
-  base::TimeDelta elapsed_time =
-      base::TimeTicks::Now() - next_start_times_.front();
-  next_start_times_.pop();
-  switch (mode_) {
-    case SharedStorageIterator::Mode::kKey:
-      base::UmaHistogramMediumTimes(
-          "Storage.SharedStorage.Worklet.Timing.Keys.Next", elapsed_time);
-      break;
-    case SharedStorageIterator::Mode::kKeyValue:
-      base::UmaHistogramMediumTimes(
-          "Storage.SharedStorage.Worklet.Timing.Entries.Next", elapsed_time);
-      break;
-  }
-}
-
-}  // namespace shared_storage_worklet
diff --git a/content/services/shared_storage_worklet/shared_storage_iterator.h b/content/services/shared_storage_worklet/shared_storage_iterator.h
deleted file mode 100644
index 4fe4be1..0000000
--- a/content/services/shared_storage_worklet/shared_storage_iterator.h
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_SERVICES_SHARED_STORAGE_WORKLET_SHARED_STORAGE_ITERATOR_H_
-#define CONTENT_SERVICES_SHARED_STORAGE_WORKLET_SHARED_STORAGE_ITERATOR_H_
-
-#include <deque>
-#include <queue>
-
-#include "base/memory/raw_ptr.h"
-#include "base/time/time.h"
-#include "gin/object_template_builder.h"
-#include "gin/wrappable.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "third_party/blink/public/mojom/shared_storage/shared_storage_worklet_service.mojom.h"
-#include "v8/include/v8-forward.h"
-#include "v8/include/v8-persistent-handle.h"
-#include "v8/include/v8-promise.h"
-
-namespace shared_storage_worklet {
-
-extern const int kSharedStorageIteratorBenchmarkStep;
-
-// The async iterator type for sharedStorage.keys()/entries().
-class SharedStorageIterator final
-    : public gin::Wrappable<SharedStorageIterator>,
-      public blink::mojom::SharedStorageEntriesListener {
- public:
-  enum class Mode {
-    kKey,
-    kKeyValue,
-  };
-
-  SharedStorageIterator(
-      Mode mode,
-      blink::mojom::SharedStorageWorkletServiceClient* client);
-
-  ~SharedStorageIterator() override;
-
-  static gin::WrapperInfo kWrapperInfo;
-
-  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override;
-
-  const char* GetTypeName() override;
-
- private:
-  v8::Local<v8::Object> GetThisObject(gin::Arguments* args);
-
-  v8::Local<v8::Promise> Next(gin::Arguments* args);
-
-  v8::Local<v8::Promise> NextHelper(v8::Isolate* isolate,
-                                    v8::Local<v8::Promise::Resolver> resolver);
-
-  // blink::mojom::SharedStorageEntriesListener
-  void DidReadEntries(
-      bool success,
-      const std::string& error_message,
-      std::vector<blink::mojom::SharedStorageKeyAndOrValuePtr> entries,
-      bool has_more_entries,
-      int total_queued_to_send) override;
-
-  v8::Local<v8::Object> CreateIteratorResult(
-      v8::Isolate* isolate,
-      const blink::mojom::SharedStorageKeyAndOrValuePtr& entry);
-
-  v8::Local<v8::Object> CreateIteratorResultDone(v8::Isolate* isolate);
-
-  // Checks if `value` meets `benchmark` percentage, for purposes of histogram
-  // logging.
-  bool MeetsBenchmark(int value, int benchmark);
-
-  // Logs the elasped time for calls to `Next()` to a histogram.
-  void LogElapsedTime();
-
-  Mode mode_;
-
-  // The error state can only be set once, when the first error is encountered
-  // in the DidReadEntries() listener callback. In this state, no further
-  // listener callbacks are expected, and the outstanding and future promises
-  // will be rejected with the error message.
-  bool has_error_ = false;
-  std::string error_message_;
-
-  // The entries that are received from the browser process but not yet returned
-  // as the promise-fulfilled-value.
-  std::deque<blink::mojom::SharedStorageKeyAndOrValuePtr> pending_entries_;
-
-  // The resolvers for promises that are not yet resolved.
-  std::deque<v8::Global<v8::Promise::Resolver>> pending_resolvers_;
-
-  // This isolate is owned by SharedStorageWorkletGlobalScope::isolate_holder_.
-  raw_ptr<v8::Isolate> isolate_for_pending_resolvers_ = nullptr;
-
-  // True if we haven't got the browser process's signal for the last batch of
-  // entries. After the state is set to false, no further DidReadEntries()
-  // listener callbacks are expected.
-  bool waiting_for_more_entries_ = true;
-
-  // The total number of entries that the database has queued to send via this
-  // iterator.
-  int total_entries_queued_ = 0;
-
-  // The number of entries that the iterator has received from the database so
-  // far.
-  int entries_received_ = 0;
-
-  // The number of entries that the iterator has iterated through.
-  int entries_iterated_ = 0;
-
-  // The lowest benchmark for received entries that is currently unmet and so
-  // has not been logged.
-  int next_benchmark_for_receipt_ = 0;
-
-  // The lowest benchmark for iterated entries that is currently unmet and so
-  // has not been logged.
-  int next_benchmark_for_iteration_ = kSharedStorageIteratorBenchmarkStep;
-
-  // Start times of each call to `Next()`, in order of the call. Used to record
-  // a timing histogram.
-  std::queue<base::TimeTicks> next_start_times_;
-
-  mojo::Receiver<blink::mojom::SharedStorageEntriesListener> receiver_{this};
-};
-
-}  // namespace shared_storage_worklet
-
-#endif  // CONTENT_SERVICES_SHARED_STORAGE_WORKLET_SHARED_STORAGE_ITERATOR_H_
diff --git a/content/services/shared_storage_worklet/shared_storage_worklet_global_scope.cc b/content/services/shared_storage_worklet/shared_storage_worklet_global_scope.cc
deleted file mode 100644
index 7e4dabc8..0000000
--- a/content/services/shared_storage_worklet/shared_storage_worklet_global_scope.cc
+++ /dev/null
@@ -1,318 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/services/shared_storage_worklet/shared_storage_worklet_global_scope.h"
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/functional/bind.h"
-#include "base/functional/callback.h"
-#include "base/functional/callback_helpers.h"
-#include "base/task/single_thread_task_runner.h"
-#include "content/services/shared_storage_worklet/console.h"
-#include "content/services/shared_storage_worklet/private_aggregation.h"
-#include "content/services/shared_storage_worklet/shared_storage.h"
-#include "content/services/shared_storage_worklet/unnamed_operation_handler.h"
-#include "content/services/shared_storage_worklet/url_selection_operation_handler.h"
-#include "content/services/shared_storage_worklet/worklet_v8_helper.h"
-#include "gin/arguments.h"
-#include "gin/function_template.h"
-#include "gin/public/isolate_holder.h"
-#include "gin/v8_initializer.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "third_party/blink/public/common/shared_storage/module_script_downloader.h"
-#include "third_party/blink/public/common/shared_storage/shared_storage_utils.h"
-#include "third_party/blink/public/mojom/private_aggregation/private_aggregation_host.mojom.h"
-#include "v8/include/v8-context.h"
-#include "v8/include/v8-function.h"
-#include "v8/include/v8-initialization.h"
-#include "v8/include/v8-local-handle.h"
-#include "v8/include/v8-object.h"
-
-namespace shared_storage_worklet {
-
-namespace {
-
-// Initialize V8 (and gin).
-void InitV8() {
-#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
-  gin::V8Initializer::LoadV8Snapshot();
-#endif
-
-  gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode,
-                                 gin::ArrayBufferAllocator::SharedInstance());
-}
-
-}  // namespace
-
-SharedStorageWorkletGlobalScope::SharedStorageWorkletGlobalScope(
-    bool private_aggregation_permissions_policy_allowed,
-    const absl::optional<std::u16string>& embedder_context)
-    : private_aggregation_permissions_policy_allowed_(
-          private_aggregation_permissions_policy_allowed),
-      embedder_context_(embedder_context) {}
-
-SharedStorageWorkletGlobalScope::~SharedStorageWorkletGlobalScope() = default;
-
-void SharedStorageWorkletGlobalScope::AddModule(
-    mojo::PendingRemote<network::mojom::URLLoaderFactory>
-        pending_url_loader_factory,
-    blink::mojom::SharedStorageWorkletServiceClient* client,
-    const GURL& script_source_url,
-    blink::mojom::SharedStorageWorkletService::AddModuleCallback callback) {
-  mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory(
-      std::move(pending_url_loader_factory));
-
-  module_script_downloader_ = std::make_unique<blink::ModuleScriptDownloader>(
-      url_loader_factory.get(), script_source_url,
-      base::BindOnce(&SharedStorageWorkletGlobalScope::OnModuleScriptDownloaded,
-                     weak_ptr_factory_.GetWeakPtr(), client, script_source_url,
-                     std::move(callback)));
-}
-
-void SharedStorageWorkletGlobalScope::OnModuleScriptDownloaded(
-    blink::mojom::SharedStorageWorkletServiceClient* client,
-    const GURL& script_source_url,
-    blink::mojom::SharedStorageWorkletService::AddModuleCallback callback,
-    std::unique_ptr<std::string> response_body,
-    std::string error_message) {
-  module_script_downloader_.reset();
-
-  if (!response_body) {
-    std::move(callback).Run(false, error_message);
-    return;
-  }
-
-  DCHECK(error_message.empty());
-
-  // Now the module script is downloaded, initialize the worklet environment.
-  InitV8();
-
-  // TODO(yaoxia): we may need a new IsolateType here. For now, set it to
-  // `kBlinkWorkerThread` even though it's not technically for blink worker:
-  // this is the best approximate type and is the only type that allows multiple
-  // isolates in one process (see CanHaveMultipleIsolates(isolate_type) in
-  // gin/v8_isolate_memory_dump_provider.cc).
-  isolate_holder_ = std::make_unique<gin::IsolateHolder>(
-      base::SingleThreadTaskRunner::GetCurrentDefault(),
-      gin::IsolateHolder::kSingleThread,
-      gin::IsolateHolder::IsolateType::kBlinkWorkerThread);
-
-  WorkletV8Helper::HandleScope scope(Isolate());
-  global_context_.Reset(Isolate(), v8::Context::New(Isolate()));
-
-  v8::Local<v8::Context> context = LocalContext();
-  v8::Context::Scope context_scope(context);
-
-  v8::Local<v8::Object> global = context->Global();
-
-  url_selection_operation_handler_ =
-      std::make_unique<UrlSelectionOperationHandler>(operation_definition_map_);
-
-  unnamed_operation_handler_ =
-      std::make_unique<UnnamedOperationHandler>(operation_definition_map_);
-
-  console_ = std::make_unique<Console>(client);
-  global
-      ->Set(context, gin::StringToSymbol(Isolate(), "console"),
-            console_->GetWrapper(Isolate()).ToLocalChecked())
-      .Check();
-
-  global
-      ->Set(context, gin::StringToSymbol(Isolate(), "register"),
-            gin::CreateFunctionTemplate(
-                Isolate(),
-                base::BindRepeating(&SharedStorageWorkletGlobalScope::Register,
-                                    weak_ptr_factory_.GetWeakPtr()))
-                ->GetFunction(context)
-                .ToLocalChecked())
-      .Check();
-
-  // Execute the module script.
-  v8::MaybeLocal<v8::Value> result = WorkletV8Helper::CompileAndRunScript(
-      context, *response_body, script_source_url, &error_message);
-
-  if (result.IsEmpty()) {
-    std::move(callback).Run(false, error_message);
-    return;
-  }
-
-  DCHECK(error_message.empty());
-
-  // After the module script execution, create and expose the shared storage
-  // and private aggregation object.
-  shared_storage_ = std::make_unique<SharedStorage>(client, embedder_context_);
-  context->Global()
-      ->Set(context, gin::StringToSymbol(Isolate(), "sharedStorage"),
-            shared_storage_->GetWrapper(Isolate()).ToLocalChecked())
-      .Check();
-
-  if (blink::ShouldDefinePrivateAggregationInSharedStorage()) {
-    private_aggregation_ = std::make_unique<PrivateAggregation>(
-        *client, private_aggregation_permissions_policy_allowed_, *this);
-    global
-        ->Set(context, gin::StringToSymbol(Isolate(), "privateAggregation"),
-              private_aggregation_->GetWrapper(Isolate()).ToLocalChecked())
-        .Check();
-  }
-
-  std::move(callback).Run(true, {});
-}
-
-void SharedStorageWorkletGlobalScope::RunURLSelectionOperation(
-    const std::string& name,
-    const std::vector<GURL>& urls,
-    const std::vector<uint8_t>& serialized_data,
-    mojo::PendingRemote<blink::mojom::PrivateAggregationHost>
-        private_aggregation_host,
-    blink::mojom::SharedStorageWorkletService::RunURLSelectionOperationCallback
-        callback) {
-  if (!isolate_holder_) {
-    // TODO(yaoxia): if this operation comes while fetching the module script,
-    // we might want to queue the operation to be handled later after addModule
-    // completes. http://crbug/1249581
-    std::move(callback).Run(
-        /*success=*/false,
-        /*error_message=*/"The module script hasn't been loaded.",
-        /*length=*/0);
-    return;
-  }
-
-  WorkletV8Helper::HandleScope scope(Isolate());
-  base::OnceClosure operation_completion_cb =
-      StartOperation(std::move(private_aggregation_host));
-  url_selection_operation_handler_->RunOperation(
-      LocalContext(), name, urls, serialized_data,
-      std::move(callback).Then(std::move(operation_completion_cb)));
-}
-
-void SharedStorageWorkletGlobalScope::RunOperation(
-    const std::string& name,
-    const std::vector<uint8_t>& serialized_data,
-    mojo::PendingRemote<blink::mojom::PrivateAggregationHost>
-        private_aggregation_host,
-    blink::mojom::SharedStorageWorkletService::RunOperationCallback callback) {
-  if (!isolate_holder_) {
-    // TODO(yaoxia): if this operation comes while fetching the module script,
-    // we might want to queue the operation to be handled later after addModule
-    // completes. http://crbug/1249581
-    std::move(callback).Run(
-        /*success=*/false,
-        /*error_message=*/"The module script hasn't been loaded.");
-    return;
-  }
-
-  WorkletV8Helper::HandleScope scope(Isolate());
-  base::OnceClosure operation_completion_cb =
-      StartOperation(std::move(private_aggregation_host));
-  unnamed_operation_handler_->RunOperation(
-      LocalContext(), name, serialized_data,
-      std::move(callback).Then(std::move(operation_completion_cb)));
-}
-
-void SharedStorageWorkletGlobalScope::Register(gin::Arguments* args) {
-  std::string name;
-  if (!args->GetNext(&name)) {
-    args->ThrowTypeError("Missing \"name\" argument in operation registration");
-    return;
-  }
-
-  if (name.empty()) {
-    args->ThrowTypeError("Operation name cannot be empty");
-    return;
-  }
-
-  if (operation_definition_map_.count(name)) {
-    args->ThrowTypeError("Operation name already registered");
-    return;
-  }
-
-  v8::Local<v8::Object> class_definition;
-  if (!args->GetNext(&class_definition)) {
-    args->ThrowTypeError(
-        "Missing class name argument in operation registration");
-    return;
-  }
-
-  if (!class_definition->IsConstructor()) {
-    args->ThrowTypeError("Unexpected class argument: not a constructor");
-    return;
-  }
-
-  v8::Isolate* isolate = args->isolate();
-  v8::Local<v8::Context> context = args->GetHolderCreationContext();
-
-  v8::Local<v8::Value> class_prototype =
-      class_definition->Get(context, gin::StringToV8(isolate, "prototype"))
-          .ToLocalChecked();
-
-  if (!class_prototype->IsObject()) {
-    args->ThrowTypeError("Unexpected class prototype: not an object");
-    return;
-  }
-
-  v8::Local<v8::Value> run_function =
-      class_prototype.As<v8::Object>()
-          ->Get(context, gin::StringToV8(isolate, "run"))
-          .ToLocalChecked();
-
-  if (run_function->IsUndefined() || !run_function->IsFunction()) {
-    args->ThrowTypeError("Missing \"run()\" function in the class");
-    return;
-  }
-
-  operation_definition_map_.emplace(
-      name, v8::Global<v8::Function>(isolate, run_function.As<v8::Function>()));
-}
-
-base::OnceClosure SharedStorageWorkletGlobalScope::StartOperationForTesting(
-    mojo::PendingRemote<blink::mojom::PrivateAggregationHost>
-        private_aggregation_host) {
-  return StartOperation(std::move(private_aggregation_host));
-}
-
-base::OnceClosure SharedStorageWorkletGlobalScope::StartOperation(
-    mojo::PendingRemote<blink::mojom::PrivateAggregationHost>
-        private_aggregation_host) {
-  CHECK_EQ(!!private_aggregation_host, !!private_aggregation_);
-  int64_t operation_id = operation_counter_++;
-
-  v8::Local<v8::Context> context = LocalContext();
-
-  context->SetContinuationPreservedEmbedderData(
-      v8::BigInt::New(context->GetIsolate(), operation_id));
-
-  if (private_aggregation_) {
-    private_aggregation_->OnOperationStarted(
-        operation_id, std::move(private_aggregation_host));
-  }
-  return base::BindOnce(&SharedStorageWorkletGlobalScope::FinishOperation,
-                        weak_ptr_factory_.GetWeakPtr(), operation_id);
-}
-
-void SharedStorageWorkletGlobalScope::FinishOperation(int64_t operation_id) {
-  if (private_aggregation_) {
-    private_aggregation_->OnOperationFinished(operation_id);
-  }
-}
-
-int64_t SharedStorageWorkletGlobalScope::GetCurrentOperationId() const {
-  v8::Local<v8::Value> data =
-      LocalContext()->GetContinuationPreservedEmbedderData();
-  return data.As<v8::BigInt>()->Int64Value();
-}
-
-v8::Isolate* SharedStorageWorkletGlobalScope::Isolate() const {
-  return isolate_holder_->isolate();
-}
-
-v8::Local<v8::Context> SharedStorageWorkletGlobalScope::LocalContext() const {
-  return global_context_.Get(Isolate());
-}
-
-}  // namespace shared_storage_worklet
diff --git a/content/services/shared_storage_worklet/shared_storage_worklet_global_scope.h b/content/services/shared_storage_worklet/shared_storage_worklet_global_scope.h
deleted file mode 100644
index 761b708..0000000
--- a/content/services/shared_storage_worklet/shared_storage_worklet_global_scope.h
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_SERVICES_SHARED_STORAGE_WORKLET_SHARED_STORAGE_WORKLET_GLOBAL_SCOPE_H_
-#define CONTENT_SERVICES_SHARED_STORAGE_WORKLET_SHARED_STORAGE_WORKLET_GLOBAL_SCOPE_H_
-
-#include <stdint.h>
-
-#include "base/functional/callback_forward.h"
-#include "content/common/content_export.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "services/network/public/mojom/url_loader_factory.mojom.h"
-#include "third_party/blink/public/mojom/private_aggregation/private_aggregation_host.mojom-forward.h"
-#include "third_party/blink/public/mojom/shared_storage/shared_storage_worklet_service.mojom.h"
-#include "v8/include/v8-forward.h"
-#include "v8/include/v8-persistent-handle.h"
-
-namespace gin {
-class IsolateHolder;
-class Arguments;
-}  // namespace gin
-
-namespace blink {
-class ModuleScriptDownloader;
-}  // namespace blink
-
-namespace shared_storage_worklet {
-
-class UrlSelectionOperationHandler;
-class UnnamedOperationHandler;
-class Console;
-class PrivateAggregation;
-class SharedStorage;
-
-// The global JS execution context for shared storage worklet. It holds a
-// v8::Isolate and a v8::Context to execute all worklet operations. Members are
-// initialized only after AddModule() succeeds.
-// https://github.com/pythagoraskitty/shared-storage/blob/main/README.md
-class CONTENT_EXPORT SharedStorageWorkletGlobalScope {
- public:
-  SharedStorageWorkletGlobalScope(
-      bool private_aggregation_permissions_policy_allowed,
-      const absl::optional<std::u16string>& embedder_context);
-  ~SharedStorageWorkletGlobalScope();
-
-  void AddModule(
-      mojo::PendingRemote<network::mojom::URLLoaderFactory>
-          pending_url_loader_factory,
-      blink::mojom::SharedStorageWorkletServiceClient* client,
-      const GURL& script_source_url,
-      blink::mojom::SharedStorageWorkletService::AddModuleCallback callback);
-
-  void OnModuleScriptDownloaded(
-      blink::mojom::SharedStorageWorkletServiceClient* client,
-      const GURL& script_source_url,
-      blink::mojom::SharedStorageWorkletService::AddModuleCallback callback,
-      std::unique_ptr<std::string> response_body,
-      std::string error_message);
-
-  void RunURLSelectionOperation(
-      const std::string& name,
-      const std::vector<GURL>& urls,
-      const std::vector<uint8_t>& serialized_data,
-      mojo::PendingRemote<blink::mojom::PrivateAggregationHost>
-          private_aggregation_host,
-      blink::mojom::SharedStorageWorkletService::
-          RunURLSelectionOperationCallback callback);
-
-  void RunOperation(
-      const std::string& name,
-      const std::vector<uint8_t>& serialized_data,
-      mojo::PendingRemote<blink::mojom::PrivateAggregationHost>
-          private_aggregation_host,
-      blink::mojom::SharedStorageWorkletService::RunOperationCallback callback);
-
-  base::OnceClosure StartOperationForTesting(
-      mojo::PendingRemote<blink::mojom::PrivateAggregationHost>
-          private_aggregation_host);
-
-  // Returns the unique ID for the currently running operation.
-  int64_t GetCurrentOperationId() const;
-
- private:
-  void Register(gin::Arguments* args);
-
-  friend class SharedStorageWorkletGlobalScopeTest;
-
-  // Sets continuation-preserved embedder data to allow us to identify this
-  // particular operation invocation later, even after asynchronous operations.
-  // Returns a closure that should be run when the operation finishes.
-  base::OnceClosure StartOperation(
-      mojo::PendingRemote<blink::mojom::PrivateAggregationHost>
-          private_aggregation_host);
-
-  // Notifies the `private_aggregation_` that the operation with the given ID
-  // has finished.
-  void FinishOperation(int64_t operation_id);
-
-  v8::Isolate* Isolate() const;
-
-  v8::Local<v8::Context> LocalContext() const;
-
-  bool private_aggregation_permissions_policy_allowed_;
-
-  std::unique_ptr<blink::ModuleScriptDownloader> module_script_downloader_;
-
-  std::unique_ptr<gin::IsolateHolder> isolate_holder_;
-  v8::Global<v8::Context> global_context_;
-
-  std::unique_ptr<Console> console_;
-  std::unique_ptr<PrivateAggregation> private_aggregation_;
-  std::unique_ptr<SharedStorage> shared_storage_;
-
-  std::unique_ptr<UrlSelectionOperationHandler>
-      url_selection_operation_handler_;
-  std::unique_ptr<UnnamedOperationHandler> unnamed_operation_handler_;
-
-  std::map<std::string, v8::Global<v8::Function>> operation_definition_map_;
-
-  int64_t operation_counter_ = 0;
-
-  // If this worklet is inside a fenced frame or a URN iframe,
-  // `embedder_context_` represents any contextual information written to the
-  // frame's `blink::FencedFrameConfig` by the embedder before navigation to the
-  // config. `embedder_context_` is passed to the worklet upon initialization.
-  absl::optional<std::u16string> embedder_context_;
-
-  base::WeakPtrFactory<SharedStorageWorkletGlobalScope> weak_ptr_factory_{this};
-};
-
-}  // namespace shared_storage_worklet
-
-#endif  // CONTENT_SERVICES_SHARED_STORAGE_WORKLET_SHARED_STORAGE_WORKLET_GLOBAL_SCOPE_H_
diff --git a/content/services/shared_storage_worklet/shared_storage_worklet_global_scope_unittest.cc b/content/services/shared_storage_worklet/shared_storage_worklet_global_scope_unittest.cc
deleted file mode 100644
index 32ccbdf..0000000
--- a/content/services/shared_storage_worklet/shared_storage_worklet_global_scope_unittest.cc
+++ /dev/null
@@ -1,2682 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/services/shared_storage_worklet/shared_storage_worklet_global_scope.h"
-
-#include "base/check_op.h"
-#include "base/task/single_thread_task_runner.h"
-#include "base/test/bind.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/test/task_environment.h"
-#include "content/services/shared_storage_worklet/worklet_v8_helper.h"
-#include "gin/arguments.h"
-#include "gin/converter.h"
-#include "gin/dictionary.h"
-#include "gin/function_template.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/abseil-cpp/absl/numeric/int128.h"
-#include "third_party/blink/public/common/features.h"
-#include "third_party/blink/public/common/shared_storage/shared_storage_utils.h"
-#include "third_party/blink/public/mojom/private_aggregation/aggregatable_report.mojom.h"
-#include "third_party/blink/public/mojom/private_aggregation/private_aggregation_host.mojom.h"
-#include "third_party/blink/public/mojom/shared_storage/shared_storage_worklet_service.mojom.h"
-#include "v8/include/v8-context.h"
-#include "v8/include/v8-function.h"
-#include "v8/include/v8-value-serializer.h"
-
-namespace shared_storage_worklet {
-
-namespace {
-
-constexpr char WorkletContextDefinedHistogram[] =
-    "Storage.SharedStorage.Worklet.Context.IsDefined";
-
-std::vector<blink::mojom::SharedStorageKeyAndOrValuePtr> CreateBatchResult(
-    std::vector<std::pair<std::u16string, std::u16string>> input) {
-  std::vector<blink::mojom::SharedStorageKeyAndOrValuePtr> result;
-  for (const auto& p : input) {
-    blink::mojom::SharedStorageKeyAndOrValuePtr e =
-        blink::mojom::SharedStorageKeyAndOrValue::New(p.first, p.second);
-    result.push_back(std::move(e));
-  }
-  return result;
-}
-
-std::vector<uint8_t> Serialize(v8::Isolate* isolate,
-                               v8::Local<v8::Context> context,
-                               v8::Local<v8::Value> v8_value) {
-  v8::ValueSerializer serializer(isolate);
-
-  bool wrote_value;
-  CHECK(serializer.WriteValue(context, v8_value).To(&wrote_value));
-  CHECK(wrote_value);
-
-  std::pair<uint8_t*, size_t> buffer = serializer.Release();
-
-  std::vector<uint8_t> serialized_data(buffer.first,
-                                       buffer.first + buffer.second);
-
-  DCHECK_EQ(serialized_data.size(), buffer.second);
-
-  free(buffer.first);
-
-  return serialized_data;
-}
-
-struct SetParams {
-  std::u16string key;
-  std::u16string value;
-  bool ignore_if_present;
-};
-
-struct AppendParams {
-  std::u16string key;
-  std::u16string value;
-};
-
-class TestClient : public blink::mojom::SharedStorageWorkletServiceClient {
- public:
-  explicit TestClient(scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-      : task_runner_(task_runner) {}
-
-  void SharedStorageSet(const std::u16string& key,
-                        const std::u16string& value,
-                        bool ignore_if_present,
-                        SharedStorageSetCallback callback) override {
-    observed_set_params_.push_back({key, value, ignore_if_present});
-
-    task_runner_->PostTask(
-        FROM_HERE,
-        base::BindLambdaForTesting([callback = std::move(callback)]() mutable {
-          std::move(callback).Run(/*success=*/true, /*error_message=*/{});
-        }));
-  }
-
-  void SharedStorageAppend(const std::u16string& key,
-                           const std::u16string& value,
-                           SharedStorageAppendCallback callback) override {
-    observed_append_params_.push_back({key, value});
-
-    task_runner_->PostTask(
-        FROM_HERE,
-        base::BindLambdaForTesting([callback = std::move(callback)]() mutable {
-          std::move(callback).Run(
-              /*success=*/false,
-              /*error_message=*/"testing error message for append");
-        }));
-  }
-
-  void SharedStorageDelete(const std::u16string& key,
-                           SharedStorageDeleteCallback callback) override {
-    observed_delete_params_.push_back(key);
-  }
-
-  void SharedStorageClear(SharedStorageClearCallback callback) override {}
-
-  void SharedStorageGet(const std::u16string& key,
-                        SharedStorageGetCallback callback) override {
-    observed_get_params_.push_back(key);
-
-    task_runner_->PostTask(
-        FROM_HERE,
-        base::BindLambdaForTesting([callback = std::move(callback)]() mutable {
-          std::move(callback).Run(
-              blink::mojom::SharedStorageGetStatus::kSuccess,
-              /*error_message=*/{},
-              /*value=*/u"test-value");
-        }));
-  }
-
-  void SharedStorageKeys(
-      mojo::PendingRemote<blink::mojom::SharedStorageEntriesListener>
-          pending_listener) override {
-    pending_keys_listeners_.push_back(std::move(pending_listener));
-  }
-
-  void SharedStorageEntries(
-      mojo::PendingRemote<blink::mojom::SharedStorageEntriesListener>
-          pending_listener) override {
-    pending_entries_listeners_.push_back(std::move(pending_listener));
-  }
-
-  void SharedStorageLength(SharedStorageLengthCallback callback) override {
-    task_runner_->PostTask(
-        FROM_HERE,
-        base::BindLambdaForTesting([callback = std::move(callback)]() mutable {
-          std::move(callback).Run(
-              /*success=*/true,
-              /*error_message=*/{},
-              /*length=*/1);
-        }));
-  }
-
-  void SharedStorageRemainingBudget(
-      SharedStorageRemainingBudgetCallback callback) override {
-    task_runner_->PostTask(
-        FROM_HERE,
-        base::BindLambdaForTesting([callback = std::move(callback)]() mutable {
-          std::move(callback).Run(
-              /*success=*/true,
-              /*error_message=*/{},
-              /*bits=*/2.5);
-        }));
-  }
-
-  void ConsoleLog(const std::string& message) override {
-    observed_console_log_messages_.push_back(message);
-  }
-
-  void RecordUseCounters(
-      const std::vector<blink::mojom::WebFeature>& features) override {
-    ASSERT_THAT(
-        features,
-        testing::UnorderedElementsAre(
-            blink::mojom::WebFeature::kPrivateAggregationApiAll,
-            blink::mojom::WebFeature::kPrivateAggregationApiSharedStorage));
-    observed_record_use_counter_call_ = true;
-  }
-
-  const std::vector<SetParams>& observed_set_params() const {
-    return observed_set_params_;
-  }
-
-  const std::vector<AppendParams>& observed_append_params() const {
-    return observed_append_params_;
-  }
-
-  const std::vector<std::u16string>& observed_delete_params() const {
-    return observed_delete_params_;
-  }
-
-  const std::vector<std::u16string>& observed_get_params() const {
-    return observed_get_params_;
-  }
-
-  bool observed_record_use_counter_call() const {
-    return observed_record_use_counter_call_;
-  }
-
-  const std::vector<std::string>& observed_console_log_messages() const {
-    return observed_console_log_messages_;
-  }
-
-  size_t pending_keys_listeners_count() const {
-    return pending_keys_listeners_.size();
-  }
-
-  size_t pending_entries_listeners_count() const {
-    return pending_entries_listeners_.size();
-  }
-
-  mojo::Remote<blink::mojom::SharedStorageEntriesListener>
-  OfferKeysListenerAtFront() {
-    CHECK(!pending_keys_listeners_.empty());
-
-    auto pending_listener = std::move(pending_keys_listeners_.front());
-    pending_keys_listeners_.pop_front();
-
-    return mojo::Remote<blink::mojom::SharedStorageEntriesListener>(
-        std::move(pending_listener));
-  }
-
-  mojo::Remote<blink::mojom::SharedStorageEntriesListener>
-  OfferEntriesListenerAtFront() {
-    CHECK(!pending_entries_listeners_.empty());
-
-    auto pending_listener = std::move(pending_entries_listeners_.front());
-    pending_entries_listeners_.pop_front();
-
-    return mojo::Remote<blink::mojom::SharedStorageEntriesListener>(
-        std::move(pending_listener));
-  }
-
- private:
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-
-  std::deque<mojo::PendingRemote<blink::mojom::SharedStorageEntriesListener>>
-      pending_keys_listeners_;
-
-  std::deque<mojo::PendingRemote<blink::mojom::SharedStorageEntriesListener>>
-      pending_entries_listeners_;
-
-  std::vector<SetParams> observed_set_params_;
-  std::vector<AppendParams> observed_append_params_;
-  std::vector<std::u16string> observed_delete_params_;
-  std::vector<std::u16string> observed_get_params_;
-  std::vector<std::string> observed_console_log_messages_;
-  bool observed_record_use_counter_call_ = false;
-};
-
-class MockMojomPrivateAggregationHost
-    : public blink::mojom::PrivateAggregationHost {
- public:
-  // blink::mojom::PrivateAggregationHost:
-  MOCK_METHOD(
-      void,
-      SendHistogramReport,
-      (std::vector<blink::mojom::AggregatableReportHistogramContributionPtr>,
-       blink::mojom::AggregationServiceMode,
-       blink::mojom::DebugModeDetailsPtr),
-      (override));
-};
-
-}  // namespace
-
-class SharedStorageWorkletGlobalScopeTest : public testing::Test {
- public:
-  SharedStorageWorkletGlobalScopeTest()
-      : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
-    test_client_ = std::make_unique<TestClient>(
-        task_environment_.GetMainThreadTaskRunner());
-    mock_private_aggregation_host_ =
-        std::make_unique<MockMojomPrivateAggregationHost>();
-    global_scope_ = std::make_unique<SharedStorageWorkletGlobalScope>(
-        /*private_aggregation_permissions_policy_allowed=*/true,
-        /*embedder_context=*/absl::nullopt);
-  }
-
-  ~SharedStorageWorkletGlobalScopeTest() override = default;
-
-  v8::Isolate* Isolate() { return global_scope_->Isolate(); }
-
-  bool IsolateInitialized() { return !!global_scope_->isolate_holder_; }
-
-  v8::Local<v8::Context> LocalContext() {
-    return global_scope_->LocalContext();
-  }
-
-  void OverrideGlobalScope(
-      std::unique_ptr<SharedStorageWorkletGlobalScope> global_scope) {
-    global_scope_ = std::move(global_scope);
-  }
-
-  v8::Local<v8::Value> EvalJs(const std::string& src) {
-    std::string error_message;
-    return WorkletV8Helper::CompileAndRunScript(LocalContext(), src,
-                                                GURL("https://example.test"),
-                                                &error_message)
-        .ToLocalChecked();
-  }
-
-  std::string GetTypeOf(std::string operand) {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    v8::Local<v8::Context> context = LocalContext();
-    v8::Context::Scope context_scope(context);
-
-    v8::Local<v8::Value> result = EvalJs("typeof " + operand);
-    return gin::V8ToString(Isolate(), result);
-  }
-
-  void RegisterAsyncReturnForTesting() {
-    WorkletV8Helper::HandleScope scope(Isolate());
-
-    v8::Local<v8::Context> context = global_scope_->LocalContext();
-    v8::Context::Scope context_scope(context);
-
-    v8::Local<v8::Object> global = context->Global();
-
-    global
-        ->Set(context, gin::StringToSymbol(Isolate(), "asyncFulfillForTesting"),
-              gin::CreateFunctionTemplate(
-                  Isolate(),
-                  base::BindRepeating(&SharedStorageWorkletGlobalScopeTest::
-                                          AsyncFulfillForTesting,
-                                      base::Unretained(this)))
-                  ->GetFunction(context)
-                  .ToLocalChecked())
-        .Check();
-
-    global
-        ->Set(
-            context, gin::StringToSymbol(Isolate(), "asyncRejectForTesting"),
-            gin::CreateFunctionTemplate(
-                Isolate(),
-                base::BindRepeating(
-                    &SharedStorageWorkletGlobalScopeTest::AsyncRejectForTesting,
-                    base::Unretained(this)))
-                ->GetFunction(context)
-                .ToLocalChecked())
-        .Check();
-  }
-
-  v8::Local<v8::Promise> AsyncFulfillForTesting(gin::Arguments* args) {
-    std::vector<v8::Local<v8::Value>> v8_args = args->GetAll();
-
-    v8::Local<v8::Value> val =
-        !v8_args.empty()
-            ? v8_args[0]
-            : v8::Local<v8::Value>(v8::Object::New(args->isolate()));
-
-    v8::Local<v8::Promise::Resolver> resolver =
-        v8::Promise::Resolver::New(args->GetHolderCreationContext())
-            .ToLocalChecked();
-
-    v8::Local<v8::Promise> promise = resolver->GetPromise();
-
-    task_environment_.GetMainThreadTaskRunner()->PostTask(
-        FROM_HERE,
-        base::BindLambdaForTesting(
-            [isolate = args->isolate(),
-             global_val = v8::Global<v8::Value>(args->isolate(), val),
-             global_resolver = v8::Global<v8::Promise::Resolver>(
-                 args->isolate(), resolver)]() mutable {
-              WorkletV8Helper::HandleScope scope(isolate);
-              v8::Local<v8::Value> val = global_val.Get(isolate);
-              v8::Local<v8::Promise::Resolver> resolver =
-                  global_resolver.Get(isolate);
-              v8::Local<v8::Context> context =
-                  resolver->GetCreationContextChecked();
-              resolver->Resolve(context, val).ToChecked();
-            }));
-
-    return promise;
-  }
-
-  v8::Local<v8::Promise> AsyncRejectForTesting(gin::Arguments* args) {
-    std::vector<v8::Local<v8::Value>> v8_args = args->GetAll();
-
-    v8::Local<v8::Value> val =
-        !v8_args.empty()
-            ? v8_args[0]
-            : v8::Local<v8::Value>(v8::Object::New(args->isolate()));
-
-    v8::Local<v8::Promise::Resolver> resolver =
-        v8::Promise::Resolver::New(args->GetHolderCreationContext())
-            .ToLocalChecked();
-
-    v8::Local<v8::Promise> promise = resolver->GetPromise();
-
-    task_environment_.GetMainThreadTaskRunner()->PostTask(
-        FROM_HERE,
-        base::BindLambdaForTesting(
-            [isolate = args->isolate(),
-             global_val = v8::Global<v8::Value>(args->isolate(), val),
-             global_resolver = v8::Global<v8::Promise::Resolver>(
-                 args->isolate(), resolver)]() mutable {
-              WorkletV8Helper::HandleScope scope(isolate);
-              v8::Local<v8::Value> val = global_val.Get(isolate);
-              v8::Local<v8::Promise::Resolver> resolver =
-                  global_resolver.Get(isolate);
-              v8::Local<v8::Context> context =
-                  resolver->GetCreationContextChecked();
-              resolver->Reject(context, val).ToChecked();
-            }));
-
-    return promise;
-  }
-
-  TestClient* test_client() { return test_client_.get(); }
-  MockMojomPrivateAggregationHost* mock_private_aggregation_host() {
-    return mock_private_aggregation_host_.get();
-  }
-
-  mojo::PendingRemote<blink::mojom::PrivateAggregationHost>
-  InitNewRemotePAHost() {
-    mojo::PendingRemote<blink::mojom::PrivateAggregationHost> remote;
-    if (blink::ShouldDefinePrivateAggregationInSharedStorage()) {
-      mock_private_aggregation_host_receiver_set_.Add(
-          mock_private_aggregation_host_.get(),
-          remote.InitWithNewPipeAndPassReceiver());
-    }
-    return remote;
-  }
-
- protected:
-  base::test::SingleThreadTaskEnvironment task_environment_;
-
-  std::unique_ptr<TestClient> test_client_;
-  std::unique_ptr<MockMojomPrivateAggregationHost>
-      mock_private_aggregation_host_;
-  mojo::ReceiverSet<blink::mojom::PrivateAggregationHost>
-      mock_private_aggregation_host_receiver_set_;
-
-  std::unique_ptr<SharedStorageWorkletGlobalScope> global_scope_;
-};
-
-TEST_F(SharedStorageWorkletGlobalScopeTest, IsolateNotInitializedByDefault) {
-  EXPECT_FALSE(IsolateInitialized());
-}
-
-TEST_F(SharedStorageWorkletGlobalScopeTest, OnModuleScriptDownloadedSuccess) {
-  global_scope_->OnModuleScriptDownloaded(
-      test_client_.get(), GURL("https://example.test"), base::DoNothing(),
-      /*response_body=*/std::make_unique<std::string>(),
-      /*error_message=*/{});
-
-  EXPECT_TRUE(IsolateInitialized());
-
-  EXPECT_EQ(GetTypeOf("console"), "object");
-  EXPECT_EQ(GetTypeOf("console.log"), "function");
-  EXPECT_EQ(GetTypeOf("register"), "function");
-  EXPECT_EQ(GetTypeOf("sharedStorage"), "object");
-  EXPECT_EQ(GetTypeOf("sharedStorage.set"), "function");
-  EXPECT_EQ(GetTypeOf("sharedStorage.append"), "function");
-  EXPECT_EQ(GetTypeOf("sharedStorage.delete"), "function");
-  EXPECT_EQ(GetTypeOf("sharedStorage.clear"), "function");
-  EXPECT_EQ(GetTypeOf("sharedStorage.get"), "function");
-  EXPECT_EQ(GetTypeOf("sharedStorage.keys"), "function");
-  EXPECT_EQ(GetTypeOf("sharedStorage.entries"), "function");
-  EXPECT_EQ(GetTypeOf("sharedStorage.length"), "function");
-  EXPECT_EQ(GetTypeOf("sharedStorage.remainingBudget"), "function");
-  EXPECT_EQ(GetTypeOf("sharedStorage.context"), "undefined");
-  EXPECT_EQ(GetTypeOf("privateAggregation"), "undefined");
-}
-
-TEST_F(SharedStorageWorkletGlobalScopeTest, OnModuleScriptDownloadedWithError) {
-  bool callback_called = false;
-  auto cb = base::BindLambdaForTesting(
-      [&](bool success, const std::string& error_message) {
-        EXPECT_FALSE(success);
-        EXPECT_EQ(error_message, "error1");
-        callback_called = true;
-      });
-
-  global_scope_->OnModuleScriptDownloaded(test_client_.get(),
-                                          GURL("https://example.test"),
-                                          std::move(cb), nullptr, "error1");
-
-  EXPECT_FALSE(IsolateInitialized());
-  EXPECT_TRUE(callback_called);
-}
-
-TEST_F(SharedStorageWorkletGlobalScopeTest,
-       OnModuleScriptDownloadedWithoutPrivateAggregationHost) {
-  global_scope_->OnModuleScriptDownloaded(
-      test_client_.get(), GURL("https://example.test"), base::DoNothing(),
-      /*response_body=*/std::make_unique<std::string>(),
-      /*error_message=*/{});
-
-  EXPECT_TRUE(IsolateInitialized());
-
-  EXPECT_EQ(GetTypeOf("privateAggregation"), "undefined");
-}
-
-class SharedStorageAddModuleTest : public SharedStorageWorkletGlobalScopeTest {
- public:
-  void SimulateAddModule(const std::string& script_body) {
-    bool callback_called = false;
-
-    auto cb = base::BindLambdaForTesting(
-        [&](bool success, const std::string& error_message) {
-          success_ = success;
-          error_message_ = error_message;
-
-          callback_called = true;
-        });
-
-    global_scope_->OnModuleScriptDownloaded(
-        test_client_.get(), GURL("https://example.test"), std::move(cb),
-        std::make_unique<std::string>(script_body), /*error_message=*/{});
-
-    ASSERT_TRUE(callback_called);
-  }
-
-  bool success() const { return success_; }
-
-  const std::string& error_message() const { return error_message_; }
-
- private:
-  bool success_ = false;
-  std::string error_message_;
-};
-
-TEST_F(SharedStorageAddModuleTest, VanillaScriptSuccess) {
-  SimulateAddModule(R"(
-    a = 1;
-  )");
-
-  EXPECT_TRUE(success());
-  EXPECT_TRUE(error_message().empty());
-  EXPECT_EQ(GetTypeOf("a"), "number");
-}
-
-TEST_F(SharedStorageAddModuleTest, VanillaScriptError) {
-  SimulateAddModule(R"(
-    a;
-  )");
-
-  EXPECT_FALSE(success());
-  EXPECT_EQ(
-      error_message(),
-      "https://example.test/:2 Uncaught ReferenceError: a is not defined.");
-}
-
-TEST_F(SharedStorageAddModuleTest, ObjectDefinedStatusDuringAddModule) {
-  SimulateAddModule(R"(
-    if (typeof(console) !== 'object' ||
-        typeof(register) !== 'function' ||
-        typeof(sharedStorage) !== 'undefined') {
-      throw Error('Unexpected object defined status.');
-    }
-  )");
-
-  EXPECT_TRUE(success());
-  EXPECT_TRUE(error_message().empty());
-}
-
-TEST_F(SharedStorageAddModuleTest, RegisterOperation_MissingOperationName) {
-  SimulateAddModule(R"(
-    register();
-  )");
-
-  EXPECT_FALSE(success());
-  EXPECT_EQ(error_message(),
-            "https://example.test/:2 Uncaught TypeError: Missing "
-            "\"name\" argument in operation registration.");
-}
-
-TEST_F(SharedStorageAddModuleTest, RegisterOperation_EmptyOperationName) {
-  SimulateAddModule(R"(
-    register("");
-  )");
-
-  EXPECT_FALSE(success());
-  EXPECT_EQ(error_message(),
-            "https://example.test/:2 Uncaught TypeError: Operation name "
-            "cannot be empty.");
-}
-
-TEST_F(SharedStorageAddModuleTest,
-       RegisterOperation_MissingClassName_MissingArgument) {
-  SimulateAddModule(R"(
-    register("test-operation");
-  )");
-
-  EXPECT_FALSE(success());
-  EXPECT_EQ(error_message(),
-            "https://example.test/:2 Uncaught TypeError: Missing class "
-            "name argument in operation registration.");
-}
-
-TEST_F(SharedStorageAddModuleTest,
-       RegisterOperation_MissingClassName_NotAnObject) {
-  SimulateAddModule(R"(
-    register("test-operation", 1);
-  )");
-
-  EXPECT_FALSE(success());
-  EXPECT_EQ(error_message(),
-            "https://example.test/:2 Uncaught TypeError: Missing class "
-            "name argument in operation registration.");
-}
-
-TEST_F(SharedStorageAddModuleTest, RegisterOperation_ClassNameNotAConstructor) {
-  SimulateAddModule(R"(
-    register("test-operation", {});
-  )");
-
-  EXPECT_FALSE(success());
-  EXPECT_EQ(error_message(),
-            "https://example.test/:2 Uncaught TypeError: Unexpected class "
-            "argument: not a constructor.");
-}
-
-TEST_F(SharedStorageAddModuleTest, RegisterOperation_MissingRunFunction) {
-  SimulateAddModule(R"(
-    class TestClass {
-      constructor() {
-        this.run = 1;
-      }
-    }
-
-    register("test-operation", TestClass);
-  )");
-
-  EXPECT_FALSE(success());
-  EXPECT_EQ(error_message(),
-            "https://example.test/:8 Uncaught TypeError: Missing \"run()\" "
-            "function in the class.");
-}
-
-TEST_F(SharedStorageAddModuleTest,
-       RegisterOperation_ClassPrototypeNotAnObject) {
-  SimulateAddModule(R"(
-    function test() {};
-    test.prototype = 123;
-
-    register("test-operation", test);
-  )");
-
-  EXPECT_FALSE(success());
-  EXPECT_EQ(error_message(),
-            "https://example.test/:5 Uncaught TypeError: Unexpected class "
-            "prototype: not an object.");
-}
-
-TEST_F(SharedStorageAddModuleTest, RegisterOperation_Success) {
-  SimulateAddModule(R"(
-    class TestClass {
-      async run() {}
-    }
-
-    register("test-operation", TestClass);
-  )");
-
-  EXPECT_TRUE(success());
-  EXPECT_TRUE(error_message().empty());
-}
-
-TEST_F(SharedStorageAddModuleTest, RegisterOperation_AlreadyRegistered) {
-  SimulateAddModule(R"(
-    class TestClass1 {
-      async run() {}
-    }
-
-    class TestClass2 {
-      async run() {}
-    }
-
-    register("test-operation", TestClass1);
-    register("test-operation", TestClass2);
-  )");
-
-  EXPECT_FALSE(success());
-  EXPECT_EQ(error_message(),
-            "https://example.test/:11 Uncaught TypeError: Operation name "
-            "already registered.");
-}
-
-TEST_F(SharedStorageAddModuleTest,
-       RegisterOperationWithPrivateAggregationCall_CallForwarded) {
-  // The operation will not be run.
-  EXPECT_CALL(*mock_private_aggregation_host(), SendHistogramReport).Times(0);
-
-  SimulateAddModule(R"(
-    class TestClass {
-      async run() {
-        privateAggregation.sendHistogramReport({bucket: 1n, value: 2});
-      }
-    }
-
-    register("test-operation", TestClass);
-  )");
-
-  EXPECT_TRUE(success());
-  EXPECT_TRUE(error_message().empty());
-}
-
-TEST_F(SharedStorageAddModuleTest,
-       RegisterOperationWithPrivateAggregationCall_PAHostNotDefined) {
-  EXPECT_CALL(*mock_private_aggregation_host(), SendHistogramReport).Times(0);
-
-  SimulateAddModule(R"(
-    class TestClass {
-      async run() {
-        privateAggregation.sendHistogramReport({bucket: 1n, value: 2});
-      }
-    }
-
-    register("test-operation", TestClass);
-  )");
-
-  EXPECT_TRUE(success());
-  EXPECT_TRUE(error_message().empty());
-  EXPECT_FALSE(test_client()->observed_record_use_counter_call());
-}
-
-TEST_F(SharedStorageAddModuleTest,
-       RunPrivateAggregationInOutermostScope_ErrorThrown) {
-  // The operation will not be run.
-  EXPECT_CALL(*mock_private_aggregation_host(), SendHistogramReport).Times(0);
-
-  SimulateAddModule(R"(
-    privateAggregation.sendHistogramReport({bucket: 1n, value: 2});
-  )");
-
-  EXPECT_FALSE(success());
-  EXPECT_EQ(error_message(),
-            "https://example.test/:2 Uncaught ReferenceError: "
-            "privateAggregation is not defined.");
-}
-
-class SharedStorageRunOperationTest
-    : public SharedStorageWorkletGlobalScopeTest {
- public:
-  // The caller should provide a valid module script. The purpose of this test
-  // suite is to test RunOperation.
-  void SimulateAddModule(const std::string& script_body) {
-    bool add_module_callback_called = false;
-
-    auto add_module_callback = base::BindLambdaForTesting(
-        [&](bool success, const std::string& error_message) {
-          DCHECK(success);
-          add_module_callback_called = true;
-        });
-
-    global_scope_->OnModuleScriptDownloaded(
-        test_client_.get(), GURL("https://example.test"),
-        std::move(add_module_callback),
-        std::make_unique<std::string>(script_body), /*error_message=*/{});
-
-    ASSERT_TRUE(add_module_callback_called);
-
-    RegisterAsyncReturnForTesting();
-  }
-
-  void SimulateRunOperation(const std::string& name,
-                            const std::vector<uint8_t>& serialized_data) {
-    auto run_operation_callback = base::BindLambdaForTesting(
-        [&](bool success, const std::string& error_message) {
-          unnamed_operation_finished_ = true;
-          unnamed_operation_success_ = success;
-          unnamed_operation_error_message_ = error_message;
-        });
-
-    global_scope_->RunOperation(name, serialized_data, InitNewRemotePAHost(),
-                                std::move(run_operation_callback));
-  }
-
-  void SimulateRunURLSelectionOperation(
-      const std::string& name,
-      const std::vector<GURL>& urls,
-      const std::vector<uint8_t>& serialized_data) {
-    auto run_operation_callback = base::BindLambdaForTesting(
-        [&](bool success, const std::string& error_message, uint32_t index) {
-          url_selection_operation_finished_ = true;
-          url_selection_operation_success_ = success;
-          url_selection_operation_error_message_ = error_message;
-          url_selection_operation_index_ = index;
-        });
-
-    global_scope_->RunURLSelectionOperation(name, urls, serialized_data,
-                                            InitNewRemotePAHost(),
-                                            std::move(run_operation_callback));
-  }
-
-  bool unnamed_operation_finished() const {
-    return unnamed_operation_finished_;
-  }
-
-  bool unnamed_operation_success() const { return unnamed_operation_success_; }
-
-  const std::string& unnamed_operation_error_message() const {
-    return unnamed_operation_error_message_;
-  }
-
-  bool url_selection_operation_finished() const {
-    return url_selection_operation_finished_;
-  }
-
-  bool url_selection_operation_success() const {
-    return url_selection_operation_success_;
-  }
-
-  const std::string& url_selection_operation_error_message() const {
-    return url_selection_operation_error_message_;
-  }
-
-  uint32_t url_selection_operation_index() const {
-    return url_selection_operation_index_;
-  }
-
- private:
-  bool unnamed_operation_finished_ = false;
-  bool unnamed_operation_success_ = false;
-  std::string unnamed_operation_error_message_;
-
-  bool url_selection_operation_finished_ = false;
-  bool url_selection_operation_success_ = false;
-  std::string url_selection_operation_error_message_;
-  uint32_t url_selection_operation_index_ = -1;
-};
-
-TEST_F(SharedStorageRunOperationTest, UnnamedOperation_BeforeAddModuleFinish) {
-  SimulateRunOperation("test-operation-1", /*serialized_data=*/{});
-
-  EXPECT_TRUE(unnamed_operation_finished());
-  EXPECT_FALSE(unnamed_operation_success());
-  EXPECT_EQ(unnamed_operation_error_message(),
-            "The module script hasn't been loaded.");
-}
-
-TEST_F(SharedStorageRunOperationTest,
-       UnnamedOperation_OperationNameNotRegistered) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run() {}
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunOperation("test-operation-1", /*serialized_data=*/{});
-
-  EXPECT_TRUE(unnamed_operation_finished());
-  EXPECT_FALSE(unnamed_operation_success());
-  EXPECT_EQ(unnamed_operation_error_message(), "Cannot find operation name.");
-}
-
-TEST_F(SharedStorageRunOperationTest, UnnamedOperation_FunctionError) {
-  SimulateAddModule(R"(
-      class TestClass {
-        run() {
-          a;
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunOperation("test-operation", /*serialized_data=*/{});
-
-  EXPECT_TRUE(unnamed_operation_finished());
-  EXPECT_FALSE(unnamed_operation_success());
-  EXPECT_EQ(
-      unnamed_operation_error_message(),
-      "https://example.test/:4 Uncaught ReferenceError: a is not defined.");
-}
-
-TEST_F(SharedStorageRunOperationTest, UnnamedOperation_ReturnValueNotAPromise) {
-  SimulateAddModule(R"(
-      class TestClass {
-        run() {}
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunOperation("test-operation", /*serialized_data=*/{});
-
-  EXPECT_TRUE(unnamed_operation_finished());
-  EXPECT_FALSE(unnamed_operation_success());
-  EXPECT_EQ(unnamed_operation_error_message(),
-            "run() did not return a promise.");
-}
-
-TEST_F(SharedStorageRunOperationTest, UnnamedOperation_Microtask) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run() {
-          await Promise.resolve(0);
-          return 0;
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunOperation("test-operation", /*serialized_data=*/{});
-
-  EXPECT_TRUE(unnamed_operation_finished());
-  EXPECT_TRUE(unnamed_operation_success());
-  EXPECT_TRUE(unnamed_operation_error_message().empty());
-}
-
-TEST_F(SharedStorageRunOperationTest,
-       UnnamedOperation_ResultPromiseFulfilledSynchronously) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run() {}
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunOperation("test-operation", /*serialized_data=*/{});
-
-  EXPECT_TRUE(unnamed_operation_finished());
-  EXPECT_TRUE(unnamed_operation_success());
-  EXPECT_TRUE(unnamed_operation_error_message().empty());
-}
-
-TEST_F(SharedStorageRunOperationTest,
-       UnnamedOperation_ResultPromiseRejectedSynchronously) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run() {
-          a;
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunOperation("test-operation", /*serialized_data=*/{});
-
-  EXPECT_TRUE(unnamed_operation_finished());
-  EXPECT_FALSE(unnamed_operation_success());
-  EXPECT_EQ(unnamed_operation_error_message(),
-            "ReferenceError: a is not defined");
-}
-
-TEST_F(SharedStorageRunOperationTest,
-       UnnamedOperation_ResultPromiseFulfilledAsynchronously) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run() {
-          return sharedStorage.set('key', 'value');
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunOperation("test-operation", /*serialized_data=*/{});
-
-  EXPECT_FALSE(unnamed_operation_finished());
-
-  task_environment_.RunUntilIdle();
-
-  EXPECT_TRUE(unnamed_operation_finished());
-  EXPECT_TRUE(unnamed_operation_success());
-  EXPECT_TRUE(unnamed_operation_error_message().empty());
-}
-
-TEST_F(SharedStorageRunOperationTest,
-       UnnamedOperation_ResultPromiseRejectedAsynchronously) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run() {
-          return sharedStorage.append('key', 'value');
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunOperation("test-operation", /*serialized_data=*/{});
-
-  EXPECT_FALSE(unnamed_operation_finished());
-
-  task_environment_.RunUntilIdle();
-
-  EXPECT_TRUE(unnamed_operation_finished());
-  EXPECT_FALSE(unnamed_operation_success());
-  EXPECT_EQ(unnamed_operation_error_message(),
-            "testing error message for append");
-}
-
-TEST_F(SharedStorageRunOperationTest, UnnamedOperation_ExpectedCustomData) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(data) {
-          if (data.customField != 'customValue') {
-            throw 'Unexpected value for customField field';
-          }
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  std::vector<uint8_t> serialized_data;
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    v8::Local<v8::Context> context = LocalContext();
-    v8::Context::Scope context_scope(context);
-
-    v8::Local<v8::Object> obj = v8::Object::New(Isolate());
-    gin::Dictionary dict(Isolate(), obj);
-    dict.Set<std::string>("customField", std::string("customValue"));
-    serialized_data = Serialize(Isolate(), LocalContext(), obj);
-  }
-
-  SimulateRunOperation("test-operation", serialized_data);
-
-  EXPECT_TRUE(unnamed_operation_finished());
-  EXPECT_TRUE(unnamed_operation_success());
-  EXPECT_TRUE(unnamed_operation_error_message().empty());
-}
-
-TEST_F(SharedStorageRunOperationTest, UnnamedOperation_UnexpectedCustomData) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(data) {
-          if (data.customField != 'customValue') {
-            throw 'Unexpected value for customField field';
-          }
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  std::vector<uint8_t> serialized_data;
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    v8::Local<v8::Context> context = LocalContext();
-    v8::Context::Scope context_scope(context);
-
-    v8::Local<v8::Object> obj = v8::Object::New(Isolate());
-    gin::Dictionary dict(Isolate(), obj);
-    dict.Set<std::string>("customField", std::string("customValue123"));
-    serialized_data = Serialize(Isolate(), LocalContext(), obj);
-  }
-
-  SimulateRunOperation("test-operation", serialized_data);
-
-  EXPECT_TRUE(unnamed_operation_finished());
-  EXPECT_FALSE(unnamed_operation_success());
-  EXPECT_EQ(unnamed_operation_error_message(),
-            "Unexpected value for customField field");
-}
-
-TEST_F(SharedStorageRunOperationTest,
-       URLSelectionOperation_ResultPromiseFulfilledSynchronously) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(urls) {
-          return 1;
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunURLSelectionOperation(
-      "test-operation", {GURL("https://foo.com"), GURL("https://bar.com")},
-      /*serialized_data=*/{});
-
-  EXPECT_TRUE(url_selection_operation_finished());
-  EXPECT_TRUE(url_selection_operation_success());
-  EXPECT_TRUE(url_selection_operation_error_message().empty());
-  EXPECT_EQ(url_selection_operation_index(), 1u);
-}
-
-TEST_F(
-    SharedStorageRunOperationTest,
-    URLSelectionOperation_ResultPromiseFulfilledSynchronously_NumberOverflow) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(urls) {
-          return -4294967295;
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunURLSelectionOperation(
-      "test-operation", {GURL("https://foo.com"), GURL("https://bar.com")},
-      /*serialized_data=*/{});
-
-  EXPECT_TRUE(url_selection_operation_finished());
-  EXPECT_TRUE(url_selection_operation_success());
-  EXPECT_TRUE(url_selection_operation_error_message().empty());
-  EXPECT_EQ(url_selection_operation_index(), 1u);
-}
-
-TEST_F(
-    SharedStorageRunOperationTest,
-    URLSelectionOperation_ResultPromiseFulfilledSynchronously_StringConvertedToUint32) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(urls) {
-          return '1';
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunURLSelectionOperation(
-      "test-operation", {GURL("https://foo.com"), GURL("https://bar.com")},
-      /*serialized_data=*/{});
-
-  EXPECT_TRUE(url_selection_operation_finished());
-  EXPECT_TRUE(url_selection_operation_success());
-  EXPECT_TRUE(url_selection_operation_error_message().empty());
-  EXPECT_EQ(url_selection_operation_index(), 1u);
-}
-
-TEST_F(
-    SharedStorageRunOperationTest,
-    URLSelectionOperation_ResultPromiseFulfilledSynchronously_RandomStringConvertedTo0) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(urls) {
-          return 'abc';
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunURLSelectionOperation(
-      "test-operation", {GURL("https://foo.com"), GURL("https://bar.com")},
-      /*serialized_data=*/{});
-
-  EXPECT_TRUE(url_selection_operation_finished());
-  EXPECT_TRUE(url_selection_operation_success());
-  EXPECT_TRUE(url_selection_operation_error_message().empty());
-  EXPECT_EQ(url_selection_operation_index(), 0u);
-}
-
-TEST_F(
-    SharedStorageRunOperationTest,
-    URLSelectionOperation_ResultPromiseFulfilledSynchronously_DefaultUndefinedResultConvertedTo0) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(urls) {}
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunURLSelectionOperation(
-      "test-operation", {GURL("https://foo.com"), GURL("https://bar.com")},
-      /*serialized_data=*/{});
-
-  EXPECT_TRUE(url_selection_operation_finished());
-  EXPECT_TRUE(url_selection_operation_success());
-  EXPECT_TRUE(url_selection_operation_error_message().empty());
-  EXPECT_EQ(url_selection_operation_index(), 0u);
-}
-
-TEST_F(
-    SharedStorageRunOperationTest,
-    URLSelectionOperation_ResultPromiseRejectedSynchronously_SynchronousScriptError) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(urls) {
-          undefined_variable;
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunURLSelectionOperation("test-operation", {GURL("https://foo.com")},
-                                   /*serialized_data=*/{});
-
-  EXPECT_TRUE(url_selection_operation_finished());
-  EXPECT_FALSE(url_selection_operation_success());
-  EXPECT_EQ(url_selection_operation_error_message(),
-            "ReferenceError: undefined_variable is not defined");
-  EXPECT_EQ(url_selection_operation_index(), 0u);
-}
-
-TEST_F(
-    SharedStorageRunOperationTest,
-    URLSelectionOperation_ResultPromiseRejectedSynchronously_ReturnValueOutOfRange) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(urls) {
-          return 1;
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunURLSelectionOperation("test-operation", {GURL("https://foo.com")},
-                                   /*serialized_data=*/{});
-
-  EXPECT_TRUE(url_selection_operation_finished());
-  EXPECT_FALSE(url_selection_operation_success());
-  EXPECT_EQ(
-      url_selection_operation_error_message(),
-      "Promise resolved to a number outside the length of the input urls.");
-  EXPECT_EQ(url_selection_operation_index(), 0u);
-}
-
-TEST_F(
-    SharedStorageRunOperationTest,
-    URLSelectionOperation_ResultPromiseRejectedSynchronously_ReturnValueToInt32Error) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(urls) {
-          class CustomClass {
-            toString() { throw Error('error 123'); }
-          }
-
-          return new CustomClass();
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunURLSelectionOperation("test-operation", {GURL("https://foo.com")},
-                                   /*serialized_data=*/{});
-
-  EXPECT_TRUE(url_selection_operation_finished());
-  EXPECT_FALSE(url_selection_operation_success());
-  EXPECT_EQ(url_selection_operation_error_message(),
-            "Promise did not resolve to an uint32 number.");
-  EXPECT_EQ(url_selection_operation_index(), 0u);
-}
-
-TEST_F(SharedStorageRunOperationTest,
-       URLSelectionOperation_ResultPromiseFulfilledAsynchronously) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(urls) {
-          return asyncFulfillForTesting(1);
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunURLSelectionOperation(
-      "test-operation", {GURL("https://foo.com"), GURL("https://bar.com")},
-      /*serialized_data=*/{});
-
-  EXPECT_FALSE(url_selection_operation_finished());
-
-  task_environment_.RunUntilIdle();
-
-  EXPECT_TRUE(url_selection_operation_finished());
-  EXPECT_TRUE(url_selection_operation_success());
-  EXPECT_TRUE(url_selection_operation_error_message().empty());
-  EXPECT_EQ(url_selection_operation_index(), 1u);
-}
-
-TEST_F(
-    SharedStorageRunOperationTest,
-    URLSelectionOperation_ResultPromiseFulfilledAsynchronously_NumberOverflow) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(urls) {
-          return asyncFulfillForTesting(-4294967295);
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunURLSelectionOperation(
-      "test-operation", {GURL("https://foo.com"), GURL("https://bar.com")},
-      /*serialized_data=*/{});
-
-  EXPECT_FALSE(url_selection_operation_finished());
-
-  task_environment_.RunUntilIdle();
-
-  EXPECT_TRUE(url_selection_operation_finished());
-  EXPECT_TRUE(url_selection_operation_success());
-  EXPECT_TRUE(url_selection_operation_error_message().empty());
-  EXPECT_EQ(url_selection_operation_index(), 1u);
-}
-
-TEST_F(
-    SharedStorageRunOperationTest,
-    URLSelectionOperation_ResultPromiseFulfilledAsynchronously_StringConvertedToUint32) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(urls) {
-          return asyncFulfillForTesting('1');
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunURLSelectionOperation(
-      "test-operation", {GURL("https://foo.com"), GURL("https://bar.com")},
-      /*serialized_data=*/{});
-
-  EXPECT_FALSE(url_selection_operation_finished());
-
-  task_environment_.RunUntilIdle();
-
-  EXPECT_TRUE(url_selection_operation_finished());
-  EXPECT_TRUE(url_selection_operation_success());
-  EXPECT_TRUE(url_selection_operation_error_message().empty());
-  EXPECT_EQ(url_selection_operation_index(), 1u);
-}
-
-TEST_F(
-    SharedStorageRunOperationTest,
-    URLSelectionOperation_ResultPromiseFulfilledAsynchronously_RandomStringConvertedTo0) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(urls) {
-          return asyncFulfillForTesting('abc');
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunURLSelectionOperation(
-      "test-operation", {GURL("https://foo.com"), GURL("https://bar.com")},
-      /*serialized_data=*/{});
-
-  EXPECT_FALSE(url_selection_operation_finished());
-
-  task_environment_.RunUntilIdle();
-
-  EXPECT_TRUE(url_selection_operation_finished());
-  EXPECT_TRUE(url_selection_operation_success());
-  EXPECT_TRUE(url_selection_operation_error_message().empty());
-  EXPECT_EQ(url_selection_operation_index(), 0u);
-}
-
-TEST_F(
-    SharedStorageRunOperationTest,
-    URLSelectionOperation_ResultPromiseFulfilledAsynchronously_DefaultUndefinedResultConvertedTo0) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(urls) {
-          return asyncFulfillForTesting();
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunURLSelectionOperation(
-      "test-operation", {GURL("https://foo.com"), GURL("https://bar.com")},
-      /*serialized_data=*/{});
-
-  EXPECT_FALSE(url_selection_operation_finished());
-
-  task_environment_.RunUntilIdle();
-
-  EXPECT_TRUE(url_selection_operation_finished());
-  EXPECT_TRUE(url_selection_operation_success());
-  EXPECT_TRUE(url_selection_operation_error_message().empty());
-  EXPECT_EQ(url_selection_operation_index(), 0u);
-}
-
-TEST_F(SharedStorageRunOperationTest,
-       URLSelectionOperation_ResultPromiseRejectedAsynchronously) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(urls) {
-          return asyncRejectForTesting('custom error message 123');
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunURLSelectionOperation(
-      "test-operation", {GURL("https://foo.com"), GURL("https://bar.com")},
-      /*serialized_data=*/{});
-
-  EXPECT_FALSE(url_selection_operation_finished());
-
-  task_environment_.RunUntilIdle();
-
-  EXPECT_TRUE(url_selection_operation_finished());
-  EXPECT_FALSE(url_selection_operation_success());
-  EXPECT_EQ(url_selection_operation_error_message(),
-            "custom error message 123");
-  EXPECT_EQ(url_selection_operation_index(), 0u);
-}
-
-TEST_F(
-    SharedStorageRunOperationTest,
-    URLSelectionOperation_ResultPromiseRejectedAsynchronously_ReturnValueOutOfRange) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(urls) {
-          return asyncFulfillForTesting(1);
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunURLSelectionOperation("test-operation", {GURL("https://foo.com")},
-                                   /*serialized_data=*/{});
-
-  EXPECT_FALSE(url_selection_operation_finished());
-
-  task_environment_.RunUntilIdle();
-
-  EXPECT_TRUE(url_selection_operation_finished());
-  EXPECT_FALSE(url_selection_operation_success());
-  EXPECT_EQ(
-      url_selection_operation_error_message(),
-      "Promise resolved to a number outside the length of the input urls.");
-  EXPECT_EQ(url_selection_operation_index(), 0u);
-}
-
-TEST_F(
-    SharedStorageRunOperationTest,
-    URLSelectionOperation_ResultPromiseRejectedAsynchronously_ReturnValueToInt32Error) {
-  SimulateAddModule(R"(
-      class TestClass {
-        async run(urls) {
-          class CustomClass {
-            toString() { throw Error('error 123'); }
-          }
-
-          return asyncFulfillForTesting(new CustomClass());
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunURLSelectionOperation("test-operation", {GURL("https://foo.com")},
-                                   /*serialized_data=*/{});
-
-  EXPECT_FALSE(url_selection_operation_finished());
-
-  task_environment_.RunUntilIdle();
-
-  EXPECT_TRUE(url_selection_operation_finished());
-  EXPECT_FALSE(url_selection_operation_success());
-  EXPECT_EQ(url_selection_operation_error_message(),
-            "Promise did not resolve to an uint32 number.");
-  EXPECT_EQ(url_selection_operation_index(), 0u);
-}
-
-TEST_F(SharedStorageRunOperationTest,
-       UnnamedOperationWithPrivateAggregationCall_PAHostNotDefined) {
-  EXPECT_CALL(*mock_private_aggregation_host(), SendHistogramReport).Times(0);
-
-  SimulateAddModule(R"(
-      class TestClass {
-        async run() {
-          privateAggregation.sendHistogramReport({bucket: 1n, value: 2});
-        }
-      }
-
-      register("test-operation", TestClass);
-    )");
-
-  SimulateRunOperation("test-operation", /*serialized_data=*/{});
-
-  EXPECT_TRUE(unnamed_operation_finished());
-  EXPECT_FALSE(unnamed_operation_success());
-  EXPECT_EQ(unnamed_operation_error_message(),
-            "ReferenceError: privateAggregation is not defined");
-  EXPECT_FALSE(test_client()->observed_record_use_counter_call());
-}
-
-class SharedStorageObjectMethodTest : public SharedStorageRunOperationTest {
- public:
-  SharedStorageObjectMethodTest() {
-    // Run AddModule so that sharedStorage is exposed.
-    SimulateAddModule(R"()");
-  }
-
-  void ExecuteScript(const std::string& script_body) {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    v8::Local<v8::Context> context = LocalContext();
-    v8::Context::Scope context_scope(context);
-
-    v8::Local<v8::Value> v8_result = EvalJs(script_body);
-
-    ASSERT_TRUE(!v8_result.IsEmpty());
-    ASSERT_TRUE(v8_result->IsPromise());
-
-    v8_result_promise_ =
-        v8::Global<v8::Promise>(Isolate(), v8_result.As<v8::Promise>());
-  }
-
-  bool finished() {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    v8::Local<v8::Promise> v8_result_promise =
-        v8_result_promise_.Get(Isolate());
-    return v8_result_promise->State() != v8::Promise::PromiseState::kPending;
-  }
-
-  bool fulfilled() {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    v8::Local<v8::Promise> v8_result_promise =
-        v8_result_promise_.Get(Isolate());
-    return v8_result_promise->State() == v8::Promise::PromiseState::kFulfilled;
-  }
-
-  v8::Local<v8::Value> v8_resolved_value() {
-    DCHECK(finished());
-    v8::Local<v8::Promise> v8_result_promise =
-        v8_result_promise_.Get(Isolate());
-    return v8_result_promise->Result();
-  }
-
- private:
-  v8::Global<v8::Promise> v8_result_promise_;
-};
-
-TEST_F(SharedStorageObjectMethodTest, SetOperation_MissingKey) {
-  ExecuteScript("sharedStorage.set()");
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    EXPECT_TRUE(v8_resolved_value()->IsString());
-    EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()),
-              "Missing or invalid \"key\" argument in sharedStorage.set()");
-  }
-
-  EXPECT_TRUE(test_client()->observed_set_params().empty());
-}
-
-TEST_F(SharedStorageObjectMethodTest, SetOperation_InvalidKey_Empty) {
-  ExecuteScript("sharedStorage.set('', 'value')");
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    EXPECT_TRUE(v8_resolved_value()->IsString());
-    EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()),
-              "Missing or invalid \"key\" argument in sharedStorage.set()");
-  }
-
-  EXPECT_TRUE(test_client()->observed_set_params().empty());
-}
-
-TEST_F(SharedStorageObjectMethodTest, SetOperation_InvalidKey_LengthTooBig) {
-  ExecuteScript("sharedStorage.set('a'.repeat(1025), 'value')");
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    EXPECT_TRUE(v8_resolved_value()->IsString());
-    EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()),
-              "Missing or invalid \"key\" argument in sharedStorage.set()");
-  }
-
-  EXPECT_TRUE(test_client()->observed_set_params().empty());
-}
-
-TEST_F(SharedStorageObjectMethodTest, SetOperation_MissingValue) {
-  ExecuteScript("sharedStorage.set('key')");
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    EXPECT_TRUE(v8_resolved_value()->IsString());
-    EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()),
-              "Missing or invalid \"value\" argument in sharedStorage.set()");
-  }
-
-  EXPECT_TRUE(test_client()->observed_set_params().empty());
-}
-
-TEST_F(SharedStorageObjectMethodTest, SetOperation_InvalidValue_LengthTooBig) {
-  ExecuteScript("sharedStorage.set('key', 'a'.repeat(1025))");
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    EXPECT_TRUE(v8_resolved_value()->IsString());
-    EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()),
-              "Missing or invalid \"value\" argument in sharedStorage.set()");
-  }
-
-  EXPECT_TRUE(test_client()->observed_set_params().empty());
-}
-
-TEST_F(SharedStorageObjectMethodTest, SetOperation_InvalidOptions) {
-  ExecuteScript("sharedStorage.set('key', 'value', true)");
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    EXPECT_TRUE(v8_resolved_value()->IsString());
-    EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()),
-              "Invalid \"options\" argument in sharedStorage.set()");
-  }
-}
-
-TEST_F(SharedStorageObjectMethodTest, SetOperation_FulfilledAsynchronously) {
-  ExecuteScript("sharedStorage.set('key', 'value')");
-  EXPECT_FALSE(finished());
-  task_environment_.RunUntilIdle();
-  EXPECT_TRUE(finished());
-  EXPECT_TRUE(fulfilled());
-
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    EXPECT_TRUE(v8_resolved_value()->IsUndefined());
-  }
-
-  EXPECT_EQ(test_client()->observed_set_params().size(), 1u);
-  EXPECT_EQ(test_client()->observed_set_params()[0].key, u"key");
-  EXPECT_EQ(test_client()->observed_set_params()[0].value, u"value");
-  EXPECT_FALSE(test_client()->observed_set_params()[0].ignore_if_present);
-}
-
-TEST_F(SharedStorageObjectMethodTest,
-       SetOperation_KeyAndValueConvertedToString) {
-  ExecuteScript("sharedStorage.set(123, 456)");
-  ExecuteScript("sharedStorage.set(null, null)");
-  ExecuteScript("sharedStorage.set(undefined, undefined)");
-  ExecuteScript(
-      "sharedStorage.set({dictKey1: 'dictValue1'}, {dictKey2: 'dictValue2'})");
-  task_environment_.RunUntilIdle();
-
-  EXPECT_EQ(test_client()->observed_set_params().size(), 4u);
-  EXPECT_EQ(test_client()->observed_set_params()[0].key, u"123");
-  EXPECT_EQ(test_client()->observed_set_params()[0].value, u"456");
-  EXPECT_EQ(test_client()->observed_set_params()[1].key, u"null");
-  EXPECT_EQ(test_client()->observed_set_params()[1].value, u"null");
-  EXPECT_EQ(test_client()->observed_set_params()[2].key, u"undefined");
-  EXPECT_EQ(test_client()->observed_set_params()[2].value, u"undefined");
-  EXPECT_EQ(test_client()->observed_set_params()[3].key, u"[object Object]");
-  EXPECT_EQ(test_client()->observed_set_params()[3].value, u"[object Object]");
-}
-
-TEST_F(SharedStorageObjectMethodTest, SetOperation_KeyConvertedToStringError) {
-  ExecuteScript(
-      "class CustomClass {"
-      "  toString() { throw Error('error 123'); }"
-      "}"
-      "sharedStorage.set(new CustomClass(), new CustomClass())");
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    EXPECT_TRUE(v8_resolved_value()->IsString());
-    EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()),
-              "Missing or invalid \"key\" argument in sharedStorage.set()");
-  }
-
-  EXPECT_TRUE(test_client()->observed_set_params().empty());
-}
-
-TEST_F(SharedStorageObjectMethodTest,
-       SetOperation_ValueConvertedToStringError) {
-  ExecuteScript(
-      "class CustomClass {"
-      "  toString() { throw Error('error 123'); }"
-      "}"
-      "sharedStorage.set(123, new CustomClass())");
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    EXPECT_TRUE(v8_resolved_value()->IsString());
-    EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()),
-              "Missing or invalid \"value\" argument in sharedStorage.set()");
-  }
-
-  EXPECT_TRUE(test_client()->observed_set_params().empty());
-}
-
-TEST_F(SharedStorageObjectMethodTest, SetOperation_IgnoreIfPresent_False) {
-  ExecuteScript("sharedStorage.set('key', 'value')");
-  ExecuteScript("sharedStorage.set('key', 'value', {})");
-  ExecuteScript("sharedStorage.set('key', 'value', {ignoreIfPresent: false})");
-  ExecuteScript("sharedStorage.set('key', 'value', {ignoreIfPresent: ''})");
-  ExecuteScript("sharedStorage.set('key', 'value', {ignoreIfPresent: null})");
-  ExecuteScript(
-      "sharedStorage.set('key', 'value', {ignoreIfPresent: undefined})");
-
-  task_environment_.RunUntilIdle();
-
-  EXPECT_EQ(test_client()->observed_set_params().size(), 6u);
-  EXPECT_FALSE(test_client()->observed_set_params()[0].ignore_if_present);
-  EXPECT_FALSE(test_client()->observed_set_params()[1].ignore_if_present);
-  EXPECT_FALSE(test_client()->observed_set_params()[2].ignore_if_present);
-  EXPECT_FALSE(test_client()->observed_set_params()[3].ignore_if_present);
-  EXPECT_FALSE(test_client()->observed_set_params()[4].ignore_if_present);
-  EXPECT_FALSE(test_client()->observed_set_params()[5].ignore_if_present);
-}
-
-TEST_F(SharedStorageObjectMethodTest, SetOperation_IgnoreIfPresent_True) {
-  ExecuteScript("sharedStorage.set('key', 'value', {ignoreIfPresent: true})");
-  // A non-empty string will evaluate to true.
-  ExecuteScript(
-      "sharedStorage.set('key', 'value', {ignoreIfPresent: 'false'})");
-  // A dictionary object will evaluate to true.
-  ExecuteScript("sharedStorage.set('key', 'value', {ignoreIfPresent: {}})");
-  task_environment_.RunUntilIdle();
-
-  EXPECT_EQ(test_client()->observed_set_params().size(), 3u);
-  EXPECT_TRUE(test_client()->observed_set_params()[0].ignore_if_present);
-  EXPECT_TRUE(test_client()->observed_set_params()[1].ignore_if_present);
-  EXPECT_TRUE(test_client()->observed_set_params()[2].ignore_if_present);
-}
-
-TEST_F(SharedStorageObjectMethodTest, AppendOperation_MissingKey) {
-  ExecuteScript("sharedStorage.append()");
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    EXPECT_TRUE(v8_resolved_value()->IsString());
-    EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()),
-              "Missing or invalid \"key\" argument in sharedStorage.append()");
-  }
-}
-
-TEST_F(SharedStorageObjectMethodTest, AppendOperation_InvalidKey_Empty) {
-  ExecuteScript("sharedStorage.append('', 'value')");
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    EXPECT_TRUE(v8_resolved_value()->IsString());
-    EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()),
-              "Missing or invalid \"key\" argument in sharedStorage.append()");
-  }
-}
-
-TEST_F(SharedStorageObjectMethodTest, AppendOperation_InvalidKey_LengthTooBig) {
-  ExecuteScript("sharedStorage.append('a'.repeat(1025), 'value')");
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    EXPECT_TRUE(v8_resolved_value()->IsString());
-    EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()),
-              "Missing or invalid \"key\" argument in sharedStorage.append()");
-  }
-}
-
-TEST_F(SharedStorageObjectMethodTest, AppendOperation_MissingValue) {
-  ExecuteScript("sharedStorage.append('key')");
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    EXPECT_TRUE(v8_resolved_value()->IsString());
-    EXPECT_EQ(
-        gin::V8ToString(Isolate(), v8_resolved_value()),
-        "Missing or invalid \"value\" argument in sharedStorage.append()");
-  }
-}
-
-TEST_F(SharedStorageObjectMethodTest,
-       AppendOperation_InvalidValue_LengthTooBig) {
-  ExecuteScript("sharedStorage.append('key', 'a'.repeat(1025))");
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    EXPECT_TRUE(v8_resolved_value()->IsString());
-    EXPECT_EQ(
-        gin::V8ToString(Isolate(), v8_resolved_value()),
-        "Missing or invalid \"value\" argument in sharedStorage.append()");
-  }
-}
-
-TEST_F(SharedStorageObjectMethodTest,
-       AppendOperation_KeyAndValueConvertedToString) {
-  ExecuteScript("sharedStorage.append(123, 456)");
-  ExecuteScript("sharedStorage.append(null, null)");
-  ExecuteScript("sharedStorage.append(undefined, undefined)");
-  ExecuteScript(
-      "sharedStorage.append({dictKey1: 'dictValue1'}, {dictKey2: "
-      "'dictValue2'})");
-  task_environment_.RunUntilIdle();
-
-  EXPECT_EQ(test_client()->observed_append_params().size(), 4u);
-  EXPECT_EQ(test_client()->observed_append_params()[0].key, u"123");
-  EXPECT_EQ(test_client()->observed_append_params()[0].value, u"456");
-  EXPECT_EQ(test_client()->observed_append_params()[1].key, u"null");
-  EXPECT_EQ(test_client()->observed_append_params()[1].value, u"null");
-  EXPECT_EQ(test_client()->observed_append_params()[2].key, u"undefined");
-  EXPECT_EQ(test_client()->observed_append_params()[2].value, u"undefined");
-  EXPECT_EQ(test_client()->observed_append_params()[3].key, u"[object Object]");
-  EXPECT_EQ(test_client()->observed_append_params()[3].value,
-            u"[object Object]");
-}
-
-TEST_F(SharedStorageObjectMethodTest, AppendOperation_RejectedAsynchronously) {
-  ExecuteScript("sharedStorage.append('key', 'value')");
-  EXPECT_FALSE(finished());
-  task_environment_.RunUntilIdle();
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-
-  WorkletV8Helper::HandleScope scope(Isolate());
-  EXPECT_TRUE(v8_resolved_value()->IsString());
-  EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()),
-            "testing error message for append");
-}
-
-TEST_F(SharedStorageObjectMethodTest, DeleteOperation_MissingKey) {
-  ExecuteScript("sharedStorage.delete()");
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-
-  WorkletV8Helper::HandleScope scope(Isolate());
-  EXPECT_TRUE(v8_resolved_value()->IsString());
-  EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()),
-            "Missing or invalid \"key\" argument in sharedStorage.delete()");
-}
-
-TEST_F(SharedStorageObjectMethodTest, DeleteOperation_KeyConvertedToString) {
-  ExecuteScript("sharedStorage.delete(123)");
-  ExecuteScript("sharedStorage.delete(null)");
-  ExecuteScript("sharedStorage.delete(undefined)");
-  ExecuteScript("sharedStorage.delete({dictKey1: 'dictValue1'})");
-  task_environment_.RunUntilIdle();
-
-  EXPECT_EQ(test_client()->observed_delete_params().size(), 4u);
-  EXPECT_EQ(test_client()->observed_delete_params()[0], u"123");
-  EXPECT_EQ(test_client()->observed_delete_params()[1], u"null");
-  EXPECT_EQ(test_client()->observed_delete_params()[2], u"undefined");
-  EXPECT_EQ(test_client()->observed_delete_params()[3], u"[object Object]");
-}
-
-TEST_F(SharedStorageObjectMethodTest, GetOperation_MissingKey) {
-  ExecuteScript("sharedStorage.get()");
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-
-  WorkletV8Helper::HandleScope scope(Isolate());
-  EXPECT_TRUE(v8_resolved_value()->IsString());
-  EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()),
-            "Missing or invalid \"key\" argument in sharedStorage.get()");
-}
-
-TEST_F(SharedStorageObjectMethodTest, GetOperation_FulfilledAsynchronously) {
-  ExecuteScript("sharedStorage.get('key')");
-  EXPECT_FALSE(finished());
-  task_environment_.RunUntilIdle();
-  EXPECT_TRUE(finished());
-  EXPECT_TRUE(fulfilled());
-
-  WorkletV8Helper::HandleScope scope(Isolate());
-  EXPECT_TRUE(v8_resolved_value()->IsString());
-  EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()), "test-value");
-}
-
-TEST_F(SharedStorageObjectMethodTest, GetOperation_KeyConvertedToString) {
-  ExecuteScript("sharedStorage.get(123)");
-  ExecuteScript("sharedStorage.get(null)");
-  ExecuteScript("sharedStorage.get(undefined)");
-  ExecuteScript("sharedStorage.get({dictKey1: 'dictValue1'})");
-  task_environment_.RunUntilIdle();
-
-  EXPECT_EQ(test_client()->observed_get_params().size(), 4u);
-  EXPECT_EQ(test_client()->observed_get_params()[0], u"123");
-  EXPECT_EQ(test_client()->observed_get_params()[1], u"null");
-  EXPECT_EQ(test_client()->observed_get_params()[2], u"undefined");
-  EXPECT_EQ(test_client()->observed_get_params()[3], u"[object Object]");
-}
-
-TEST_F(SharedStorageObjectMethodTest, LengthOperation_FulfilledAsynchronously) {
-  ExecuteScript("sharedStorage.length()");
-  EXPECT_FALSE(finished());
-  task_environment_.RunUntilIdle();
-  EXPECT_TRUE(finished());
-  EXPECT_TRUE(fulfilled());
-
-  WorkletV8Helper::HandleScope scope(Isolate());
-  EXPECT_TRUE(v8_resolved_value()->IsNumber());
-
-  uint32_t n = 0;
-  gin::Converter<uint32_t>::FromV8(Isolate(), v8_resolved_value(), &n);
-  EXPECT_EQ(n, 1u);
-}
-
-TEST_F(SharedStorageObjectMethodTest,
-       RemainingBudgetOperation_FulfilledAsynchronously) {
-  ExecuteScript("sharedStorage.remainingBudget()");
-  EXPECT_FALSE(finished());
-  task_environment_.RunUntilIdle();
-  EXPECT_TRUE(finished());
-  EXPECT_TRUE(fulfilled());
-
-  WorkletV8Helper::HandleScope scope(Isolate());
-  EXPECT_TRUE(v8_resolved_value()->IsNumber());
-
-  double bits = 0.0;
-  gin::Converter<double>::FromV8(Isolate(), v8_resolved_value(), &bits);
-  EXPECT_EQ(bits, 2.5);
-}
-
-TEST_F(SharedStorageObjectMethodTest,
-       EntriesOperationAsyncIterator_OneEmptyBatch_Success) {
-  ExecuteScript(R"(
-    (async () => {
-      for await (const [key, value] of sharedStorage.entries()) {
-        console.log(key + ';' + value);
-      }
-    })();
-  )");
-  task_environment_.RunUntilIdle();
-
-  EXPECT_FALSE(finished());
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 0u);
-
-  EXPECT_EQ(test_client()->pending_entries_listeners_count(), 1u);
-  auto remote_listener = test_client()->OfferEntriesListenerAtFront();
-
-  remote_listener->DidReadEntries(
-      /*success=*/true, /*error_message=*/{}, CreateBatchResult({}),
-      /*has_more_entries=*/false, /*total_queued_to_send=*/0);
-  task_environment_.RunUntilIdle();
-
-  EXPECT_TRUE(finished());
-  EXPECT_TRUE(fulfilled());
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 0u);
-}
-
-TEST_F(SharedStorageObjectMethodTest,
-       EntriesOperationAsyncIterator_FirstBatchError_Failure) {
-  ExecuteScript(R"(
-    (async () => {
-      for await (const [key, value] of sharedStorage.entries()) {
-        console.log(key + ';' + value);
-      }
-    })();
-  )");
-  task_environment_.RunUntilIdle();
-
-  EXPECT_FALSE(finished());
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 0u);
-
-  EXPECT_EQ(test_client()->pending_entries_listeners_count(), 1u);
-  auto remote_listener = test_client()->OfferEntriesListenerAtFront();
-
-  remote_listener->DidReadEntries(
-      /*success=*/false, /*error_message=*/"Internal error 12345",
-      CreateBatchResult({}),
-      /*has_more_entries=*/true, /*total_queued_to_send=*/0);
-  task_environment_.RunUntilIdle();
-
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 0u);
-
-  WorkletV8Helper::HandleScope scope(Isolate());
-  EXPECT_TRUE(v8_resolved_value()->IsString());
-  EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()),
-            "Internal error 12345");
-}
-
-TEST_F(SharedStorageObjectMethodTest,
-       EntriesOperationAsyncIterator_TwoBatches_Success) {
-  ExecuteScript(R"(
-    (async () => {
-      for await (const [key, value] of sharedStorage.entries()) {
-        console.log(key + ';' + value);
-      }
-    })();
-  )");
-  task_environment_.RunUntilIdle();
-
-  EXPECT_FALSE(finished());
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 0u);
-
-  EXPECT_EQ(test_client()->pending_entries_listeners_count(), 1u);
-  auto remote_listener = test_client()->OfferEntriesListenerAtFront();
-
-  remote_listener->DidReadEntries(
-      /*success=*/true, /*error_message=*/{},
-      CreateBatchResult({{u"key0", u"value0"}}),
-      /*has_more_entries=*/true, /*total_queued_to_send=*/3);
-  task_environment_.RunUntilIdle();
-
-  EXPECT_FALSE(finished());
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 1u);
-  EXPECT_EQ(test_client()->observed_console_log_messages()[0], "key0;value0");
-
-  remote_listener->DidReadEntries(
-      /*success=*/true, /*error_message=*/{},
-      CreateBatchResult({{u"key1", u"value1"}, {u"key2", u"value2"}}),
-      /*has_more_entries=*/false, /*total_queued_to_send=*/3);
-  task_environment_.RunUntilIdle();
-
-  EXPECT_TRUE(finished());
-  EXPECT_TRUE(fulfilled());
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 3u);
-  EXPECT_EQ(test_client()->observed_console_log_messages()[1], "key1;value1");
-  EXPECT_EQ(test_client()->observed_console_log_messages()[2], "key2;value2");
-}
-
-TEST_F(SharedStorageObjectMethodTest,
-       EntriesOperationAsyncIterator_SecondBatchError_Failure) {
-  ExecuteScript(R"(
-    (async () => {
-      for await (const [key, value] of sharedStorage.entries()) {
-        console.log(key + ';' + value);
-      }
-    })();
-  )");
-  task_environment_.RunUntilIdle();
-
-  EXPECT_FALSE(finished());
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 0u);
-
-  EXPECT_EQ(test_client()->pending_entries_listeners_count(), 1u);
-  auto remote_listener = test_client()->OfferEntriesListenerAtFront();
-
-  remote_listener->DidReadEntries(
-      /*success=*/true, /*error_message=*/{},
-      CreateBatchResult({{u"key0", u"value0"}}),
-      /*has_more_entries=*/true, /*total_queued_to_send=*/3);
-  task_environment_.RunUntilIdle();
-
-  EXPECT_FALSE(finished());
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 1u);
-  EXPECT_EQ(test_client()->observed_console_log_messages()[0], "key0;value0");
-
-  remote_listener->DidReadEntries(
-      /*success=*/false, /*error_message=*/"Internal error 12345",
-      CreateBatchResult({}),
-      /*has_more_entries=*/true, /*total_queued_to_send=*/3);
-  task_environment_.RunUntilIdle();
-
-  EXPECT_TRUE(finished());
-  EXPECT_FALSE(fulfilled());
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 1u);
-
-  WorkletV8Helper::HandleScope scope(Isolate());
-  EXPECT_TRUE(v8_resolved_value()->IsString());
-  EXPECT_EQ(gin::V8ToString(Isolate(), v8_resolved_value()),
-            "Internal error 12345");
-}
-
-TEST_F(SharedStorageObjectMethodTest,
-       KeysOperationAsyncIterator_OneBatch_Success) {
-  ExecuteScript(R"(
-    (async () => {
-      for await (const key of sharedStorage.keys()) {
-        console.log(key);
-      }
-    })();
-  )");
-  task_environment_.RunUntilIdle();
-
-  EXPECT_FALSE(finished());
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 0u);
-
-  EXPECT_EQ(test_client()->pending_keys_listeners_count(), 1u);
-  auto remote_listener = test_client()->OfferKeysListenerAtFront();
-
-  // It's harmless to still send the `value` field. They will simply be ignored.
-  remote_listener->DidReadEntries(
-      /*success=*/true, /*error_message=*/{},
-      CreateBatchResult({{u"key0", u"value0"}, {u"key1", u"value1"}}),
-      /*has_more_entries=*/false, /*total_queued_to_send=*/2);
-  task_environment_.RunUntilIdle();
-
-  EXPECT_TRUE(finished());
-  EXPECT_TRUE(fulfilled());
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 2u);
-  EXPECT_EQ(test_client()->observed_console_log_messages()[0], "key0");
-  EXPECT_EQ(test_client()->observed_console_log_messages()[1], "key1");
-}
-
-TEST_F(SharedStorageObjectMethodTest,
-       KeysOperationAsyncIterator_ManuallyCallNext) {
-  ExecuteScript(R"(
-    (async () => {
-      const keys_iterator = sharedStorage.keys()[Symbol.asyncIterator]();
-
-      keys_iterator.next(); // result0 skipped
-      keys_iterator.next(); // result1 skipped
-
-      const result2 = await keys_iterator.next();
-      console.log(JSON.stringify(result2, Object.keys(result2).sort()));
-
-      const result3 = await keys_iterator.next();
-      console.log(JSON.stringify(result3, Object.keys(result3).sort()));
-
-      const result4 = await keys_iterator.next();
-      console.log(JSON.stringify(result4, Object.keys(result4).sort()));
-
-      const result5 = await keys_iterator.next();
-      console.log(JSON.stringify(result5, Object.keys(result5).sort()));
-    })();
-  )");
-  task_environment_.RunUntilIdle();
-
-  EXPECT_FALSE(finished());
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 0u);
-
-  EXPECT_EQ(test_client()->pending_keys_listeners_count(), 1u);
-  auto remote_listener = test_client()->OfferKeysListenerAtFront();
-
-  remote_listener->DidReadEntries(
-      /*success=*/true, /*error_message=*/{},
-      CreateBatchResult({{u"key0", /*value=*/{}}}),
-      /*has_more_entries=*/true, /*total_queued_to_send=*/6);
-  task_environment_.RunUntilIdle();
-
-  EXPECT_FALSE(finished());
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 0u);
-
-  remote_listener->DidReadEntries(
-      /*success=*/true, /*error_message=*/{},
-      CreateBatchResult({{u"key1", /*value=*/{}}, {u"key2", /*value=*/{}}}),
-      /*has_more_entries=*/true, /*total_queued_to_send=*/6);
-  task_environment_.RunUntilIdle();
-
-  EXPECT_FALSE(finished());
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 1u);
-  EXPECT_EQ(test_client()->observed_console_log_messages()[0],
-            "{\"done\":false,\"value\":\"key2\"}");
-
-  remote_listener->DidReadEntries(
-      /*success=*/true, /*error_message=*/{},
-      CreateBatchResult({{u"key3", /*value=*/{}}}),
-      /*has_more_entries=*/false, /*total_queued_to_send=*/6);
-  task_environment_.RunUntilIdle();
-
-  EXPECT_TRUE(finished());
-  EXPECT_TRUE(fulfilled());
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 4u);
-  EXPECT_EQ(test_client()->observed_console_log_messages()[1],
-            "{\"done\":false,\"value\":\"key3\"}");
-  EXPECT_EQ(test_client()->observed_console_log_messages()[2],
-            "{\"done\":true}");
-  EXPECT_EQ(test_client()->observed_console_log_messages()[3],
-            "{\"done\":true}");
-}
-
-TEST_F(SharedStorageObjectMethodTest, ConsoleLogOperation_NoArgument) {
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    v8::Local<v8::Context> context = LocalContext();
-    v8::Context::Scope context_scope(context);
-
-    v8::Local<v8::Value> v8_result = EvalJs("console.log()");
-    EXPECT_TRUE(!v8_result.IsEmpty());
-    EXPECT_TRUE(v8_result->IsUndefined());
-  }
-
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 1u);
-  EXPECT_EQ(test_client()->observed_console_log_messages()[0], "");
-}
-
-TEST_F(SharedStorageObjectMethodTest, ConsoleLogOperation_SingleArgument) {
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    v8::Local<v8::Context> context = LocalContext();
-    v8::Context::Scope context_scope(context);
-
-    v8::Local<v8::Value> v8_result = EvalJs("console.log('123')");
-    EXPECT_TRUE(!v8_result.IsEmpty());
-    EXPECT_TRUE(v8_result->IsUndefined());
-  }
-
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 1u);
-  EXPECT_EQ(test_client()->observed_console_log_messages()[0], "123");
-}
-
-TEST_F(SharedStorageObjectMethodTest, ConsoleLogOperation_MultipleArguments) {
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    v8::Local<v8::Context> context = LocalContext();
-    v8::Context::Scope context_scope(context);
-
-    v8::Local<v8::Value> v8_result =
-        EvalJs("console.log(123, '456', true, undefined, null, {})");
-    EXPECT_TRUE(!v8_result.IsEmpty());
-    EXPECT_TRUE(v8_result->IsUndefined());
-  }
-
-  EXPECT_EQ(test_client()->observed_console_log_messages().size(), 1u);
-  EXPECT_EQ(test_client()->observed_console_log_messages()[0],
-            "123 456 true undefined null [object Object]");
-}
-
-class SharedStorageObjectPropertyTest : public SharedStorageRunOperationTest {
- public:
-  SharedStorageObjectPropertyTest() = default;
-
-  void SetEmbedderContext(absl::optional<std::u16string> embedder_context) {
-    OverrideGlobalScope(std::make_unique<SharedStorageWorkletGlobalScope>(
-        /*private_aggregation_permissions_policy_allowed=*/true,
-        embedder_context));
-
-    // Run AddModule so that sharedStorage is exposed.
-    SimulateAddModule(R"()");
-  }
-
-  void ExecuteScript(const std::string& script_body) {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    v8::Local<v8::Context> context = LocalContext();
-    v8::Context::Scope context_scope(context);
-
-    v8::Local<v8::Value> v8_result = EvalJs(script_body);
-
-    ASSERT_TRUE(!v8_result.IsEmpty());
-    ASSERT_FALSE(v8_result->IsPromise());
-
-    v8_result_value_ =
-        v8::Global<v8::Value>(Isolate(), v8_result.As<v8::Value>());
-  }
-
-  v8::Local<v8::Value> v8_result_value() {
-    v8::Local<v8::Value> v8_result_value = v8_result_value_.Get(Isolate());
-    return v8_result_value;
-  }
-
- protected:
-  base::HistogramTester histogram_tester_;
-
- private:
-  v8::Global<v8::Value> v8_result_value_;
-};
-
-TEST_F(SharedStorageObjectPropertyTest, ContextOperation_String) {
-  SetEmbedderContext(absl::make_optional(u"some embedder context"));
-  EXPECT_EQ(GetTypeOf("sharedStorage.context"), "string");
-
-  ExecuteScript("sharedStorage.context");
-
-  WorkletV8Helper::HandleScope scope(Isolate());
-  EXPECT_TRUE(v8_result_value()->IsString());
-  EXPECT_EQ(gin::V8ToString(Isolate(), v8_result_value()),
-            "some embedder context");
-  histogram_tester_.ExpectUniqueSample(WorkletContextDefinedHistogram, true, 2);
-}
-
-TEST_F(SharedStorageObjectPropertyTest, ContextOperation_Undefined) {
-  SetEmbedderContext(absl::nullopt);
-  EXPECT_EQ(GetTypeOf("sharedStorage.context"), "undefined");
-
-  ExecuteScript("sharedStorage.context");
-
-  WorkletV8Helper::HandleScope scope(Isolate());
-  EXPECT_TRUE(v8_result_value()->IsUndefined());
-  histogram_tester_.ExpectUniqueSample(WorkletContextDefinedHistogram, false,
-                                       2);
-}
-
-class SharedStoragePrivateAggregationTest
-    : public SharedStorageRunOperationTest {
- public:
-  SharedStoragePrivateAggregationTest() {
-    private_aggregation_feature_.InitWithFeaturesAndParameters(
-        /*enabled_features=*/
-        {{blink::features::kPrivateAggregationApi,
-          {{"enabled_in_shared_storage", "true"}}}},
-        /*disabled_features=*/{});
-  }
-
-  void SetUp() override {
-    // Run AddModule so that `privateAggregation` is exposed.
-    SimulateAddModule(R"()");
-  }
-
-  void ExecuteScriptExpectNoError(const std::string& script_body) {
-    std::string error_message;
-    ExecuteScript(script_body, &error_message);
-    EXPECT_TRUE(error_message.empty());
-  }
-
-  // error_message` being `nullptr` indicates no error is expected.
-  void ExecuteScriptAndValidateContribution(
-      const std::string& script_body,
-      absl::uint128 expected_bucket,
-      int expected_value,
-      blink::mojom::DebugModeDetailsPtr expected_debug_mode_details =
-          blink::mojom::DebugModeDetails::New(),
-      std::string* error_message = nullptr) {
-    EXPECT_CALL(*mock_private_aggregation_host(), SendHistogramReport)
-        .WillOnce(testing::Invoke(
-            [&](std::vector<
-                    blink::mojom::AggregatableReportHistogramContributionPtr>
-                    contributions,
-                blink::mojom::AggregationServiceMode aggregation_mode,
-                blink::mojom::DebugModeDetailsPtr debug_mode_details) {
-              ASSERT_EQ(contributions.size(), 1u);
-              EXPECT_EQ(contributions[0]->bucket, expected_bucket);
-              EXPECT_EQ(contributions[0]->value, expected_value);
-              EXPECT_EQ(aggregation_mode,
-                        blink::mojom::AggregationServiceMode::kDefault);
-              EXPECT_TRUE(debug_mode_details == expected_debug_mode_details);
-            }));
-
-    if (error_message == nullptr) {
-      ExecuteScriptExpectNoError(script_body);
-    } else {
-      ExecuteScript(script_body, error_message);
-    }
-
-    EXPECT_TRUE(test_client()->observed_record_use_counter_call());
-
-    mock_private_aggregation_host_receiver_set_.FlushForTesting();
-  }
-
-  std::string ExecuteScriptReturningError(const std::string& script_body) {
-    EXPECT_CALL(*mock_private_aggregation_host(), SendHistogramReport).Times(0);
-
-    std::string error_message;
-    ExecuteScript(script_body, &error_message);
-    EXPECT_FALSE(error_message.empty());
-
-    // These tests all invoke sendHistogramReport (albeit incorrectly), so the
-    // use counter is expected to be triggered.
-    EXPECT_TRUE(test_client()->observed_record_use_counter_call());
-    return error_message;
-  }
-
- private:
-  void ExecuteScript(const std::string& script_body, std::string* out_error) {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    v8::Local<v8::Context> context = LocalContext();
-    v8::Context::Scope context_scope(context);
-    base::OnceClosure operation_completion_closure =
-        global_scope_->StartOperationForTesting(InitNewRemotePAHost());
-
-    WorkletV8Helper::CompileAndRunScript(
-        LocalContext(), script_body, GURL("https://example.test"), out_error);
-
-    std::move(operation_completion_closure).Run();
-  }
-
-  base::test::ScopedFeatureList private_aggregation_feature_;
-};
-
-TEST_F(SharedStoragePrivateAggregationTest, BasicTest) {
-  ExecuteScriptAndValidateContribution(
-      "privateAggregation.sendHistogramReport({bucket: 1n, value: 2});",
-      /*expected_bucket=*/1, /*expected_value=*/2);
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, ZeroBucket) {
-  ExecuteScriptAndValidateContribution(
-      "privateAggregation.sendHistogramReport({bucket: 0n, value: 2});",
-      /*expected_bucket=*/0, /*expected_value=*/2);
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, ZeroValue) {
-  ExecuteScriptAndValidateContribution(
-      "privateAggregation.sendHistogramReport({bucket: 1n, value: 0});",
-      /*expected_bucket=*/1, /*expected_value=*/0);
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, LargeBucket) {
-  ExecuteScriptAndValidateContribution(
-      "privateAggregation.sendHistogramReport({bucket: 18446744073709551616n, "
-      "value: 2});",
-      /*expected_bucket=*/absl::MakeUint128(/*high=*/1, /*low=*/0),
-      /*expected_value=*/2);
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, MaxBucket) {
-  ExecuteScriptAndValidateContribution(
-      "privateAggregation.sendHistogramReport({bucket: "
-      "340282366920938463463374607431768211455n, value: 2});",
-      /*expected_bucket=*/absl::Uint128Max(), /*expected_value=*/2);
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, TooLargeBucket_Rejected) {
-  std::string error_str = ExecuteScriptReturningError(
-      "privateAggregation.sendHistogramReport({bucket: "
-      "340282366920938463463374607431768211456n, value: 2});");
-
-  EXPECT_EQ(error_str,
-            "https://example.test/:1 Uncaught TypeError: BigInt is too large.");
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, NegativeBucket_Rejected) {
-  std::string error_str = ExecuteScriptReturningError(
-      "privateAggregation.sendHistogramReport({bucket: "
-      "-1n, value: 2});");
-
-  EXPECT_EQ(error_str,
-            "https://example.test/:1 Uncaught TypeError: BigInt must be "
-            "non-negative.");
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, NonBigIntBucket_Rejected) {
-  std::string error_str = ExecuteScriptReturningError(
-      "privateAggregation.sendHistogramReport({bucket: 1, value: 2});");
-
-  EXPECT_EQ(
-      error_str,
-      "https://example.test/:1 Uncaught TypeError: bucket must be a BigInt.");
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, NonIntegerValue_Rejected) {
-  std::string error_str = ExecuteScriptReturningError(
-      "privateAggregation.sendHistogramReport({bucket: 1n, value: 2.3});");
-
-  EXPECT_EQ(error_str,
-            "https://example.test/:1 Uncaught TypeError: Value must be an "
-            "integer Number.");
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, NegativeValue_Rejected) {
-  std::string error_str = ExecuteScriptReturningError(
-      "privateAggregation.sendHistogramReport({bucket: 1n, value: -1});");
-
-  EXPECT_EQ(error_str,
-            "https://example.test/:1 Uncaught TypeError: Value must be "
-            "non-negative.");
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, NoApiUse_UseCounterNotCalled) {
-  EXPECT_CALL(*mock_private_aggregation_host(), SendHistogramReport).Times(0);
-  ExecuteScriptExpectNoError("const a = 1;");
-  EXPECT_FALSE(test_client()->observed_record_use_counter_call());
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, MultipleRequests) {
-  EXPECT_CALL(*mock_private_aggregation_host(), SendHistogramReport)
-      .WillOnce(testing::Invoke(
-          [](std::vector<
-                 blink::mojom::AggregatableReportHistogramContributionPtr>
-                 contributions,
-             blink::mojom::AggregationServiceMode aggregation_mode,
-             blink::mojom::DebugModeDetailsPtr debug_mode_details) {
-            ASSERT_EQ(contributions.size(), 2u);
-            EXPECT_EQ(contributions[0]->bucket, 1);
-            EXPECT_EQ(contributions[0]->value, 2);
-            EXPECT_EQ(contributions[1]->bucket, 3);
-            EXPECT_EQ(contributions[1]->value, 4);
-            EXPECT_EQ(aggregation_mode,
-                      blink::mojom::AggregationServiceMode::kDefault);
-            ASSERT_FALSE(debug_mode_details.is_null());
-            EXPECT_EQ(*debug_mode_details, blink::mojom::DebugModeDetails());
-          }));
-
-  ExecuteScriptExpectNoError(
-      R"(
-        privateAggregation.sendHistogramReport({bucket: 1n, value: 2});
-        privateAggregation.sendHistogramReport({bucket: 3n, value: 4});
-      )");
-
-  mock_private_aggregation_host_receiver_set_.FlushForTesting();
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, DebugModeWithNoDebugKey) {
-  ExecuteScriptAndValidateContribution(
-      R"(
-        privateAggregation.enableDebugMode();
-        privateAggregation.sendHistogramReport({bucket: 1n, value: 2});
-      )",
-      /*expected_bucket=*/1,
-      /*expected_value=*/2,
-      /*expected_debug_mode_details=*/
-      blink::mojom::DebugModeDetails::New(/*is_enabled=*/true,
-                                          /*debug_key=*/nullptr));
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, DebugModeWithDebugKey) {
-  ExecuteScriptAndValidateContribution(
-      R"(
-        privateAggregation.enableDebugMode({debug_key: 1234n});
-        privateAggregation.sendHistogramReport({bucket: 1n, value: 2});
-      )",
-      /*expected_bucket=*/1,
-      /*expected_value=*/2,
-      /*expected_debug_mode_details=*/
-      blink::mojom::DebugModeDetails::New(
-          /*is_enabled=*/true,
-          /*debug_key=*/blink::mojom::DebugKey::New(1234u)));
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, NegativeDebugKey_Rejected) {
-  std::string error_str = ExecuteScriptReturningError(
-      "privateAggregation.enableDebugMode({debug_key: -1n});");
-
-  EXPECT_EQ(error_str,
-            "https://example.test/:1 Uncaught TypeError: BigInt must be "
-            "non-negative.");
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, TooLargeDebugKey_Rejected) {
-  std::string error_str = ExecuteScriptReturningError(
-      "privateAggregation.enableDebugMode({debug_key: "
-      "18446744073709551616n});");
-
-  EXPECT_EQ(error_str,
-            "https://example.test/:1 Uncaught TypeError: BigInt is too large.");
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, NonBigIntDebugKey_Rejected) {
-  std::string error_str = ExecuteScriptReturningError(
-      "privateAggregation.enableDebugMode({debug_key: 1});");
-
-  EXPECT_EQ(error_str,
-            "https://example.test/:1 Uncaught TypeError: debug_key must be a "
-            "BigInt.");
-}
-
-TEST_F(SharedStoragePrivateAggregationTest,
-       InvalidEnableDebugModeArgument_Rejected) {
-  // The debug key is not wrapped in a dictionary.
-  std::string error_str =
-      ExecuteScriptReturningError("privateAggregation.enableDebugMode(1234n);");
-
-  EXPECT_EQ(error_str,
-            "https://example.test/:1 Uncaught TypeError: Invalid argument in "
-            "enableDebugMode.");
-}
-
-TEST_F(SharedStoragePrivateAggregationTest,
-       EnableDebugModeCalledTwice_SecondCallFails) {
-  std::string error_str;
-
-  // Note that the first call still applies to future requests if the error is
-  // caught. Here, we rethrow it to check its value.
-  ExecuteScriptAndValidateContribution(
-      R"(
-        let error;
-        try {
-          privateAggregation.enableDebugMode({debug_key: 1234n});
-          privateAggregation.enableDebugMode();
-        } catch (e) {
-          error = e;
-        }
-        privateAggregation.sendHistogramReport({bucket: 1n, value: 2});
-        throw error;
-      )",
-      /*expected_bucket=*/1,
-      /*expected_value=*/2,
-      /*expected_debug_mode_details=*/
-      blink::mojom::DebugModeDetails::New(
-          /*is_enabled=*/true,
-          /*debug_key=*/blink::mojom::DebugKey::New(1234u)),
-      &error_str);
-
-  EXPECT_EQ(error_str,
-            "https://example.test/:10 Uncaught TypeError: enableDebugMode may "
-            "be called at most once.");
-}
-
-// Note that FLEDGE worklets have different behavior in this case.
-TEST_F(SharedStoragePrivateAggregationTest,
-       EnableDebugModeCalledAfterRequest_DoesntApply) {
-  ExecuteScriptAndValidateContribution(
-      "privateAggregation.sendHistogramReport({bucket: 1n, value: 2});",
-      /*expected_bucket=*/1,
-      /*expected_value=*/2,
-      /*expected_debug_mode_details=*/
-      blink::mojom::DebugModeDetails::New());
-
-  ExecuteScriptExpectNoError(
-      "privateAggregation.enableDebugMode({debug_key: 1234n});");
-}
-
-TEST_F(SharedStoragePrivateAggregationTest, MultipleDebugModeRequests) {
-  EXPECT_CALL(*mock_private_aggregation_host(), SendHistogramReport)
-      .WillOnce(testing::Invoke(
-          [](std::vector<
-                 blink::mojom::AggregatableReportHistogramContributionPtr>
-                 contributions,
-             blink::mojom::AggregationServiceMode aggregation_mode,
-             blink::mojom::DebugModeDetailsPtr debug_mode_details) {
-            ASSERT_EQ(contributions.size(), 2u);
-            EXPECT_EQ(contributions[0]->bucket, 1);
-            EXPECT_EQ(contributions[0]->value, 2);
-            EXPECT_EQ(contributions[1]->bucket, 3);
-            EXPECT_EQ(contributions[1]->value, 4);
-            EXPECT_EQ(aggregation_mode,
-                      blink::mojom::AggregationServiceMode::kDefault);
-            EXPECT_EQ(debug_mode_details,
-                      blink::mojom::DebugModeDetails::New(
-                          /*is_enabled=*/true,
-                          /*debug_key=*/blink::mojom::DebugKey::New(1234u)));
-          }));
-
-  ExecuteScriptExpectNoError(
-      R"(
-        privateAggregation.enableDebugMode({debug_key: 1234n});
-        privateAggregation.sendHistogramReport({bucket: 1n, value: 2});
-        privateAggregation.sendHistogramReport({bucket: 3n, value: 4});
-      )");
-
-  mock_private_aggregation_host_receiver_set_.FlushForTesting();
-}
-
-// Regression test for crbug.com/1429895.
-TEST_F(SharedStoragePrivateAggregationTest,
-       GlobalScopeDeletedBeforeOperationCompletes_ContributionsStillFlushed) {
-  EXPECT_CALL(*mock_private_aggregation_host(), SendHistogramReport)
-      .WillOnce(testing::Invoke(
-          [&](std::vector<
-                  blink::mojom::AggregatableReportHistogramContributionPtr>
-                  contributions,
-              blink::mojom::AggregationServiceMode aggregation_mode,
-              blink::mojom::DebugModeDetailsPtr debug_mode_details) {
-            ASSERT_EQ(contributions.size(), 1u);
-            EXPECT_EQ(contributions[0]->bucket, 1);
-            EXPECT_EQ(contributions[0]->value, 2);
-            EXPECT_EQ(aggregation_mode,
-                      blink::mojom::AggregationServiceMode::kDefault);
-            EXPECT_FALSE(debug_mode_details->is_enabled);
-          }));
-
-  {
-    WorkletV8Helper::HandleScope scope(Isolate());
-    v8::Local<v8::Context> context = LocalContext();
-    v8::Context::Scope context_scope(context);
-    std::string error_str;
-
-    // Intentionally discard returned operation completion closure without
-    // running.
-    global_scope_->StartOperationForTesting(InitNewRemotePAHost());
-
-    WorkletV8Helper::CompileAndRunScript(
-        LocalContext(),
-        "privateAggregation.sendHistogramReport({bucket: 1n, value: 2});",
-        GURL("https://example.test"), &error_str);
-  }
-
-  global_scope_.reset();
-  mock_private_aggregation_host_receiver_set_.FlushForTesting();
-}
-
-class SharedStoragePrivateAggregationPermissionsPolicyDisabledTest
-    : public SharedStoragePrivateAggregationTest {
- public:
-  void SetUp() override {
-    OverrideGlobalScope(std::make_unique<SharedStorageWorkletGlobalScope>(
-        /*private_aggregation_permissions_policy_allowed=*/false,
-        /*embedder_context=*/absl::nullopt));
-    SharedStoragePrivateAggregationTest::SetUp();
-  }
-};
-
-TEST_F(SharedStoragePrivateAggregationPermissionsPolicyDisabledTest, Rejected) {
-  std::string error_str = ExecuteScriptReturningError(
-      "privateAggregation.sendHistogramReport({bucket: 1, value: 2});");
-
-  EXPECT_EQ(
-      error_str,
-      "https://example.test/:1 Uncaught TypeError: The \"private-aggregation\" "
-      "Permissions Policy denied the method on privateAggregation.");
-}
-
-}  // namespace shared_storage_worklet
diff --git a/content/services/shared_storage_worklet/shared_storage_worklet_service_impl.cc b/content/services/shared_storage_worklet/shared_storage_worklet_service_impl.cc
deleted file mode 100644
index 6e76c461..0000000
--- a/content/services/shared_storage_worklet/shared_storage_worklet_service_impl.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/services/shared_storage_worklet/shared_storage_worklet_service_impl.h"
-
-#include <utility>
-
-#include "base/check.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "third_party/blink/public/mojom/private_aggregation/private_aggregation_host.mojom.h"
-
-namespace shared_storage_worklet {
-
-SharedStorageWorkletServiceImpl::SharedStorageWorkletServiceImpl(
-    mojo::PendingReceiver<blink::mojom::SharedStorageWorkletService> receiver,
-    base::OnceClosure disconnect_handler)
-    : receiver_(this, std::move(receiver)) {
-  receiver_.set_disconnect_handler(std::move(disconnect_handler));
-}
-
-SharedStorageWorkletServiceImpl::~SharedStorageWorkletServiceImpl() = default;
-
-void SharedStorageWorkletServiceImpl::Initialize(
-    mojo::PendingAssociatedRemote<
-        blink::mojom::SharedStorageWorkletServiceClient> client,
-    bool private_aggregation_permissions_policy_allowed,
-    const absl::optional<std::u16string>& embedder_context) {
-  DCHECK(!global_scope_);
-  client_.Bind(std::move(client));
-  private_aggregation_permissions_policy_allowed_ =
-      private_aggregation_permissions_policy_allowed;
-  embedder_context_ = embedder_context;
-}
-
-void SharedStorageWorkletServiceImpl::AddModule(
-    mojo::PendingRemote<network::mojom::URLLoaderFactory>
-        pending_url_loader_factory,
-    const GURL& script_source_url,
-    AddModuleCallback callback) {
-  DCHECK(!global_scope_);
-  GetGlobalScope()->AddModule(std::move(pending_url_loader_factory),
-                              client_.get(), script_source_url,
-                              std::move(callback));
-}
-
-void SharedStorageWorkletServiceImpl::RunURLSelectionOperation(
-    const std::string& name,
-    const std::vector<GURL>& urls,
-    const std::vector<uint8_t>& serialized_data,
-    mojo::PendingRemote<blink::mojom::PrivateAggregationHost>
-        private_aggregation_host,
-    RunURLSelectionOperationCallback callback) {
-  GetGlobalScope()->RunURLSelectionOperation(
-      name, urls, serialized_data, std::move(private_aggregation_host),
-      std::move(callback));
-}
-
-void SharedStorageWorkletServiceImpl::RunOperation(
-    const std::string& name,
-    const std::vector<uint8_t>& serialized_data,
-    mojo::PendingRemote<blink::mojom::PrivateAggregationHost>
-        private_aggregation_host,
-    RunOperationCallback callback) {
-  GetGlobalScope()->RunOperation(name, serialized_data,
-                                 std::move(private_aggregation_host),
-                                 std::move(callback));
-}
-
-SharedStorageWorkletGlobalScope*
-SharedStorageWorkletServiceImpl::GetGlobalScope() {
-  if (!global_scope_) {
-    global_scope_ = std::make_unique<SharedStorageWorkletGlobalScope>(
-        private_aggregation_permissions_policy_allowed_, embedder_context_);
-  }
-
-  return global_scope_.get();
-}
-
-}  // namespace shared_storage_worklet
diff --git a/content/services/shared_storage_worklet/shared_storage_worklet_service_impl.h b/content/services/shared_storage_worklet/shared_storage_worklet_service_impl.h
deleted file mode 100644
index 8dcd42e..0000000
--- a/content/services/shared_storage_worklet/shared_storage_worklet_service_impl.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_SERVICES_SHARED_STORAGE_WORKLET_SHARED_STORAGE_WORKLET_SERVICE_IMPL_H_
-#define CONTENT_SERVICES_SHARED_STORAGE_WORKLET_SHARED_STORAGE_WORKLET_SERVICE_IMPL_H_
-
-#include "content/services/shared_storage_worklet/shared_storage_worklet_global_scope.h"
-#include "mojo/public/cpp/bindings/associated_remote.h"
-#include "mojo/public/cpp/bindings/pending_associated_remote.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "services/network/public/mojom/url_loader_factory.mojom-forward.h"
-#include "third_party/blink/public/mojom/private_aggregation/private_aggregation_host.mojom.h"
-#include "third_party/blink/public/mojom/shared_storage/shared_storage_worklet_service.mojom.h"
-
-namespace shared_storage_worklet {
-
-// blink::mojom::SharedStorageWorkletService implementation. Responsible for
-// handling worklet operations. The service is started through
-// `SharedStorageWorkletDriver::StartWorkletService`.
-class SharedStorageWorkletServiceImpl
-    : public blink::mojom::SharedStorageWorkletService {
- public:
-  explicit SharedStorageWorkletServiceImpl(
-      mojo::PendingReceiver<blink::mojom::SharedStorageWorkletService> receiver,
-      base::OnceClosure disconnect_handler);
-  ~SharedStorageWorkletServiceImpl() override;
-
-  // blink::mojom::SharedStorageWorkletService implementation:
-  void Initialize(
-      mojo::PendingAssociatedRemote<
-          blink::mojom::SharedStorageWorkletServiceClient> client,
-      bool private_aggregation_permissions_policy_allowed,
-      const absl::optional<std::u16string>& embedder_context) override;
-  void AddModule(mojo::PendingRemote<network::mojom::URLLoaderFactory>
-                     pending_url_loader_factory,
-                 const GURL& script_source_url,
-                 AddModuleCallback callback) override;
-  void RunURLSelectionOperation(
-      const std::string& name,
-      const std::vector<GURL>& urls,
-      const std::vector<uint8_t>& serialized_data,
-      mojo::PendingRemote<blink::mojom::PrivateAggregationHost>
-          private_aggregation_host,
-      RunURLSelectionOperationCallback callback) override;
-  void RunOperation(const std::string& name,
-                    const std::vector<uint8_t>& serialized_data,
-                    mojo::PendingRemote<blink::mojom::PrivateAggregationHost>
-                        private_aggregation_host,
-                    RunOperationCallback callback) override;
-
- private:
-  SharedStorageWorkletGlobalScope* GetGlobalScope();
-
-  // `receiver_`'s disconnect handler explicitly deletes the worklet thread
-  // object that owns this service, thus deleting `this` upon disconnect. To
-  // ensure that the worklet thread object and this service are not leaked,
-  // `receiver_` must be cut off from the remote side when the worklet is
-  // supposed to be destroyed.
-  mojo::Receiver<blink::mojom::SharedStorageWorkletService> receiver_;
-
-  // This is associated because on the client side (i.e. worklet host), we want
-  // the call-in methods (e.g. storage access) and the callback methods
-  // (e.g. finish of a run-operation) to preserve their invocation order. This
-  // guarantee is desirable, as the client may shut down the service immediately
-  // after it gets the callback and sees no more outstanding operations, thus we
-  // want it to be more likely for the worklet to finish its intended work.
-  //
-  // In contrast, the `receiver_` doesn't need to be associated. This is a
-  // standalone service, so the starting of a worklet operation doesn't have to
-  // depend on / preserve the order with messages of other types.
-  mojo::AssociatedRemote<blink::mojom::SharedStorageWorkletServiceClient>
-      client_;
-
-  // Whether the "private-aggregation" permissions policy is enabled in the
-  // worklet.
-  bool private_aggregation_permissions_policy_allowed_ = false;
-
-  std::unique_ptr<SharedStorageWorkletGlobalScope> global_scope_;
-
-  // If this worklet is inside a fenced frame or a URN iframe,
-  // `embedder_context_` represents any contextual information written to the
-  // frame's `blink::FencedFrameConfig` by the embedder before navigation to the
-  // config. `embedder_context_` is passed to the worklet upon initialization.
-  absl::optional<std::u16string> embedder_context_;
-};
-
-}  // namespace shared_storage_worklet
-
-#endif  // CONTENT_SERVICES_SHARED_STORAGE_WORKLET_SHARED_STORAGE_WORKLET_SERVICE_IMPL_H_
diff --git a/content/services/shared_storage_worklet/unnamed_operation_handler.cc b/content/services/shared_storage_worklet/unnamed_operation_handler.cc
deleted file mode 100644
index d9b016c..0000000
--- a/content/services/shared_storage_worklet/unnamed_operation_handler.cc
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/services/shared_storage_worklet/unnamed_operation_handler.h"
-
-#include "content/services/shared_storage_worklet/worklet_v8_helper.h"
-#include "gin/arguments.h"
-#include "gin/function_template.h"
-#include "v8/include/v8-context.h"
-#include "v8/include/v8-function.h"
-#include "v8/include/v8-object.h"
-#include "v8/include/v8-promise.h"
-#include "v8/include/v8-value-serializer.h"
-
-namespace shared_storage_worklet {
-
-struct UnnamedOperationHandler::PendingRequest {
-  explicit PendingRequest(
-      blink::mojom::SharedStorageWorkletService::RunOperationCallback callback);
-
-  ~PendingRequest();
-
-  blink::mojom::SharedStorageWorkletService::RunOperationCallback callback;
-};
-
-UnnamedOperationHandler::PendingRequest::PendingRequest(
-    blink::mojom::SharedStorageWorkletService::RunOperationCallback callback)
-    : callback(std::move(callback)) {}
-
-UnnamedOperationHandler::PendingRequest::~PendingRequest() = default;
-
-UnnamedOperationHandler::UnnamedOperationHandler(
-    const std::map<std::string, v8::Global<v8::Function>>&
-        operation_definition_map)
-    : operation_definition_map_(operation_definition_map) {}
-
-UnnamedOperationHandler::~UnnamedOperationHandler() = default;
-
-void UnnamedOperationHandler::RunOperation(
-    v8::Local<v8::Context> context,
-    const std::string& name,
-    const std::vector<uint8_t>& serialized_data,
-    blink::mojom::SharedStorageWorkletService::RunOperationCallback callback) {
-  auto it = operation_definition_map_->find(name);
-  if (it == operation_definition_map_->end()) {
-    std::move(callback).Run(/*success=*/false, "Cannot find operation name.");
-    return;
-  }
-
-  v8::Isolate* isolate = context->GetIsolate();
-
-  v8::Context::Scope context_scope(context);
-
-  v8::Local<v8::Function> run_function = it->second.Get(isolate);
-
-  v8::Local<v8::Object> js_data;
-
-  if (serialized_data.empty()) {
-    js_data = v8::Object::New(isolate);
-  } else {
-    v8::ValueDeserializer deserializer(isolate, serialized_data.data(),
-                                       serialized_data.size());
-    v8::Local<v8::Value> value =
-        deserializer.ReadValue(context).ToLocalChecked();
-    js_data = value->ToObject(context).ToLocalChecked();
-  }
-
-  std::vector<v8::Local<v8::Value>> args{js_data};
-
-  std::string error_message;
-  v8::MaybeLocal<v8::Value> result = WorkletV8Helper::InvokeFunction(
-      context, run_function, args, &error_message);
-
-  if (result.IsEmpty()) {
-    std::move(callback).Run(
-        /*success=*/false, error_message);
-    return;
-  }
-
-  if (!result.ToLocalChecked()->IsPromise()) {
-    std::move(callback).Run(/*success=*/false,
-                            "run() did not return a promise.");
-    return;
-  }
-
-  v8::Local<v8::Promise> result_promise =
-      result.ToLocalChecked().As<v8::Promise>();
-
-  // If the promise is already completed, retrieve and handle the result
-  // directly.
-  if (result_promise->State() == v8::Promise::PromiseState::kFulfilled) {
-    std::move(callback).Run(/*success=*/true, /*error_message=*/{});
-    return;
-  }
-
-  if (result_promise->State() == v8::Promise::PromiseState::kRejected) {
-    error_message = gin::V8ToString(
-        isolate,
-        result_promise->Result()->ToDetailString(context).ToLocalChecked());
-
-    std::move(callback).Run(
-        /*success=*/false, error_message);
-    return;
-  }
-
-  // If the promise is pending, install callback functions that will be
-  // triggered when it completes.
-  auto pending_request = std::make_unique<PendingRequest>(std::move(callback));
-  PendingRequest* pending_request_raw = pending_request.get();
-  pending_requests_.emplace(pending_request_raw, std::move(pending_request));
-
-  v8::Local<v8::Function> fulfilled_callback =
-      gin::CreateFunctionTemplate(
-          isolate, base::BindRepeating(
-                       &UnnamedOperationHandler::OnPromiseFulfilled,
-                       weak_ptr_factory_.GetWeakPtr(), pending_request_raw))
-          ->GetFunction(context)
-          .ToLocalChecked();
-
-  v8::Local<v8::Function> rejected_callback =
-      gin::CreateFunctionTemplate(
-          isolate, base::BindRepeating(
-                       &UnnamedOperationHandler::OnPromiseRejected,
-                       weak_ptr_factory_.GetWeakPtr(), pending_request_raw))
-          ->GetFunction(context)
-          .ToLocalChecked();
-
-  result_promise->Then(context, fulfilled_callback, rejected_callback)
-      .ToLocalChecked();
-}
-
-void UnnamedOperationHandler::OnPromiseFulfilled(PendingRequest* request,
-                                                 gin::Arguments* args) {
-  std::move(request->callback).Run(/*success=*/true, /*error_message=*/{});
-  pending_requests_.erase(request);
-}
-
-void UnnamedOperationHandler::OnPromiseRejected(PendingRequest* request,
-                                                gin::Arguments* args) {
-  std::string error_message;
-  if (!args->GetNext(&error_message)) {
-    std::move(request->callback)
-        .Run(/*success=*/false,
-             "Promise is rejected without an explicit error message.");
-    pending_requests_.erase(request);
-    return;
-  }
-
-  std::move(request->callback).Run(/*success=*/false, error_message);
-
-  pending_requests_.erase(request);
-}
-
-}  // namespace shared_storage_worklet
diff --git a/content/services/shared_storage_worklet/unnamed_operation_handler.h b/content/services/shared_storage_worklet/unnamed_operation_handler.h
deleted file mode 100644
index b1c07a1..0000000
--- a/content/services/shared_storage_worklet/unnamed_operation_handler.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_SERVICES_SHARED_STORAGE_WORKLET_UNNAMED_OPERATION_HANDLER_H_
-#define CONTENT_SERVICES_SHARED_STORAGE_WORKLET_UNNAMED_OPERATION_HANDLER_H_
-
-#include <map>
-
-#include "base/memory/raw_ref.h"
-#include "third_party/blink/public/mojom/shared_storage/shared_storage_worklet_service.mojom.h"
-#include "v8/include/v8-forward.h"
-#include "v8/include/v8-persistent-handle.h"
-
-namespace gin {
-class Arguments;
-}  // namespace gin
-
-namespace shared_storage_worklet {
-
-class UnnamedOperationHandler {
- public:
-  struct PendingRequest;
-
-  explicit UnnamedOperationHandler(
-      const std::map<std::string, v8::Global<v8::Function>>&
-          operation_definition_map);
-
-  ~UnnamedOperationHandler();
-
-  void RunOperation(
-      v8::Local<v8::Context> context,
-      const std::string& name,
-      const std::vector<uint8_t>& serialized_data,
-      blink::mojom::SharedStorageWorkletService::RunOperationCallback callback);
-
-  void OnPromiseFulfilled(PendingRequest* request, gin::Arguments* args);
-
-  void OnPromiseRejected(PendingRequest* request, gin::Arguments* args);
-
- private:
-  const raw_ref<const std::map<std::string, v8::Global<v8::Function>>>
-      operation_definition_map_;
-
-  std::map<PendingRequest*, std::unique_ptr<PendingRequest>> pending_requests_;
-
-  base::WeakPtrFactory<UnnamedOperationHandler> weak_ptr_factory_{this};
-};
-
-}  // namespace shared_storage_worklet
-
-#endif  // CONTENT_SERVICES_SHARED_STORAGE_WORKLET_UNNAMED_OPERATION_HANDLER_H_
diff --git a/content/services/shared_storage_worklet/url_selection_operation_handler.cc b/content/services/shared_storage_worklet/url_selection_operation_handler.cc
deleted file mode 100644
index f349de5..0000000
--- a/content/services/shared_storage_worklet/url_selection_operation_handler.cc
+++ /dev/null
@@ -1,247 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/services/shared_storage_worklet/url_selection_operation_handler.h"
-
-#include "base/ranges/algorithm.h"
-#include "content/services/shared_storage_worklet/worklet_v8_helper.h"
-#include "gin/arguments.h"
-#include "gin/function_template.h"
-#include "v8/include/v8-context.h"
-#include "v8/include/v8-exception.h"
-#include "v8/include/v8-function.h"
-#include "v8/include/v8-object.h"
-#include "v8/include/v8-promise.h"
-#include "v8/include/v8-value-serializer.h"
-
-namespace shared_storage_worklet {
-
-namespace {
-
-const char kErrorMessageReturnValueNotUint32[] =
-    "Promise did not resolve to an uint32 number.";
-
-const char kErrorMessageReturnValueOutOfRange[] =
-    "Promise resolved to a number outside the length of the input urls.";
-
-// Convert ECMAScript value to IDL unsigned long (i.e. uint32):
-// https://webidl.spec.whatwg.org/#es-unsigned-long
-bool ToIDLUnsignedLong(v8::Isolate* isolate,
-                       v8::Local<v8::Value> val,
-                       uint32_t& out) {
-  v8::Local<v8::Context> context = isolate->GetCurrentContext();
-
-  WorkletV8Helper::HandleScope scope(isolate);
-  v8::TryCatch try_catch(isolate);
-
-  v8::Local<v8::Uint32> uint32_val;
-  if (!val->ToUint32(context).ToLocal(&uint32_val))
-    return false;
-
-  out = uint32_val->Value();
-  return true;
-}
-
-}  // namespace
-
-struct UrlSelectionOperationHandler::PendingRequest {
-  explicit PendingRequest(size_t urls_size,
-                          blink::mojom::SharedStorageWorkletService::
-                              RunURLSelectionOperationCallback callback);
-
-  ~PendingRequest();
-
-  size_t urls_size;
-  blink::mojom::SharedStorageWorkletService::RunURLSelectionOperationCallback
-      callback;
-};
-
-UrlSelectionOperationHandler::PendingRequest::PendingRequest(
-    size_t urls_size,
-    blink::mojom::SharedStorageWorkletService::RunURLSelectionOperationCallback
-        callback)
-    : urls_size(urls_size), callback(std::move(callback)) {}
-
-UrlSelectionOperationHandler::PendingRequest::~PendingRequest() = default;
-
-UrlSelectionOperationHandler::UrlSelectionOperationHandler(
-    const std::map<std::string, v8::Global<v8::Function>>&
-        operation_definition_map)
-    : operation_definition_map_(operation_definition_map) {}
-
-UrlSelectionOperationHandler::~UrlSelectionOperationHandler() = default;
-
-void UrlSelectionOperationHandler::RunOperation(
-    v8::Local<v8::Context> context,
-    const std::string& name,
-    const std::vector<GURL>& urls,
-    const std::vector<uint8_t>& serialized_data,
-    blink::mojom::SharedStorageWorkletService::RunURLSelectionOperationCallback
-        callback) {
-  auto it = operation_definition_map_->find(name);
-  if (it == operation_definition_map_->end()) {
-    std::move(callback).Run(/*success=*/false, "Cannot find operation name.",
-                            /*index=*/0);
-    return;
-  }
-
-  v8::Isolate* isolate = context->GetIsolate();
-
-  v8::Context::Scope context_scope(context);
-
-  v8::Local<v8::Function> run_function = it->second.Get(isolate);
-
-  std::vector<std::string> string_urls;
-  base::ranges::transform(urls, std::back_inserter(string_urls), &GURL::spec);
-
-  v8::Local<v8::Array> js_urls =
-      gin::Converter<std::vector<std::string>>::ToV8(isolate, string_urls)
-          .As<v8::Array>();
-
-  v8::Local<v8::Object> js_data;
-
-  if (serialized_data.empty()) {
-    js_data = v8::Object::New(isolate);
-  } else {
-    v8::ValueDeserializer deserializer(isolate, serialized_data.data(),
-                                       serialized_data.size());
-    v8::Local<v8::Value> value =
-        deserializer.ReadValue(context).ToLocalChecked();
-    js_data = value->ToObject(context).ToLocalChecked();
-  }
-
-  std::vector<v8::Local<v8::Value>> args{js_urls, js_data};
-
-  std::string error_message;
-  v8::MaybeLocal<v8::Value> result = WorkletV8Helper::InvokeFunction(
-      context, run_function, args, &error_message);
-
-  if (result.IsEmpty()) {
-    std::move(callback).Run(
-        /*success=*/false, error_message, /*index=*/0);
-    return;
-  }
-
-  if (!result.ToLocalChecked()->IsPromise()) {
-    std::move(callback).Run(/*success=*/false,
-                            "run() did not return a promise.",
-                            /*index=*/0);
-    return;
-  }
-
-  v8::Local<v8::Promise> result_promise =
-      result.ToLocalChecked().As<v8::Promise>();
-
-  // If the promise is already completed, retrieve and handle the result
-  // directly.
-  if (result_promise->State() == v8::Promise::PromiseState::kFulfilled) {
-    v8::Local<v8::Value> result_value = result_promise->Result();
-
-    uint32_t result_index = 0;
-    if (!ToIDLUnsignedLong(isolate, result_value, result_index)) {
-      std::move(callback).Run(/*success=*/false,
-                              kErrorMessageReturnValueNotUint32,
-                              /*index=*/0);
-      return;
-    }
-
-    if (result_index >= urls.size()) {
-      std::move(callback).Run(
-          /*success=*/false, kErrorMessageReturnValueOutOfRange,
-          /*index=*/0);
-      return;
-    }
-
-    std::move(callback).Run(/*success=*/true,
-                            /*error_message=*/{}, result_index);
-    return;
-  }
-
-  if (result_promise->State() == v8::Promise::PromiseState::kRejected) {
-    error_message = gin::V8ToString(
-        isolate,
-        result_promise->Result()->ToDetailString(context).ToLocalChecked());
-
-    std::move(callback).Run(
-        /*success=*/false, error_message, /*index=*/0);
-    return;
-  }
-
-  // If the promise is pending, install callback functions that will be
-  // triggered when it completes.
-  auto pending_request =
-      std::make_unique<PendingRequest>(urls.size(), std::move(callback));
-  PendingRequest* pending_request_raw = pending_request.get();
-  pending_requests_.emplace(pending_request_raw, std::move(pending_request));
-
-  v8::Local<v8::Function> fulfilled_callback =
-      gin::CreateFunctionTemplate(
-          isolate, base::BindRepeating(
-                       &UrlSelectionOperationHandler::OnPromiseFulfilled,
-                       weak_ptr_factory_.GetWeakPtr(), pending_request_raw))
-          ->GetFunction(context)
-          .ToLocalChecked();
-
-  v8::Local<v8::Function> rejected_callback =
-      gin::CreateFunctionTemplate(
-          isolate, base::BindRepeating(
-                       &UrlSelectionOperationHandler::OnPromiseRejected,
-                       weak_ptr_factory_.GetWeakPtr(), pending_request_raw))
-          ->GetFunction(context)
-          .ToLocalChecked();
-
-  result_promise->Then(context, fulfilled_callback, rejected_callback)
-      .ToLocalChecked();
-}
-
-void UrlSelectionOperationHandler::OnPromiseFulfilled(PendingRequest* request,
-                                                      gin::Arguments* args) {
-  std::vector<v8::Local<v8::Value>> v8_args = args->GetAll();
-
-  uint32_t result_index = 0;
-
-  // We are guaranteed to have a single argument here.
-  CHECK_EQ(v8_args.size(), 1u);
-
-  if (!ToIDLUnsignedLong(args->isolate(), v8_args[0], result_index)) {
-    std::move(request->callback)
-        .Run(/*success=*/false, kErrorMessageReturnValueNotUint32,
-             /*index=*/0);
-    pending_requests_.erase(request);
-    return;
-  }
-
-  if (result_index >= request->urls_size) {
-    std::move(request->callback)
-        .Run(/*success=*/false, kErrorMessageReturnValueOutOfRange,
-             /*index=*/0);
-    pending_requests_.erase(request);
-    return;
-  }
-
-  std::move(request->callback)
-      .Run(/*success=*/true,
-           /*error_message=*/{}, result_index);
-  pending_requests_.erase(request);
-}
-
-void UrlSelectionOperationHandler::OnPromiseRejected(PendingRequest* request,
-                                                     gin::Arguments* args) {
-  std::string error_message;
-  if (!args->GetNext(&error_message)) {
-    std::move(request->callback)
-        .Run(/*success=*/false,
-             "Promise is rejected without an explicit error message.",
-             /*index=*/0);
-    pending_requests_.erase(request);
-    return;
-  }
-
-  std::move(request->callback)
-      .Run(/*success=*/false, error_message, /*index=*/0);
-
-  pending_requests_.erase(request);
-}
-
-}  // namespace shared_storage_worklet
diff --git a/content/services/shared_storage_worklet/url_selection_operation_handler.h b/content/services/shared_storage_worklet/url_selection_operation_handler.h
deleted file mode 100644
index 2e3c0fe..0000000
--- a/content/services/shared_storage_worklet/url_selection_operation_handler.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_SERVICES_SHARED_STORAGE_WORKLET_URL_SELECTION_OPERATION_HANDLER_H_
-#define CONTENT_SERVICES_SHARED_STORAGE_WORKLET_URL_SELECTION_OPERATION_HANDLER_H_
-
-#include <map>
-
-#include "base/memory/raw_ref.h"
-#include "third_party/blink/public/mojom/shared_storage/shared_storage_worklet_service.mojom.h"
-#include "v8/include/v8-forward.h"
-#include "v8/include/v8-persistent-handle.h"
-
-namespace gin {
-class Arguments;
-}  // namespace gin
-
-namespace shared_storage_worklet {
-
-class UrlSelectionOperationHandler {
- public:
-  struct PendingRequest;
-
-  explicit UrlSelectionOperationHandler(
-      const std::map<std::string, v8::Global<v8::Function>>&
-          operation_definition_map);
-
-  ~UrlSelectionOperationHandler();
-
-  void RunOperation(v8::Local<v8::Context> context,
-                    const std::string& name,
-                    const std::vector<GURL>& urls,
-                    const std::vector<uint8_t>& serialized_data,
-                    blink::mojom::SharedStorageWorkletService::
-                        RunURLSelectionOperationCallback callback);
-
-  void OnPromiseFulfilled(PendingRequest* request, gin::Arguments* args);
-
-  void OnPromiseRejected(PendingRequest* request, gin::Arguments* args);
-
- private:
-  const raw_ref<const std::map<std::string, v8::Global<v8::Function>>>
-      operation_definition_map_;
-
-  std::map<PendingRequest*, std::unique_ptr<PendingRequest>> pending_requests_;
-
-  base::WeakPtrFactory<UrlSelectionOperationHandler> weak_ptr_factory_{this};
-};
-
-}  // namespace shared_storage_worklet
-
-#endif  // CONTENT_SERVICES_SHARED_STORAGE_WORKLET_URL_SELECTION_OPERATION_HANDLER_H_
diff --git a/content/services/shared_storage_worklet/worklet_v8_helper.cc b/content/services/shared_storage_worklet/worklet_v8_helper.cc
deleted file mode 100644
index 523e5c9..0000000
--- a/content/services/shared_storage_worklet/worklet_v8_helper.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/services/shared_storage_worklet/worklet_v8_helper.h"
-
-#include "base/strings/strcat.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "v8/include/v8-context.h"
-#include "v8/include/v8-exception.h"
-#include "v8/include/v8-function.h"
-#include "v8/include/v8-message.h"
-#include "v8/include/v8-primitive.h"
-#include "v8/include/v8-script.h"
-
-namespace shared_storage_worklet {
-
-namespace {
-
-std::string FormatValue(v8::Isolate* isolate, v8::Local<v8::Value> val) {
-  if (val.IsEmpty()) {
-    return "\"\"";
-  } else {
-    v8::String::Utf8Value val_utf8(isolate, val);
-    if (*val_utf8 == nullptr)
-      return std::string();
-    return std::string(*val_utf8, val_utf8.length());
-  }
-}
-
-std::string FormatExceptionMessage(v8::Local<v8::Context> context,
-                                   v8::Local<v8::Message> message) {
-  if (message.IsEmpty()) {
-    return "Unknown exception.";
-  } else {
-    v8::Isolate* isolate = message->GetIsolate();
-    int line_num;
-    return base::StrCat(
-        {FormatValue(isolate, message->GetScriptResourceName()),
-         !context.IsEmpty() && message->GetLineNumber(context).To(&line_num)
-             ? std::string(":") + base::NumberToString(line_num)
-             : std::string(),
-         " ", FormatValue(isolate, message->Get()), "."});
-  }
-}
-
-v8::MaybeLocal<v8::String> CreateUtf8String(v8::Isolate* isolate,
-                                            base::StringPiece utf8_string) {
-  if (!base::IsStringUTF8(utf8_string))
-    return v8::MaybeLocal<v8::String>();
-  return v8::String::NewFromUtf8(isolate, utf8_string.data(),
-                                 v8::NewStringType::kNormal,
-                                 utf8_string.length());
-}
-
-}  // namespace
-
-WorkletV8Helper::HandleScope::HandleScope(v8::Isolate* isolate)
-    : isolate_scope_(isolate), handle_scope_(isolate) {}
-
-WorkletV8Helper::HandleScope::~HandleScope() = default;
-
-// static
-v8::MaybeLocal<v8::Value> WorkletV8Helper::InvokeFunction(
-    v8::Local<v8::Context> context,
-    v8::Local<v8::Function> function,
-    base::span<v8::Local<v8::Value>> args,
-    std::string* error_message) {
-  v8::Isolate* isolate = context->GetIsolate();
-
-  v8::TryCatch try_catch(isolate);
-
-  v8::MaybeLocal<v8::Value> func_result =
-      function->Call(context, context->Global(), args.size(), args.data());
-
-  if (func_result.IsEmpty()) {
-    *error_message = FormatExceptionMessage(context, try_catch.Message());
-    return v8::MaybeLocal<v8::Value>();
-  }
-
-  return func_result;
-}
-
-v8::MaybeLocal<v8::Value> WorkletV8Helper::CompileAndRunScript(
-    v8::Local<v8::Context> context,
-    const std::string& src,
-    const GURL& src_url,
-    std::string* error_message) {
-  v8::Isolate* isolate = context->GetIsolate();
-
-  v8::MaybeLocal<v8::String> src_string = CreateUtf8String(isolate, src);
-  if (src_string.IsEmpty()) {
-    *error_message = "Invalid script content.";
-    return {};
-  }
-
-  v8::MaybeLocal<v8::String> origin_string =
-      CreateUtf8String(isolate, src_url.spec());
-  if (origin_string.IsEmpty()) {
-    *error_message = "Invalid script origin.";
-    return {};
-  }
-
-  // Compile script.
-  v8::TryCatch try_catch(isolate);
-  v8::ScriptCompiler::Source script_source(
-      src_string.ToLocalChecked(),
-      v8::ScriptOrigin(isolate, origin_string.ToLocalChecked()));
-  v8::MaybeLocal<v8::Script> maybe_compile_result = v8::ScriptCompiler::Compile(
-      context, &script_source, v8::ScriptCompiler::kNoCompileOptions,
-      v8::ScriptCompiler::NoCacheReason::kNoCacheNoReason);
-
-  v8::Local<v8::Script> compile_result;
-  if (!maybe_compile_result.ToLocal(&compile_result)) {
-    *error_message = FormatExceptionMessage(context, try_catch.Message());
-    return {};
-  }
-
-  v8::Local<v8::Value> run_result;
-  if (!compile_result->Run(context).ToLocal(&run_result)) {
-    *error_message = FormatExceptionMessage(context, try_catch.Message());
-    return {};
-  }
-
-  return run_result;
-}
-
-}  // namespace shared_storage_worklet
diff --git a/content/services/shared_storage_worklet/worklet_v8_helper.h b/content/services/shared_storage_worklet/worklet_v8_helper.h
deleted file mode 100644
index 2577d658..0000000
--- a/content/services/shared_storage_worklet/worklet_v8_helper.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_SERVICES_SHARED_STORAGE_WORKLET_WORKLET_V8_HELPER_H_
-#define CONTENT_SERVICES_SHARED_STORAGE_WORKLET_WORKLET_V8_HELPER_H_
-
-#include <string>
-
-#include "base/containers/span.h"
-#include "content/common/content_export.h"
-#include "url/gurl.h"
-#include "v8/include/v8-forward.h"
-#include "v8/include/v8-isolate.h"
-#include "v8/include/v8-locker.h"
-
-namespace shared_storage_worklet {
-
-class CONTENT_EXPORT WorkletV8Helper {
- public:
-  class CONTENT_EXPORT HandleScope {
-   public:
-    explicit HandleScope(v8::Isolate* isolate);
-    explicit HandleScope(const HandleScope&) = delete;
-    HandleScope& operator=(const HandleScope&) = delete;
-    ~HandleScope();
-
-   private:
-    const v8::Isolate::Scope isolate_scope_;
-    const v8::HandleScope handle_scope_;
-  };
-
-  static v8::MaybeLocal<v8::Value> InvokeFunction(
-      v8::Local<v8::Context> context,
-      v8::Local<v8::Function> function,
-      base::span<v8::Local<v8::Value>> args,
-      std::string* error_message);
-
-  static v8::MaybeLocal<v8::Value> CompileAndRunScript(
-      v8::Local<v8::Context> context,
-      const std::string& src,
-      const GURL& src_url,
-      std::string* error_message);
-};
-
-}  // namespace shared_storage_worklet
-
-#endif  // CONTENT_SERVICES_SHARED_STORAGE_WORKLET_WORKLET_V8_HELPER_H_
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index c55b0a6..d0608cb 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -2676,7 +2676,6 @@
     "../renderer/skia_benchmarking_extension_unittest.cc",
     "../renderer/v8_value_converter_impl_unittest.cc",
     "../renderer/worker/worker_thread_registry_unittest.cc",
-    "../services/shared_storage_worklet/shared_storage_worklet_global_scope_unittest.cc",
     "navigation_simulator_unittest.cc",
     "test_aggregation_service_impl_unittest.cc",
     "test_page_unittest.cc",
@@ -2834,7 +2833,6 @@
     "//content/renderer:for_content_tests",
     "//content/services/auction_worklet:tests",
     "//content/services/auction_worklet/public/mojom:for_content_tests",
-    "//content/services/shared_storage_worklet:for_content_tests",
     "//crypto",
     "//device/bluetooth",
     "//device/bluetooth:mocks",
diff --git a/content/test/data/service_worker/race_network_request.js b/content/test/data/service_worker/race_network_request.js
index 57a8790..07d68d2 100644
--- a/content/test/data/service_worker/race_network_request.js
+++ b/content/test/data/service_worker/race_network_request.js
@@ -1,54 +1,51 @@
 // Copyright 2023 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-const OFFLINE_URL = 'race_network_request_from_fetch_handler.html'
-const CACHE_NAME = 'race_network_request';
+const composeCustomResponse = () => {
+  const headers = new Headers();
+  headers.append('Content-Type', 'text/html');
+  headers.append('X-Response-From', 'fetch-handler');
+  const options = {
+    status: 200,
+    statusText: 'Custom response from fetch handler',
+    headers
+  };
+
+  return new Response(
+      '[ServiceWorkerRaceNetworkRequest] Response from the fetch handler',
+      options);
+};
 
 self.addEventListener('install', e => {
-  e.waitUntil(
-    (async () => {
-      const cache = await caches.open(CACHE_NAME);
-      const response = await fetch(OFFLINE_URL);
-
-      const customHeaders = new Headers(response.headers);
-      customHeaders.append('X-Response-From', 'fetch-handler');
-
-      await cache.put(OFFLINE_URL, new Response(response.body, {
-                        status: response.status,
-                        statusText: response.statusText,
-                        headers: customHeaders
-                      }));
-    })()
-  );
   self.skipWaiting();
 });
 
-self.addEventListener("activate", () => {
-  self.clients.claim();
+self.addEventListener('activate', e => {
+  e.waitUntil(clients.claim());
 });
 
 self.addEventListener("fetch", async e => {
   const {request} = e;
   const url = new URL(request.url);
 
-  // Force fallback
-  if (url.search.includes('fallback')) {
-    return;
-  }
-
-  // Force timeout
+  // Force slow response
   let timeout = Promise.resolve();
-  if (request.mode == 'navigate' && url.search.includes('timeout')) {
+  if (url.search.includes('sw_slow')) {
     timeout = new Promise(resolve => setTimeout(resolve, 1500));
   }
 
+  // Force fallback
+  if (url.search.includes('sw_fallback')) {
+    await timeout;
+    return;
+  }
+
   // Force respond from the cache
-  if (url.search.includes('respond_from_fetch_handler')) {
+  if (url.search.includes('sw_respond')) {
     e.respondWith(
       (async () => {
         await timeout;
-        const cache = await caches.open(CACHE_NAME);
-        return await cache.match(OFFLINE_URL);
+        return composeCustomResponse();
       })()
     );
   }
diff --git a/content/test/gpu/gpu_tests/trace_integration_test.py b/content/test/gpu/gpu_tests/trace_integration_test.py
index 71306a3..641eea3 100644
--- a/content/test/gpu/gpu_tests/trace_integration_test.py
+++ b/content/test/gpu/gpu_tests/trace_integration_test.py
@@ -109,9 +109,7 @@
 
 _GET_STATISTICS_EVENT_NAME = 'GetFrameStatisticsMedia'
 _SWAP_CHAIN_PRESENT_EVENT_NAME = 'SwapChain::Present'
-_PRESENT_TO_SWAP_CHAIN_EVENT_NAME = 'SwapChainPresenter::PresentToSwapChain'
-_PRESENT_ROOT_SWAP_CHAIN_EVENT_NAME =\
-    'DirectCompositionChildSurfaceWin::PresentSwapChain'
+_UPDATE_OVERLAY_EVENT_NAME = 'DCLayerTree::VisualTree::UpdateOverlay'
 
 _SUPPORTED_WIN_AMD_GPUS_WITH_NV12_ROTATED_OVERLAYS = [0x7340]
 
@@ -881,7 +879,7 @@
     for event in event_iterator:
       if event.category != category:
         continue
-      if event.name != _PRESENT_TO_SWAP_CHAIN_EVENT_NAME:
+      if event.name != _UPDATE_OVERLAY_EVENT_NAME:
         continue
       image_type = event.args.get('image_type', None)
       if image_type == 'DCompVisualContent':
@@ -890,11 +888,11 @@
     if expect_overlay and not found_overlay:
       self.fail(
           'Overlay expected but not found: matching %s events were not found' %
-          _PRESENT_TO_SWAP_CHAIN_EVENT_NAME)
+          _UPDATE_OVERLAY_EVENT_NAME)
     elif expect_no_overlay and found_overlay:
       self.fail(
           'Overlay not expected but found: matching %s events were found' %
-          _PRESENT_TO_SWAP_CHAIN_EVENT_NAME)
+          _UPDATE_OVERLAY_EVENT_NAME)
 
   def _EvaluateSuccess_CheckWebGLCanvasCapture(self, category: str,
                                                event_iterator: Iterator,
diff --git a/content/utility/BUILD.gn b/content/utility/BUILD.gn
index aa80caf..a717b924 100644
--- a/content/utility/BUILD.gn
+++ b/content/utility/BUILD.gn
@@ -51,7 +51,6 @@
     "//content/public/common:common_sources",
     "//content/public/common:content_descriptor_keys",
     "//content/services/auction_worklet",
-    "//content/services/shared_storage_worklet",
     "//device/vr/buildflags",
     "//media:media_buildflags",
     "//mojo/public/cpp/bindings",
diff --git a/extensions/common/api/storage.json b/extensions/common/api/storage.json
index 9ed0be0..5d450db 100644
--- a/extensions/common/api/storage.json
+++ b/extensions/common/api/storage.json
@@ -253,7 +253,7 @@
         "value": [ "local" ],
         "properties": {
           "QUOTA_BYTES": {
-            "value": 5242880,
+            "value": 10485760,
             "description": "The maximum amount (in bytes) of data that can be stored in local storage, as measured by the JSON stringification of every value plus every key's length. This value will be ignored if the extension has the <code>unlimitedStorage</code> permission. Updates that would cause this limit to be exceeded fail immediately and set $(ref:runtime.lastError)."
           }
         }
diff --git a/extensions/common/constants.h b/extensions/common/constants.h
index 284cc87..ad65e1f 100644
--- a/extensions/common/constants.h
+++ b/extensions/common/constants.h
@@ -298,9 +298,6 @@
 // The extension id of the Google Keep application.
 EXTENSIONS_EXPORT extern const char kGoogleKeepAppId[];
 
-// The extension id of the office PWA.
-EXTENSIONS_EXPORT extern const char kOfficePwaAppId[];
-
 // The extension id of the Youtube application.
 EXTENSIONS_EXPORT extern const char kYoutubeAppId[];
 
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index e8c7fd76..7bbd7cb 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -652,6 +652,10 @@
     sources += [ "command_buffer/service/gpu_fence_manager_unittest.cc" ]
   }
 
+  if (is_mac) {
+    sources += [ "ipc/service/built_in_shader_cache_unittest.cc" ]
+  }
+
   # On official builds angle doesn't build null backend that is required for
   # unit tests. We don't check directly for angle_enable_null to avoid
   # accidental skipping all the tests if angle logic to build null backend will
diff --git a/gpu/command_buffer/client/buffer_tracker_unittest.cc b/gpu/command_buffer/client/buffer_tracker_unittest.cc
index dee24d9c..2c05760 100644
--- a/gpu/command_buffer/client/buffer_tracker_unittest.cc
+++ b/gpu/command_buffer/client/buffer_tracker_unittest.cc
@@ -33,14 +33,13 @@
   scoped_refptr<gpu::Buffer> CreateTransferBuffer(
       uint32_t size,
       int32_t* id,
-      uint32_t alignment = 0,
       TransferBufferAllocationOption option =
           TransferBufferAllocationOption::kLoseContextOnOOM) override {
     if (context_lost_) {
       *id = -1;
       return nullptr;
     }
-    return MockClientCommandBuffer::CreateTransferBuffer(size, id, alignment);
+    return MockClientCommandBuffer::CreateTransferBuffer(size, id);
   }
 
   void set_context_lost(bool context_lost) {
diff --git a/gpu/command_buffer/client/client_discardable_manager_unittest.cc b/gpu/command_buffer/client/client_discardable_manager_unittest.cc
index 4f2fa68d..1ab2e01 100644
--- a/gpu/command_buffer/client/client_discardable_manager_unittest.cc
+++ b/gpu/command_buffer/client/client_discardable_manager_unittest.cc
@@ -34,12 +34,11 @@
   scoped_refptr<gpu::Buffer> CreateTransferBuffer(
       uint32_t size,
       int32_t* id,
-      uint32_t alignment = 0,
       TransferBufferAllocationOption option =
           TransferBufferAllocationOption::kLoseContextOnOOM) override {
     *id = next_id_++;
     active_ids_.insert(*id);
-    return MakeMemoryBuffer(size, alignment);
+    return MakeMemoryBuffer(size);
   }
   void DestroyTransferBuffer(int32_t id) override {
     auto found = active_ids_.find(id);
diff --git a/gpu/command_buffer/client/client_test_helper.cc b/gpu/command_buffer/client/client_test_helper.cc
index f21ec2d..be91ffa 100644
--- a/gpu/command_buffer/client/client_test_helper.cc
+++ b/gpu/command_buffer/client/client_test_helper.cc
@@ -137,7 +137,6 @@
 scoped_refptr<gpu::Buffer> MockClientCommandBuffer::CreateTransferBuffer(
     uint32_t size,
     int32_t* id,
-    uint32_t alignment,
     TransferBufferAllocationOption option) {
   return CreateTransferBufferHelper(size, id);
 }
diff --git a/gpu/command_buffer/client/client_test_helper.h b/gpu/command_buffer/client/client_test_helper.h
index 5399b36..a7464d5 100644
--- a/gpu/command_buffer/client/client_test_helper.h
+++ b/gpu/command_buffer/client/client_test_helper.h
@@ -69,7 +69,6 @@
   scoped_refptr<gpu::Buffer> CreateTransferBuffer(
       uint32_t size,
       int32_t* id,
-      uint32_t alignment = 0,
       TransferBufferAllocationOption option =
           TransferBufferAllocationOption::kLoseContextOnOOM) override;
 
diff --git a/gpu/command_buffer/client/command_buffer_direct_locked.cc b/gpu/command_buffer/client/command_buffer_direct_locked.cc
index 5cb71b2..04de60d 100644
--- a/gpu/command_buffer/client/command_buffer_direct_locked.cc
+++ b/gpu/command_buffer/client/command_buffer_direct_locked.cc
@@ -44,14 +44,12 @@
 scoped_refptr<Buffer> CommandBufferDirectLocked::CreateTransferBuffer(
     uint32_t size,
     int32_t* id,
-    uint32_t alignment,
     TransferBufferAllocationOption option) {
   if (fail_create_transfer_buffer_) {
     *id = -1;
     return nullptr;
   } else {
-    return CommandBufferDirect::CreateTransferBuffer(size, id, alignment,
-                                                     option);
+    return CommandBufferDirect::CreateTransferBuffer(size, id, option);
   }
 }
 
diff --git a/gpu/command_buffer/client/command_buffer_direct_locked.h b/gpu/command_buffer/client/command_buffer_direct_locked.h
index a4c1bbf..4195797 100644
--- a/gpu/command_buffer/client/command_buffer_direct_locked.h
+++ b/gpu/command_buffer/client/command_buffer_direct_locked.h
@@ -30,7 +30,6 @@
   scoped_refptr<Buffer> CreateTransferBuffer(
       uint32_t size,
       int32_t* id,
-      uint32_t alignment = 0,
       TransferBufferAllocationOption option =
           TransferBufferAllocationOption::kLoseContextOnOOM) override;
 
diff --git a/gpu/command_buffer/client/mapped_memory.cc b/gpu/command_buffer/client/mapped_memory.cc
index b4b3572..8acb49e 100644
--- a/gpu/command_buffer/client/mapped_memory.cc
+++ b/gpu/command_buffer/client/mapped_memory.cc
@@ -112,8 +112,8 @@
     return nullptr;
 
   int32_t id = -1;
-  scoped_refptr<gpu::Buffer> shm = cmd_buf->CreateTransferBuffer(
-      safe_chunk_size, &id, /* alignment */ 0, option);
+  scoped_refptr<gpu::Buffer> shm =
+      cmd_buf->CreateTransferBuffer(safe_chunk_size, &id, option);
   if (id  < 0)
     return nullptr;
   DCHECK(shm.get());
diff --git a/gpu/command_buffer/client/transfer_buffer.cc b/gpu/command_buffer/client/transfer_buffer.cc
index 81a3848..698da14 100644
--- a/gpu/command_buffer/client/transfer_buffer.cc
+++ b/gpu/command_buffer/client/transfer_buffer.cc
@@ -119,7 +119,7 @@
   for (;size >= min_buffer_size_; size /= 2) {
     int32_t id = -1;
     scoped_refptr<gpu::Buffer> buffer =
-        helper_->command_buffer()->CreateTransferBuffer(size, &id, alignment_);
+        helper_->command_buffer()->CreateTransferBuffer(size, &id);
     if (id != -1) {
       last_allocated_size_ = size;
       DCHECK(buffer.get());
diff --git a/gpu/command_buffer/client/transfer_buffer_unittest.cc b/gpu/command_buffer/client/transfer_buffer_unittest.cc
index f9b70370..6781aa8 100644
--- a/gpu/command_buffer/client/transfer_buffer_unittest.cc
+++ b/gpu/command_buffer/client/transfer_buffer_unittest.cc
@@ -230,19 +230,17 @@
   MockClientCommandBufferCanFail() = default;
   ~MockClientCommandBufferCanFail() override = default;
 
-  MOCK_METHOD4(CreateTransferBuffer,
+  MOCK_METHOD3(CreateTransferBuffer,
                scoped_refptr<Buffer>(uint32_t size,
                                      int32_t* id,
-                                     uint32_t alignment,
                                      TransferBufferAllocationOption option));
 
   scoped_refptr<gpu::Buffer> RealCreateTransferBuffer(
       uint32_t size,
       int32_t* id,
-      uint32_t alignment,
       TransferBufferAllocationOption option) {
-    return MockClientCommandBufferMockFlush::CreateTransferBuffer(
-        size, id, alignment, option);
+    return MockClientCommandBufferMockFlush::CreateTransferBuffer(size, id,
+                                                                  option);
   }
 };
 
@@ -280,7 +278,7 @@
   command_buffer_->SetTokenForSetGetBuffer(0);
 
   EXPECT_CALL(*command_buffer(),
-              CreateTransferBuffer(kCommandBufferSizeBytes, _, _, _))
+              CreateTransferBuffer(kCommandBufferSizeBytes, _, _))
       .WillOnce(
           Invoke(command_buffer(),
                  &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
@@ -293,7 +291,7 @@
   transfer_buffer_id_ = command_buffer()->GetNextFreeTransferBufferId();
 
   EXPECT_CALL(*command_buffer(),
-              CreateTransferBuffer(kStartTransferBufferSize, _, _, _))
+              CreateTransferBuffer(kStartTransferBufferSize, _, _))
       .WillOnce(
           Invoke(command_buffer(),
                  &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
@@ -344,7 +342,7 @@
     EXPECT_CALL(*command_buffer(), OrderingBarrier(_))
         .Times(1)
         .RetiresOnSaturation();
-    EXPECT_CALL(*command_buffer(), CreateTransferBuffer(size, _, _, _))
+    EXPECT_CALL(*command_buffer(), CreateTransferBuffer(size, _, _))
         .WillOnce(
             Invoke(command_buffer(),
                    &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
@@ -441,7 +439,7 @@
     EXPECT_CALL(*command_buffer(), OrderingBarrier(_))
         .Times(1)
         .RetiresOnSaturation();
-    EXPECT_CALL(*command_buffer(), CreateTransferBuffer(size, _, _, _))
+    EXPECT_CALL(*command_buffer(), CreateTransferBuffer(size, _, _))
         .WillOnce(
             Invoke(command_buffer(),
                    &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
@@ -491,7 +489,7 @@
     EXPECT_CALL(*command_buffer(), OrderingBarrier(_))
         .Times(1)
         .RetiresOnSaturation();
-    EXPECT_CALL(*command_buffer(), CreateTransferBuffer(size, _, _, _))
+    EXPECT_CALL(*command_buffer(), CreateTransferBuffer(size, _, _))
         .WillOnce(
             Invoke(command_buffer(),
                    &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
@@ -539,12 +537,12 @@
 
   // Try to allocate again, fail first request
   EXPECT_CALL(*command_buffer(),
-              CreateTransferBuffer(kStartTransferBufferSize, _, _, _))
+              CreateTransferBuffer(kStartTransferBufferSize, _, _))
       .WillOnce(
           DoAll(SetArgPointee<1>(-1), Return(scoped_refptr<gpu::Buffer>())))
       .RetiresOnSaturation();
   EXPECT_CALL(*command_buffer(),
-              CreateTransferBuffer(kMinTransferBufferSize, _, _, _))
+              CreateTransferBuffer(kMinTransferBufferSize, _, _))
       .WillOnce(
           Invoke(command_buffer(),
                  &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
@@ -572,7 +570,7 @@
 
   // Try to allocate again,
   EXPECT_CALL(*command_buffer(),
-              CreateTransferBuffer(kMinTransferBufferSize, _, _, _))
+              CreateTransferBuffer(kMinTransferBufferSize, _, _))
       .WillOnce(
           Invoke(command_buffer(),
                  &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
@@ -598,7 +596,7 @@
   EXPECT_FALSE(transfer_buffer_->HaveBuffer());
 
   // Try to allocate again, fail both requests.
-  EXPECT_CALL(*command_buffer(), CreateTransferBuffer(_, _, _, _))
+  EXPECT_CALL(*command_buffer(), CreateTransferBuffer(_, _, _))
       .WillOnce(
           DoAll(SetArgPointee<1>(-1), Return(scoped_refptr<gpu::Buffer>())))
       .WillOnce(
@@ -628,7 +626,7 @@
 
   // See that it gets reallocated.
   EXPECT_CALL(*command_buffer(),
-              CreateTransferBuffer(kStartTransferBufferSize, _, _, _))
+              CreateTransferBuffer(kStartTransferBufferSize, _, _))
       .WillOnce(
           Invoke(command_buffer(),
                  &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
diff --git a/gpu/command_buffer/common/buffer.cc b/gpu/command_buffer/common/buffer.cc
index a99be70..d3d5ac8 100644
--- a/gpu/command_buffer/common/buffer.cc
+++ b/gpu/command_buffer/common/buffer.cc
@@ -9,7 +9,6 @@
 #include <ostream>
 
 #include "base/atomic_sequence_num.h"
-#include "base/bits.h"
 #include "base/check_op.h"
 #include "base/format_macros.h"
 #include "base/no_destructor.h"
@@ -35,14 +34,13 @@
   return base::UnguessableToken();
 }
 
-MemoryBufferBacking::MemoryBufferBacking(uint32_t size, uint32_t alignment)
-    : memory_(new char[size + alignment]), size_(size), alignment_(alignment) {}
+MemoryBufferBacking::MemoryBufferBacking(uint32_t size)
+    : memory_(new char[size]), size_(size) {}
 
 MemoryBufferBacking::~MemoryBufferBacking() = default;
 
 void* MemoryBufferBacking::GetMemory() const {
-  return alignment_ > 0 ? base::bits::AlignUp(memory_.get(), alignment_)
-                        : memory_.get();
+  return memory_.get();
 }
 
 uint32_t MemoryBufferBacking::GetSize() const {
diff --git a/gpu/command_buffer/common/buffer.h b/gpu/command_buffer/common/buffer.h
index 28e47ee..b441738 100644
--- a/gpu/command_buffer/common/buffer.h
+++ b/gpu/command_buffer/common/buffer.h
@@ -29,7 +29,7 @@
 
 class GPU_EXPORT MemoryBufferBacking : public BufferBacking {
  public:
-  explicit MemoryBufferBacking(uint32_t size, uint32_t alignment = 0);
+  explicit MemoryBufferBacking(uint32_t size);
 
   MemoryBufferBacking(const MemoryBufferBacking&) = delete;
   MemoryBufferBacking& operator=(const MemoryBufferBacking&) = delete;
@@ -41,7 +41,6 @@
  private:
   std::unique_ptr<char[]> memory_;
   uint32_t size_;
-  uint32_t alignment_;
 };
 
 
@@ -109,10 +108,9 @@
       std::move(shared_memory_region), std::move(shared_memory_mapping)));
 }
 
-inline scoped_refptr<Buffer> MakeMemoryBuffer(uint32_t size,
-                                              uint32_t alignment = 0) {
+inline scoped_refptr<Buffer> MakeMemoryBuffer(uint32_t size) {
   return base::MakeRefCounted<Buffer>(
-      std::make_unique<MemoryBufferBacking>(size, alignment));
+      std::make_unique<MemoryBufferBacking>(size));
 }
 
 // Generates a process unique buffer ID which can be safely used with
diff --git a/gpu/command_buffer/common/command_buffer.h b/gpu/command_buffer/common/command_buffer.h
index 5cc7983..40acc174 100644
--- a/gpu/command_buffer/common/command_buffer.h
+++ b/gpu/command_buffer/common/command_buffer.h
@@ -119,7 +119,6 @@
   virtual scoped_refptr<gpu::Buffer> CreateTransferBuffer(
       uint32_t size,
       int32_t* id,
-      uint32_t alignment = 0,
       TransferBufferAllocationOption option =
           TransferBufferAllocationOption::kLoseContextOnOOM) = 0;
 
diff --git a/gpu/command_buffer/service/command_buffer_direct.cc b/gpu/command_buffer/service/command_buffer_direct.cc
index 4a46a88..13ad519 100644
--- a/gpu/command_buffer/service/command_buffer_direct.cc
+++ b/gpu/command_buffer/service/command_buffer_direct.cc
@@ -55,9 +55,8 @@
 scoped_refptr<Buffer> CommandBufferDirect::CreateTransferBuffer(
     uint32_t size,
     int32_t* id,
-    uint32_t alignment,
     TransferBufferAllocationOption option) {
-  return service_.CreateTransferBuffer(size, id, alignment);
+  return service_.CreateTransferBuffer(size, id);
 }
 
 void CommandBufferDirect::DestroyTransferBuffer(int32_t id) {
diff --git a/gpu/command_buffer/service/command_buffer_direct.h b/gpu/command_buffer/service/command_buffer_direct.h
index 6fa3e7f4..7483bd85 100644
--- a/gpu/command_buffer/service/command_buffer_direct.h
+++ b/gpu/command_buffer/service/command_buffer_direct.h
@@ -38,7 +38,6 @@
   scoped_refptr<Buffer> CreateTransferBuffer(
       uint32_t size,
       int32_t* id,
-      uint32_t alignment = 0,
       TransferBufferAllocationOption option =
           TransferBufferAllocationOption::kLoseContextOnOOM) override;
   void DestroyTransferBuffer(int32_t id) override;
diff --git a/gpu/command_buffer/service/command_buffer_service.cc b/gpu/command_buffer/service/command_buffer_service.cc
index 7368f3e..be460adc 100644
--- a/gpu/command_buffer/service/command_buffer_service.cc
+++ b/gpu/command_buffer/service/command_buffer_service.cc
@@ -309,15 +309,12 @@
   UpdateState();
 }
 
-scoped_refptr<Buffer> CommandBufferService::CreateTransferBuffer(
-    uint32_t size,
-    int32_t* id,
-    uint32_t alignment) {
+scoped_refptr<Buffer> CommandBufferService::CreateTransferBuffer(uint32_t size,
+                                                                 int32_t* id) {
   *id = GetNextBufferId();
-  auto result = CreateTransferBufferWithId(size, *id, alignment);
-  if (!result) {
+  auto result = CreateTransferBufferWithId(size, *id);
+  if (!result)
     *id = -1;
-  }
   return result;
 }
 
@@ -338,9 +335,8 @@
 
 scoped_refptr<Buffer> CommandBufferService::CreateTransferBufferWithId(
     uint32_t size,
-    int32_t id,
-    uint32_t alignment) {
-  scoped_refptr<Buffer> buffer = MakeMemoryBuffer(size, alignment);
+    int32_t id) {
+  scoped_refptr<Buffer> buffer = MakeMemoryBuffer(size);
   if (!RegisterTransferBuffer(id, buffer)) {
     SetParseError(gpu::error::kOutOfBounds);
     return nullptr;
diff --git a/gpu/command_buffer/service/command_buffer_service.h b/gpu/command_buffer/service/command_buffer_service.h
index 4c6ca4af..557a168 100644
--- a/gpu/command_buffer/service/command_buffer_service.h
+++ b/gpu/command_buffer/service/command_buffer_service.h
@@ -112,14 +112,10 @@
 
   // Creates an in-process transfer buffer and register it with a newly created
   // id.
-  scoped_refptr<Buffer> CreateTransferBuffer(uint32_t size,
-                                             int32_t* id,
-                                             uint32_t alignment = 0);
+  scoped_refptr<Buffer> CreateTransferBuffer(uint32_t size, int32_t* id);
 
   // Creates an in-process transfer buffer and register it with a given id.
-  scoped_refptr<Buffer> CreateTransferBufferWithId(uint32_t size,
-                                                   int32_t id,
-                                                   uint32_t alignment = 0);
+  scoped_refptr<Buffer> CreateTransferBufferWithId(uint32_t size, int32_t id);
 
   // Sets whether commands should be processed by this scheduler. Setting to
   // false unschedules. Setting to true reschedules.
diff --git a/gpu/command_buffer/service/passthrough_program_cache.cc b/gpu/command_buffer/service/passthrough_program_cache.cc
index dde084a..e175f4b 100644
--- a/gpu/command_buffer/service/passthrough_program_cache.cc
+++ b/gpu/command_buffer/service/passthrough_program_cache.cc
@@ -37,11 +37,13 @@
 
 PassthroughProgramCache::PassthroughProgramCache(
     size_t max_cache_size_bytes,
-    bool disable_gpu_shader_disk_cache)
+    bool disable_gpu_shader_disk_cache,
+    ValueAddedHook* value_added_hook)
     : ProgramCache(max_cache_size_bytes),
       disable_gpu_shader_disk_cache_(disable_gpu_shader_disk_cache),
       curr_size_bytes_(0),
-      store_(ProgramLRUCache::NO_AUTO_EVICT) {
+      store_(ProgramLRUCache::NO_AUTO_EVICT),
+      value_added_hook_(value_added_hook) {
 #if defined(USE_EGL)
   gl::GLDisplayEGL* gl_display = gl::GLSurfaceEGL::GetGLDisplayEGL();
   EGLDisplay egl_display = gl_display->GetDisplay();
@@ -151,7 +153,7 @@
   {
     base::AutoLock auto_lock(lock_);
     // If callback is set, notify that there was a new/updated blob entry so it
-    // can be soted in disk.  Note that this is done before the Put() call as
+    // can be stored in disk.  Note that this is done before the Put() call as
     // that consumes `value`.
     if (cache_program_callback_) {
       // Convert the key and binary to string form.
@@ -166,6 +168,10 @@
       cache_program_callback_.Run(key_string_64, value_string_64);
     }
 
+    if (value_added_hook_) {
+      value_added_hook_->OnValueAddedToCache(key, value);
+    }
+
     store_.Put(key, ProgramCacheValue(std::move(value), this));
   }
 }
diff --git a/gpu/command_buffer/service/passthrough_program_cache.h b/gpu/command_buffer/service/passthrough_program_cache.h
index b5c9a21..d47a196 100644
--- a/gpu/command_buffer/service/passthrough_program_cache.h
+++ b/gpu/command_buffer/service/passthrough_program_cache.h
@@ -7,6 +7,7 @@
 
 #include <mutex>
 #include "base/containers/lru_cache.h"
+#include "base/memory/raw_ptr.h"
 #include "base/memory/raw_ptr_exclusion.h"
 #include "gpu/command_buffer/service/decoder_context.h"
 #include "gpu/command_buffer/service/program_cache.h"
@@ -21,8 +22,21 @@
 // implementation via the blob cache extension.
 class GPU_GLES2_EXPORT PassthroughProgramCache : public ProgramCache {
  public:
+  using Key = std::vector<uint8_t>;
+  using Value = std::vector<uint8_t>;
+
+  // Notified everytime an entry is added to the cache.
+  class GPU_GLES2_EXPORT ValueAddedHook {
+   public:
+    virtual void OnValueAddedToCache(const Key& key, const Value& value) = 0;
+
+   protected:
+    virtual ~ValueAddedHook() = default;
+  };
+
   PassthroughProgramCache(size_t max_cache_size_bytes,
-                          bool disable_gpu_shader_disk_cache);
+                          bool disable_gpu_shader_disk_cache,
+                          ValueAddedHook* value_added_hook = nullptr);
 
   PassthroughProgramCache(const PassthroughProgramCache&) = delete;
   PassthroughProgramCache& operator=(const PassthroughProgramCache&) = delete;
@@ -60,10 +74,9 @@
                                       void* value,
                                       EGLsizeiANDROID value_size);
 
- private:
-  typedef std::vector<uint8_t> Key;
-  typedef std::vector<uint8_t> Value;
+  void Set(Key&& key, Value&& value);
 
+ private:
   class ProgramCacheValue {
    public:
     ProgramCacheValue(Value&& program_blob,
@@ -91,7 +104,6 @@
   void ClearBackend() override;
   bool CacheEnabled() const;
 
-  void Set(Key&& key, Value&& value);
   const ProgramCacheValue* Get(const Key& key);
 
   friend class ProgramCacheValue;
@@ -101,6 +113,7 @@
   const bool disable_gpu_shader_disk_cache_;
   size_t curr_size_bytes_;
   ProgramLRUCache store_ GUARDED_BY(lock_);
+  raw_ptr<ValueAddedHook> value_added_hook_;
 
   // TODO(syoussefi): take compression from memory_program_cache, see
   // compress_program_binaries_
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.cc b/gpu/ipc/client/command_buffer_proxy_impl.cc
index ab04701b..8469e93 100644
--- a/gpu/ipc/client/command_buffer_proxy_impl.cc
+++ b/gpu/ipc/client/command_buffer_proxy_impl.cc
@@ -342,7 +342,6 @@
 scoped_refptr<gpu::Buffer> CommandBufferProxyImpl::CreateTransferBuffer(
     uint32_t size,
     int32_t* id,
-    uint32_t alignment,
     TransferBufferAllocationOption option) {
   CheckLock();
   base::AutoLock lock(last_state_lock_);
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.h b/gpu/ipc/client/command_buffer_proxy_impl.h
index 18859f8..c4bedde 100644
--- a/gpu/ipc/client/command_buffer_proxy_impl.h
+++ b/gpu/ipc/client/command_buffer_proxy_impl.h
@@ -118,7 +118,6 @@
   scoped_refptr<gpu::Buffer> CreateTransferBuffer(
       uint32_t size,
       int32_t* id,
-      uint32_t alignment = 0,
       TransferBufferAllocationOption option =
           TransferBufferAllocationOption::kLoseContextOnOOM) override;
   void DestroyTransferBuffer(int32_t id) override;
diff --git a/gpu/ipc/client/command_buffer_proxy_impl_unittest.cc b/gpu/ipc/client/command_buffer_proxy_impl_unittest.cc
index 16d78ff..8f01de6 100644
--- a/gpu/ipc/client/command_buffer_proxy_impl_unittest.cc
+++ b/gpu/ipc/client/command_buffer_proxy_impl_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "gpu/ipc/client/command_buffer_proxy_impl.h"
 
-#include <limits>
 #include <utility>
 #include <vector>
 
@@ -291,7 +290,7 @@
 
   int32_t id = -1;
   scoped_refptr<gpu::Buffer> transfer_buffer_oom = proxy->CreateTransferBuffer(
-      std::numeric_limits<uint32_t>::max(), &id, 0,
+      std::numeric_limits<uint32_t>::max(), &id,
       TransferBufferAllocationOption::kReturnNullOnOOM);
   if (transfer_buffer_oom) {
     // In this test, there's no guarantee allocating UINT32_MAX will definitely
@@ -316,7 +315,7 @@
       .RetiresOnSaturation();
 
   transfer_buffer_oom = proxy->CreateTransferBuffer(
-      std::numeric_limits<uint32_t>::max(), &id, 0,
+      std::numeric_limits<uint32_t>::max(), &id,
       TransferBufferAllocationOption::kLoseContextOnOOM);
 
   EXPECT_CALL(mock_gpu_channel_, DestroyCommandBuffer(_))
diff --git a/gpu/ipc/host/gpu_disk_cache.cc b/gpu/ipc/host/gpu_disk_cache.cc
index ad1088af..ad9a08b 100644
--- a/gpu/ipc/host/gpu_disk_cache.cc
+++ b/gpu/ipc/host/gpu_disk_cache.cc
@@ -638,8 +638,8 @@
 
   auto shim = std::make_unique<GpuDiskCacheEntry>(this, key, blob);
   shim->Cache();
-  auto* raw_ptr = shim.get();
-  entries_.insert(std::make_pair(raw_ptr, std::move(shim)));
+  auto* ptr = shim.get();
+  entries_.insert(std::make_pair(ptr, std::move(shim)));
 }
 
 int GpuDiskCache::Clear(base::Time begin_time,
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index b459188b..7cc29133 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -747,9 +747,8 @@
 scoped_refptr<Buffer> InProcessCommandBuffer::CreateTransferBuffer(
     uint32_t size,
     int32_t* id,
-    uint32_t alignment,
     TransferBufferAllocationOption option) {
-  scoped_refptr<Buffer> buffer = MakeMemoryBuffer(size, alignment);
+  scoped_refptr<Buffer> buffer = MakeMemoryBuffer(size);
   *id = GetNextBufferId();
   ScheduleGpuTask(
       base::BindOnce(&InProcessCommandBuffer::RegisterTransferBufferOnGpuThread,
diff --git a/gpu/ipc/in_process_command_buffer.h b/gpu/ipc/in_process_command_buffer.h
index 47e677c..774a235 100644
--- a/gpu/ipc/in_process_command_buffer.h
+++ b/gpu/ipc/in_process_command_buffer.h
@@ -117,7 +117,6 @@
   scoped_refptr<Buffer> CreateTransferBuffer(
       uint32_t size,
       int32_t* id,
-      uint32_t alignment = 0,
       TransferBufferAllocationOption option =
           TransferBufferAllocationOption::kLoseContextOnOOM) override;
   void DestroyTransferBuffer(int32_t id) override;
diff --git a/gpu/ipc/service/BUILD.gn b/gpu/ipc/service/BUILD.gn
index 89e0e91..f52c3b6 100644
--- a/gpu/ipc/service/BUILD.gn
+++ b/gpu/ipc/service/BUILD.gn
@@ -104,6 +104,10 @@
   }
   if (is_mac) {
     sources += [
+      "built_in_shader_cache_loader.cc",
+      "built_in_shader_cache_loader.h",
+      "built_in_shader_cache_writer.cc",
+      "built_in_shader_cache_writer.h",
       "gpu_memory_buffer_factory_io_surface.cc",
       "gpu_memory_buffer_factory_io_surface.h",
       "image_transport_surface_mac.mm",
diff --git a/gpu/ipc/service/built_in_shader_cache_loader.cc b/gpu/ipc/service/built_in_shader_cache_loader.cc
new file mode 100644
index 0000000..b0b87703
--- /dev/null
+++ b/gpu/ipc/service/built_in_shader_cache_loader.cc
@@ -0,0 +1,193 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/ipc/service/built_in_shader_cache_loader.h"
+
+#include "base/files/file.h"
+#include "base/functional/bind.h"
+#include "base/mac/foundation_util.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/task/thread_pool.h"
+#include "base/time/time.h"
+#include "gpu/ipc/service/built_in_shader_cache_writer.h"
+
+namespace gpu {
+
+namespace {
+
+// File the shaders are put in.
+const char kShaderCacheFileName[] = "gpu_shader_cache.bin";
+
+// A single instance is created. It is destroyed once the values are taken.
+static BuiltInShaderCacheLoader* g_loader = nullptr;
+
+// Responsible for reading the shader file.
+class FileReader {
+ public:
+  bool Init(const base::FilePath& path) {
+    file_.Initialize(AdjustPath(path),
+                     base::File::FLAG_OPEN | base::File::FLAG_READ);
+    if (!file_.IsValid()) {
+      LOG(WARNING) << "Failed opening metal shader cache";
+      return false;
+    }
+    return ReadHeader();
+  }
+
+  bool ReadHeader() {
+    uint32_t header;
+    if (!ReadBytes(sizeof(header), reinterpret_cast<char*>(&header))) {
+      return false;
+    }
+    return header == BuiltInShaderCacheWriter::kSignature;
+  }
+
+  bool ReadKeyOrValue(std::vector<uint8_t>& data) {
+    // uint32_t corresponds to how the data is written. See writer for details.
+    uint32_t data_size;
+    if (!ReadBytes(sizeof(data_size), reinterpret_cast<char*>(&data_size))) {
+      return false;
+    }
+    if (data_size == 0) {
+      // Invalid data size.
+      return false;
+    }
+    data.resize(data_size);
+    return ReadBytes(data_size, reinterpret_cast<char*>(&data.front()));
+  }
+
+ private:
+  static base::FilePath AdjustPath(const base::FilePath& path) {
+    return path.empty()
+               ? base::mac::PathForFrameworkBundleResource(kShaderCacheFileName)
+               : path;
+  }
+
+  bool ReadBytes(uint32_t size, char* data) {
+    char* data_ptr = data;
+    char* data_end = data + size;
+    while (!AtEndOrErrored()) {
+      if (!RemainingBytesInBuffer() && !FillBuffer()) {
+        return false;
+      }
+      const uint32_t bytes_to_copy = std::min(
+          static_cast<uint32_t>(data_end - data_ptr), RemainingBytesInBuffer());
+      CopyFromBufferAndAdvance(bytes_to_copy, data_ptr);
+      data_ptr += bytes_to_copy;
+      if (data_ptr == data_end) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  bool AtEndOrErrored() const { return at_end_or_errored_; }
+
+  void CopyFromBufferAndAdvance(uint32_t num_bytes, char* data) {
+    CHECK_LE(num_bytes, RemainingBytesInBuffer());
+    memcpy(data, read_buffer_ + current_pos_, num_bytes);
+    current_pos_ += num_bytes;
+  }
+
+  uint32_t RemainingBytesInBuffer() const {
+    CHECK_GE(bytes_available_, current_pos_);
+    return bytes_available_ - current_pos_;
+  }
+
+  bool FillBuffer() {
+    current_pos_ = 0;
+    int read = file_.ReadAtCurrentPos(read_buffer_, kReadBufferSize);
+    if (read <= 0) {
+      bytes_available_ = 0;
+      at_end_or_errored_ = true;
+      return false;
+    }
+    bytes_available_ = static_cast<uint32_t>(read);
+    return true;
+  }
+
+  static constexpr size_t kReadBufferSize = 4096;
+  base::File file_;
+  char read_buffer_[kReadBufferSize];
+  uint32_t current_pos_ = 0;
+  uint32_t bytes_available_ = 0;
+  bool at_end_or_errored_ = false;
+};
+
+}  // namespace
+
+BuiltInShaderCacheLoader::CacheEntry::CacheEntry() = default;
+BuiltInShaderCacheLoader::CacheEntry::CacheEntry(CacheEntry&& other) = default;
+BuiltInShaderCacheLoader::CacheEntry::~CacheEntry() = default;
+
+// static
+void BuiltInShaderCacheLoader::StartLoading() {
+  CHECK(!g_loader);
+  // Destroyed when finished loading.
+  g_loader = new BuiltInShaderCacheLoader;
+  base::ThreadPool::PostTask(
+      FROM_HERE, {base::TaskPriority::USER_BLOCKING, base::MayBlock()},
+      base::BindOnce(&BuiltInShaderCacheLoader::Load,
+                     base::Unretained(g_loader), base::FilePath()));
+}
+
+// static
+std::unique_ptr<std::vector<BuiltInShaderCacheLoader::CacheEntry>>
+BuiltInShaderCacheLoader::TakeEntries() {
+  // This is always called, but StartLoading() is only called if loading is
+  // needed.
+  if (!g_loader) {
+    return std::make_unique<std::vector<CacheEntry>>();
+  }
+  auto entries = g_loader->TakeEntriesImpl();
+  delete g_loader;
+  g_loader = nullptr;
+  return entries;
+}
+
+std::unique_ptr<std::vector<BuiltInShaderCacheLoader::CacheEntry>>
+BuiltInShaderCacheLoader::TakeEntriesImpl() {
+  const base::TimeTicks start_time = base::TimeTicks::Now();
+  loaded_signaler_.Wait();
+  const base::TimeTicks end_time = base::TimeTicks::Now();
+  base::UmaHistogramCustomMicrosecondsTimes(
+      "Gpu.MetalShaderCache.WaitTime", end_time - start_time,
+      base::Microseconds(1), base::Milliseconds(100), 100);
+  std::unique_ptr<std::vector<CacheEntry>> entries =
+      std::make_unique<std::vector<CacheEntry>>(std::move(entries_));
+  return entries;
+}
+
+BuiltInShaderCacheLoader::BuiltInShaderCacheLoader() = default;
+
+BuiltInShaderCacheLoader::~BuiltInShaderCacheLoader() = default;
+
+void BuiltInShaderCacheLoader::Load(const base::FilePath& path) {
+  const base::TimeTicks start_time = base::TimeTicks::Now();
+  LoadImpl(path);
+  const base::TimeTicks end_time = base::TimeTicks::Now();
+  base::UmaHistogramCustomMicrosecondsTimes(
+      "Gpu.MetalShaderCache.LoadTime", end_time - start_time,
+      base::Microseconds(10), base::Milliseconds(100), 100);
+  base::UmaHistogramCounts100("Gpu.MetalShaderCache.NumEntriesInCache",
+                              entries_.size());
+  loaded_signaler_.Signal();
+}
+
+void BuiltInShaderCacheLoader::LoadImpl(const base::FilePath& path) {
+  FileReader reader;
+  if (!reader.Init(path)) {
+    return;
+  }
+  for (;;) {
+    CacheEntry entry;
+    if (!reader.ReadKeyOrValue(entry.key) ||
+        !reader.ReadKeyOrValue(entry.value)) {
+      return;
+    }
+    entries_.push_back(std::move(entry));
+  }
+}
+
+}  // namespace gpu
diff --git a/gpu/ipc/service/built_in_shader_cache_loader.h b/gpu/ipc/service/built_in_shader_cache_loader.h
new file mode 100644
index 0000000..0841ce7
--- /dev/null
+++ b/gpu/ipc/service/built_in_shader_cache_loader.h
@@ -0,0 +1,64 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_IPC_SERVICE_BUILT_IN_SHADER_CACHE_LOADER_H_
+#define GPU_IPC_SERVICE_BUILT_IN_SHADER_CACHE_LOADER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/gtest_prod_util.h"
+#include "base/synchronization/waitable_event.h"
+#include "gpu/ipc/service/gpu_ipc_service_export.h"
+
+namespace gpu {
+
+// BuiltInShaderCacheLoader loads the metal shaders that are packaged with
+// chrome. Loading happens in the background. StartLoading() should be called
+// early in startup to start the loading, and later on the values taken by way
+// of TakeEntries().
+class GPU_IPC_SERVICE_EXPORT BuiltInShaderCacheLoader {
+ public:
+  struct CacheEntry {
+    CacheEntry();
+    CacheEntry(CacheEntry&& other);
+    ~CacheEntry();
+
+    std::vector<uint8_t> key;
+    std::vector<uint8_t> value;
+  };
+
+  // Starts loading the cache.
+  static void StartLoading();
+
+  // Returns the entries from the cache and deletes it. This blocks until the
+  // cache is loaded.
+  static std::unique_ptr<std::vector<CacheEntry>> TakeEntries();
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(BuiltInShaderCacheTest, Basic);
+
+  BuiltInShaderCacheLoader();
+  ~BuiltInShaderCacheLoader();
+
+  // Called on the background thread to load the cache.
+  void Load(const base::FilePath& path = base::FilePath());
+
+  // Does the real work of loading the cache.
+  void LoadImpl(const base::FilePath& path);
+
+  // Returns the entries from the cache and deletes it. This blocks until the
+  // cache is loaded.
+  std::unique_ptr<std::vector<CacheEntry>> TakeEntriesImpl();
+
+  std::vector<BuiltInShaderCacheLoader::CacheEntry> entries_;
+
+  // Signaled when the cache is finished loading.
+  base::WaitableEvent loaded_signaler_;
+};
+
+}  // namespace gpu
+
+#endif  // GPU_IPC_SERVICE_BUILT_IN_SHADER_CACHE_LOADER_H_
diff --git a/gpu/ipc/service/built_in_shader_cache_unittest.cc b/gpu/ipc/service/built_in_shader_cache_unittest.cc
new file mode 100644
index 0000000..d5dfa2b
--- /dev/null
+++ b/gpu/ipc/service/built_in_shader_cache_unittest.cc
@@ -0,0 +1,44 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ptr_util.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "gpu/ipc/service/built_in_shader_cache_loader.h"
+#include "gpu/ipc/service/built_in_shader_cache_writer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+TEST(BuiltInShaderCacheTest, Basic) {
+  const std::vector<uint8_t> kKey1{1, 2, 3, 4, 5};
+  const std::vector<uint8_t> kValue1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+  const std::vector<uint8_t> kKey2{9, 101, 55};
+  std::vector<uint8_t> kValue2(257);
+  for (int i = 0; i < 257; ++i) {
+    kValue2[i] = static_cast<uint8_t>(i);
+  }
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  auto path = temp_dir.GetPath().AppendASCII("shaders");
+  {
+    BuiltInShaderCacheWriter writer(path);
+    writer.OnValueAddedToCache(kKey1, kValue1);
+    writer.OnValueAddedToCache(kKey2, kValue2);
+  }
+
+  {
+    base::HistogramTester histogram_tester;
+    BuiltInShaderCacheLoader loader;
+    loader.Load(path);
+    auto entries = loader.TakeEntriesImpl();
+    ASSERT_EQ(2u, entries->size());
+    EXPECT_EQ(kKey1, (*entries)[0].key);
+    EXPECT_EQ(kValue1, (*entries)[0].value);
+    EXPECT_EQ(kKey2, (*entries)[1].key);
+    EXPECT_EQ(kValue2, (*entries)[1].value);
+  }
+}
+
+}  // namespace gpu
diff --git a/gpu/ipc/service/built_in_shader_cache_writer.cc b/gpu/ipc/service/built_in_shader_cache_writer.cc
new file mode 100644
index 0000000..bb8fa5c
--- /dev/null
+++ b/gpu/ipc/service/built_in_shader_cache_writer.cc
@@ -0,0 +1,66 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/ipc/service/built_in_shader_cache_writer.h"
+
+#include <limits.h>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+
+namespace gpu {
+
+namespace {
+
+// Returns the path to use is no path is supplied.
+base::FilePath GetDefaultPath() {
+  auto path = base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+      "shader-cache-path");
+  return path.empty() ? base::FilePath::FromASCII("/tmp/shader") : path;
+}
+
+}  // namespace
+
+const uint32_t BuiltInShaderCacheWriter::kSignature = 0x53484430;
+
+BuiltInShaderCacheWriter::BuiltInShaderCacheWriter(const base::FilePath& path)
+    : file_(path.empty() ? GetDefaultPath() : path,
+            base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_OPEN_TRUNCATED |
+                base::File::FLAG_WRITE) {
+  valid_file_ =
+      file_.IsValid() &&
+      file_.WriteAtCurrentPos(reinterpret_cast<const char*>(&kSignature),
+                              sizeof(kSignature)) == sizeof(kSignature);
+}
+
+BuiltInShaderCacheWriter::~BuiltInShaderCacheWriter() = default;
+
+void BuiltInShaderCacheWriter::OnValueAddedToCache(
+    const std::vector<uint8_t>& key,
+    const std::vector<uint8_t>& value) {
+  CHECK(!key.empty());
+  CHECK(!value.empty());
+  LOG(ERROR) << "Added shader cache value, count is " << ++add_count_;
+  valid_file_ &= WriteVectorToFile(key);
+  valid_file_ &= WriteVectorToFile(value);
+  if (valid_file_) {
+    // Flush after every entry because the gpu is not cleanly shutdown.
+    file_.Flush();
+  }
+}
+
+bool BuiltInShaderCacheWriter::WriteVectorToFile(
+    const std::vector<uint8_t>& value) {
+  // The cache has a max size which is represented by a uint32_t (see
+  // `GpuPreferences::gpu_program_cache_size`), additionally the current max
+  // is ~6mb (anything above the max is dropped, and shouldn't result in
+  // calling this). For this reason `uint32_t` is used.
+  CHECK_LE(value.size(), std::numeric_limits<uint32_t>::max());
+  const uint32_t size = static_cast<uint32_t>(value.size());
+  return file_.WriteAtCurrentPos(reinterpret_cast<const char*>(&size),
+                                 sizeof(size)) == sizeof(size) &&
+         file_.WriteAtCurrentPosAndCheck(value);
+}
+
+}  // namespace gpu
diff --git a/gpu/ipc/service/built_in_shader_cache_writer.h b/gpu/ipc/service/built_in_shader_cache_writer.h
new file mode 100644
index 0000000..4b81952
--- /dev/null
+++ b/gpu/ipc/service/built_in_shader_cache_writer.h
@@ -0,0 +1,52 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_IPC_SERVICE_BUILT_IN_SHADER_CACHE_WRITER_H_
+#define GPU_IPC_SERVICE_BUILT_IN_SHADER_CACHE_WRITER_H_
+
+#include "base/files/file.h"
+#include "gpu/command_buffer/service/passthrough_program_cache.h"
+#include "gpu/ipc/service/gpu_ipc_service_export.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace gpu {
+
+// Used to write the shader cache to disk. Generating the shader libraries
+// requires executing command line programs and is slow. Because of this,
+// writing the shaders is done as part of the build process. That is, a script
+// runs chrome with a set of command line arguments that results in this class
+// being used.
+//
+// As the gpu process does not cleanly shutdown, this writes as it's going.
+class GPU_IPC_SERVICE_EXPORT BuiltInShaderCacheWriter
+    : public gles2::PassthroughProgramCache::ValueAddedHook {
+ public:
+  // Written to beginning of file to ensure file was created by this code.
+  static const uint32_t kSignature;
+
+  explicit BuiltInShaderCacheWriter(
+      const base::FilePath& path = base::FilePath());
+  ~BuiltInShaderCacheWriter() override;
+
+  void OnValueAddedToCache(const std::vector<uint8_t>& key,
+                           const std::vector<uint8_t>& value) override;
+
+ private:
+  bool WriteVectorToFile(const std::vector<uint8_t>& key);
+
+  base::File file_;
+
+  // Set to false if an an error is encountered when writing.
+  bool valid_file_ = false;
+
+  // Number of entries added.
+  int add_count_ = 0;
+};
+
+}  // namespace gpu
+
+#endif  // GPU_IPC_SERVICE_BUILT_IN_SHADER_CACHE_WRITER_H_
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc
index dc4464cb..4d446cb 100644
--- a/gpu/ipc/service/gpu_channel_manager.cc
+++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -56,6 +56,7 @@
 #endif
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_enums.h"
+#include "ui/gl/gl_features.h"
 #include "ui/gl/gl_share_group.h"
 #include "ui/gl/gl_surface_egl.h"
 #include "ui/gl/gl_version_info.h"
@@ -66,6 +67,11 @@
 #include "gpu/vulkan/vulkan_fence_helper.h"
 #endif
 
+#if BUILDFLAG(IS_MAC)
+#include "gpu/ipc/service/built_in_shader_cache_loader.h"
+#include "gpu/ipc/service/built_in_shader_cache_writer.h"
+#endif
+
 namespace gpu {
 
 namespace {
@@ -383,7 +389,6 @@
 
 GpuChannelManager::~GpuChannelManager() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
   // Clear |gpu_channels_| first to prevent reentrancy problems from GpuChannel
   // destructor.
   auto gpu_channels = std::move(gpu_channels_);
@@ -426,8 +431,25 @@
 
     // Use the EGL blob cache extension for the passthrough decoder.
     if (use_passthrough_cmd_decoder()) {
-      program_cache_ = std::make_unique<gles2::PassthroughProgramCache>(
-          gpu_preferences_.gpu_program_cache_size, disable_disk_cache);
+      gles2::PassthroughProgramCache::ValueAddedHook* value_add_hook = nullptr;
+#if BUILDFLAG(IS_MAC)
+      if (base::FeatureList::IsEnabled(
+              features::kWriteMetalShaderCacheToDisk)) {
+        shader_cache_writer_ = std::make_unique<BuiltInShaderCacheWriter>();
+        value_add_hook = shader_cache_writer_.get();
+      }
+#endif
+      std::unique_ptr<gles2::PassthroughProgramCache> cache =
+          std::make_unique<gles2::PassthroughProgramCache>(
+              gpu_preferences_.gpu_program_cache_size, disable_disk_cache,
+              value_add_hook);
+#if BUILDFLAG(IS_MAC)
+      auto entries = BuiltInShaderCacheLoader::TakeEntries();
+      for (auto& entry : *entries) {
+        cache->Set(std::move(entry.key), std::move(entry.value));
+      }
+#endif
+      program_cache_ = std::move(cache);
     } else {
       program_cache_ = std::make_unique<gles2::MemoryProgramCache>(
           gpu_preferences_.gpu_program_cache_size, disable_disk_cache,
diff --git a/gpu/ipc/service/gpu_channel_manager.h b/gpu/ipc/service/gpu_channel_manager.h
index 2054fbdf..fc3e2f4 100644
--- a/gpu/ipc/service/gpu_channel_manager.h
+++ b/gpu/ipc/service/gpu_channel_manager.h
@@ -57,6 +57,7 @@
 
 namespace gpu {
 
+class BuiltInShaderCacheWriter;
 class SharedImageManager;
 struct GpuPreferences;
 class GpuChannel;
@@ -338,6 +339,10 @@
 
   scoped_refptr<gl::GLShareGroup> share_group_;
 
+#if BUILDFLAG(IS_MAC)
+  std::unique_ptr<BuiltInShaderCacheWriter> shader_cache_writer_;
+#endif
+
   std::unique_ptr<MailboxManager> mailbox_manager_;
   std::unique_ptr<gles2::Outputter> outputter_;
   raw_ptr<Scheduler> scheduler_;
diff --git a/infra/config/generated/builders/try/dawn-android-arm-deps-rel/properties.json b/infra/config/generated/builders/try/dawn-android-arm-deps-rel/properties.json
index 5b0440f..6f19125 100644
--- a/infra/config/generated/builders/try/dawn-android-arm-deps-rel/properties.json
+++ b/infra/config/generated/builders/try/dawn-android-arm-deps-rel/properties.json
@@ -55,6 +55,5 @@
   },
   "builder_group": "tryserver.chromium.dawn",
   "cq": "path-based",
-  "recipe": "chromium_trybot",
-  "root_solution_revision": "refs/heads/main"
+  "recipe": "chromium_trybot"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/dawn-linux-x64-deps-rel/properties.json b/infra/config/generated/builders/try/dawn-linux-x64-deps-rel/properties.json
index bc4b842..9105cff 100644
--- a/infra/config/generated/builders/try/dawn-linux-x64-deps-rel/properties.json
+++ b/infra/config/generated/builders/try/dawn-linux-x64-deps-rel/properties.json
@@ -126,6 +126,5 @@
   },
   "builder_group": "tryserver.chromium.dawn",
   "cq": "path-based",
-  "recipe": "chromium_trybot",
-  "root_solution_revision": "refs/heads/main"
+  "recipe": "chromium_trybot"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/dawn-mac-x64-deps-rel/properties.json b/infra/config/generated/builders/try/dawn-mac-x64-deps-rel/properties.json
index 2ed8bd2..91f8264 100644
--- a/infra/config/generated/builders/try/dawn-mac-x64-deps-rel/properties.json
+++ b/infra/config/generated/builders/try/dawn-mac-x64-deps-rel/properties.json
@@ -127,6 +127,5 @@
   },
   "builder_group": "tryserver.chromium.dawn",
   "cq": "path-based",
-  "recipe": "chromium_trybot",
-  "root_solution_revision": "refs/heads/main"
+  "recipe": "chromium_trybot"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/dawn-win10-x64-deps-rel/properties.json b/infra/config/generated/builders/try/dawn-win10-x64-deps-rel/properties.json
index 4fc369a..69a1a85 100644
--- a/infra/config/generated/builders/try/dawn-win10-x64-deps-rel/properties.json
+++ b/infra/config/generated/builders/try/dawn-win10-x64-deps-rel/properties.json
@@ -126,6 +126,5 @@
   },
   "builder_group": "tryserver.chromium.dawn",
   "cq": "path-based",
-  "recipe": "chromium_trybot",
-  "root_solution_revision": "refs/heads/main"
+  "recipe": "chromium_trybot"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/dawn-win10-x86-deps-rel/properties.json b/infra/config/generated/builders/try/dawn-win10-x86-deps-rel/properties.json
index 757246e..0871422b1 100644
--- a/infra/config/generated/builders/try/dawn-win10-x86-deps-rel/properties.json
+++ b/infra/config/generated/builders/try/dawn-win10-x86-deps-rel/properties.json
@@ -126,6 +126,5 @@
   },
   "builder_group": "tryserver.chromium.dawn",
   "cq": "path-based",
-  "recipe": "chromium_trybot",
-  "root_solution_revision": "refs/heads/main"
+  "recipe": "chromium_trybot"
 }
\ No newline at end of file
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 8b23b62..e532b46 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -28783,13 +28783,10 @@
     builders {
       name: "build-perf-android"
       swarming_host: "chromium-swarm.appspot.com"
-      dimensions: "builderless:1"
-      dimensions: "cores:32"
+      dimensions: "builder:build-perf-android"
       dimensions: "cpu:x86-64"
-      dimensions: "free_space:standard"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:1"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
         cipd_version: "refs/heads/main"
@@ -28907,11 +28904,9 @@
       name: "build-perf-android-siso"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builder:build-perf-android-siso"
-      dimensions: "cores:32"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:1"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
         cipd_version: "refs/heads/main"
@@ -29032,13 +29027,10 @@
     builders {
       name: "build-perf-linux"
       swarming_host: "chromium-swarm.appspot.com"
-      dimensions: "builderless:1"
-      dimensions: "cores:16"
+      dimensions: "builder:build-perf-linux"
       dimensions: "cpu:x86-64"
-      dimensions: "free_space:standard"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:1"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
         cipd_version: "refs/heads/main"
@@ -29152,11 +29144,9 @@
       name: "build-perf-linux-siso"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builder:build-perf-linux-siso"
-      dimensions: "cores:16"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:1"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
         cipd_version: "refs/heads/main"
@@ -29273,13 +29263,10 @@
     builders {
       name: "build-perf-windows"
       swarming_host: "chromium-swarm.appspot.com"
-      dimensions: "builderless:1"
-      dimensions: "cores:32"
+      dimensions: "builder:build-perf-windows"
       dimensions: "cpu:x86-64"
-      dimensions: "free_space:standard"
       dimensions: "os:Windows-10"
       dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:1"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
         cipd_version: "refs/heads/main"
@@ -29393,11 +29380,9 @@
       name: "build-perf-windows-siso"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builder:build-perf-windows-siso"
-      dimensions: "cores:32"
       dimensions: "cpu:x86-64"
       dimensions: "os:Windows-10"
       dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:1"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
         cipd_version: "refs/heads/main"
diff --git a/infra/config/lib/linux-default.json b/infra/config/lib/linux-default.json
index 5631960..b0b4044 100644
--- a/infra/config/lib/linux-default.json
+++ b/infra/config/lib/linux-default.json
@@ -1,7 +1,11 @@
 {
   "ci": {
     "linux-rel-jammy-dev": "Ubuntu-22.04",
-    "linux-ssd-rel-dev": "Ubuntu-22.04"
+    "linux-ssd-rel-dev": "Ubuntu-22.04",
+    "build-perf-linux": "Ubuntu-22.04",
+    "build-perf-linux-siso": "Ubuntu-22.04",
+    "build-perf-android": "Ubuntu-22.04",
+    "build-perf-android-siso": "Ubuntu-22.04"
   },
   "try": {
     "android-12-x64-rel": "Ubuntu-22.04",
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star
index a20248b..9cb7eb9 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -1537,11 +1537,9 @@
             config = "main_builder",
         ),
     ),
-    builderless = True,
-    cores = 32,
-    # Target luci-chromium-ci-bionic-us-central1-c-1000-ssd-hm32-*.
+    builderless = False,
+    cores = None,  # rely on the builder dimension for the bot selection.
     os = os.LINUX_DEFAULT,
-    ssd = True,
     console_view_entry = consoles.console_view_entry(
         category = "buildperf",
         short_name = "and",
@@ -1582,10 +1580,8 @@
         ),
     ),
     builderless = False,
-    cores = 32,
-    # Target luci-chromium-ci-bionic-us-central1-c-1000-ssd-hm32-*.
+    cores = None,  # rely on the builder dimension for the bot selection.
     os = os.LINUX_DEFAULT,
-    ssd = True,
     console_view_entry = consoles.console_view_entry(
         category = "buildperf",
         short_name = "andss",
@@ -1616,11 +1612,9 @@
             ],
         ),
     ),
-    builderless = True,
-    cores = 16,
-    # Target luci-chromium-ci-bionic-us-central1-b-ssd-16-*.
+    builderless = False,
+    cores = None,  # rely on the builder dimension for the bot selection.
     os = os.LINUX_DEFAULT,
-    ssd = True,
     console_view_entry = consoles.console_view_entry(
         category = "buildperf",
         short_name = "lnx",
@@ -1655,10 +1649,8 @@
         ),
     ),
     builderless = False,
-    cores = 16,
-    # Target luci-chromium-ci-bionic-us-central1-b-ssd-16-*.
+    cores = None,  # rely on the builder dimension for the bot selection.
     os = os.LINUX_DEFAULT,
-    ssd = True,
     console_view_entry = consoles.console_view_entry(
         category = "buildperf",
         short_name = "lnxss",
@@ -1690,11 +1682,9 @@
             ],
         ),
     ),
-    builderless = True,
-    cores = 32,
-    # Target luci-chromium-ci-win10-ssd-32-*.
+    builderless = False,
+    cores = None,  # rely on the builder dimension for the bot selection.
     os = os.WINDOWS_DEFAULT,
-    ssd = True,
     console_view_entry = consoles.console_view_entry(
         category = "buildperf",
         short_name = "win",
@@ -1729,10 +1719,8 @@
         ),
     ),
     builderless = False,
-    cores = 32,
-    # Target luci-chromium-ci-win10-ssd-32-*.
+    cores = None,  # rely on the builder dimension for the bot selection.
     os = os.WINDOWS_DEFAULT,
-    ssd = True,
     console_view_entry = consoles.console_view_entry(
         category = "buildperf",
         short_name = "winss",
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.dawn.star b/infra/config/subprojects/chromium/try/tryserver.chromium.dawn.star
index 7fe85dd6..b20b5ac 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.dawn.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.dawn.star
@@ -7,7 +7,6 @@
 load("//lib/builders.star", "os", "reclient")
 load("//lib/consoles.star", "consoles")
 load("//lib/try.star", "try_")
-load("//project.star", "settings")
 
 try_.defaults.set(
     executable = try_.DEFAULT_EXECUTABLE,
@@ -36,9 +35,6 @@
         "ci/Dawn Android arm DEPS Release (Pixel 4)",
     ],
     main_list_view = "try",
-    properties = {
-        "root_solution_revision": settings.ref,
-    },
     test_presentation = resultdb.test_presentation(
         grouping_keys = ["status", "v.test_suite", "v.gpu"],
     ),
@@ -68,9 +64,6 @@
         "ci/Dawn Linux x64 DEPS Release (NVIDIA)",
     ],
     main_list_view = "try",
-    properties = {
-        "root_solution_revision": settings.ref,
-    },
     test_presentation = resultdb.test_presentation(
         grouping_keys = ["status", "v.test_suite", "v.gpu"],
     ),
@@ -101,9 +94,6 @@
     ],
     os = os.MAC_ANY,
     main_list_view = "try",
-    properties = {
-        "root_solution_revision": settings.ref,
-    },
     test_presentation = resultdb.test_presentation(
         grouping_keys = ["status", "v.test_suite", "v.gpu"],
     ),
@@ -134,9 +124,6 @@
     ],
     os = os.WINDOWS_ANY,
     main_list_view = "try",
-    properties = {
-        "root_solution_revision": settings.ref,
-    },
     test_presentation = resultdb.test_presentation(
         grouping_keys = ["status", "v.test_suite", "v.gpu"],
     ),
@@ -167,9 +154,6 @@
     ],
     os = os.WINDOWS_ANY,
     main_list_view = "try",
-    properties = {
-        "root_solution_revision": settings.ref,
-    },
     test_presentation = resultdb.test_presentation(
         grouping_keys = ["status", "v.test_suite", "v.gpu"],
     ),
diff --git a/ios/chrome/browser/default_browser/BUILD.gn b/ios/chrome/browser/default_browser/BUILD.gn
index 6959dec..461b03c 100644
--- a/ios/chrome/browser/default_browser/BUILD.gn
+++ b/ios/chrome/browser/default_browser/BUILD.gn
@@ -18,6 +18,7 @@
     "//components/sync/driver",
     "//ios/chrome/browser/application_context",
     "//ios/chrome/browser/feature_engagement",
+    "//ios/chrome/browser/ntp:features",
     "//ios/chrome/browser/settings/sync/utils:identity_error_util",
     "//ios/chrome/browser/shared/public/features",
   ]
diff --git a/ios/chrome/browser/default_browser/utils.h b/ios/chrome/browser/default_browser/utils.h
index adb780a2..7c0f5ff 100644
--- a/ios/chrome/browser/default_browser/utils.h
+++ b/ios/chrome/browser/default_browser/utils.h
@@ -130,7 +130,7 @@
 void LogUserInteractionWithFirstRunPromo(BOOL openedSettings);
 
 // Returns YES if the user has opened the app through first-party intent 2
-// times in the last 7 days, with more than 6 hours between each time. Also
+// times in the last 7 days, but across 2 user sessions (default 6 hours). Also
 // records that a new launch has happened if the last one was more than one
 // session ago.
 bool HasRecentFirstPartyIntentLaunchesAndRecordsCurrentLaunch();
@@ -140,7 +140,7 @@
 bool HasRecentValidURLPastesAndRecordsCurrentPaste();
 
 // Returns YES if the last timestamp passed as `eventKey` is part of the current
-// user session (6 hours). If not, it records the timestamp.
+// user session (default 6 hours). If not, it records the timestamp.
 bool HasRecentTimestampForKey(NSString* eventKey);
 
 // Returns true if the last URL open is within the time threshold that would
diff --git a/ios/chrome/browser/default_browser/utils.mm b/ios/chrome/browser/default_browser/utils.mm
index 0df9faf..b6ee318 100644
--- a/ios/chrome/browser/default_browser/utils.mm
+++ b/ios/chrome/browser/default_browser/utils.mm
@@ -16,6 +16,7 @@
 #import "components/sync/driver/sync_service.h"
 #import "ios/chrome/browser/application_context/application_context.h"
 #import "ios/chrome/browser/feature_engagement/tracker_factory.h"
+#import "ios/chrome/browser/ntp/features.h"
 #import "ios/chrome/browser/settings/sync/utils/identity_error_util.h"
 #import "ios/chrome/browser/shared/public/features/features.h"
 
@@ -131,9 +132,6 @@
 constexpr base::TimeDelta kMaximumTimeBetweenFirstPartyAppLaunches =
     base::Days(7);
 
-// Maximum time representing one user session.
-constexpr base::TimeDelta kMaximumTimeOneUserSession = base::Hours(6);
-
 // Maximum time range between valid user URL pastes to notify the FET.
 constexpr base::TimeDelta kMaximumTimeBetweenValidURLPastes = base::Days(7);
 
@@ -525,12 +523,14 @@
 }
 
 bool HasRecentFirstPartyIntentLaunchesAndRecordsCurrentLaunch() {
+  const base::TimeDelta max_session_time =
+      base::Seconds(GetFeedUnseenRefreshThresholdInSeconds());
+
   if (HasRecordedEventForKeyLessThanDelay(
           kTimestampAppLastOpenedViaFirstPartyIntent,
           kMaximumTimeBetweenFirstPartyAppLaunches)) {
     if (HasRecordedEventForKeyMoreThanDelay(
-            kTimestampAppLastOpenedViaFirstPartyIntent,
-            kMaximumTimeOneUserSession)) {
+            kTimestampAppLastOpenedViaFirstPartyIntent, max_session_time)) {
       SetObjectIntoStorageForKey(kTimestampAppLastOpenedViaFirstPartyIntent,
                                  [NSDate date]);
       return YES;
@@ -556,8 +556,10 @@
 }
 
 bool HasRecentTimestampForKey(NSString* eventKey) {
-  if (HasRecordedEventForKeyLessThanDelay(eventKey,
-                                          kMaximumTimeOneUserSession)) {
+  const base::TimeDelta max_session_time =
+      base::Seconds(GetFeedUnseenRefreshThresholdInSeconds());
+
+  if (HasRecordedEventForKeyLessThanDelay(eventKey, max_session_time)) {
     return YES;
   }
 
diff --git a/ios/chrome/browser/passwords/BUILD.gn b/ios/chrome/browser/passwords/BUILD.gn
index 81209996..d8ad9ee 100644
--- a/ios/chrome/browser/passwords/BUILD.gn
+++ b/ios/chrome/browser/passwords/BUILD.gn
@@ -257,11 +257,9 @@
     "//components/password_manager/core/common",
     "//components/strings",
     "//ios/chrome/app/strings",
-    "//ios/chrome/browser/credential_provider_promo:features",
     "//ios/chrome/browser/signin:fake_system_identity",
     "//ios/chrome/browser/ui/authentication:eg_test_support+eg2",
     "//ios/chrome/browser/ui/infobars/banners:public",
-    "//ios/chrome/common/ui/confirmation_alert",
     "//ios/chrome/test:eg_test_support+eg2",
     "//ios/chrome/test/earl_grey:eg_test_support+eg2",
     "//ios/testing/earl_grey:eg_test_support+eg2",
diff --git a/ios/chrome/browser/passwords/password_controller_egtest.mm b/ios/chrome/browser/passwords/password_controller_egtest.mm
index 9b0e9c7..af4cde0 100644
--- a/ios/chrome/browser/passwords/password_controller_egtest.mm
+++ b/ios/chrome/browser/passwords/password_controller_egtest.mm
@@ -11,14 +11,11 @@
 #import "base/test/ios/wait_util.h"
 #import "components/password_manager/core/common/password_manager_features.h"
 #import "components/strings/grit/components_strings.h"
-#import "ios/chrome/browser/credential_provider_promo/features.h"
 #import "ios/chrome/browser/passwords/password_manager_app_interface.h"
 #import "ios/chrome/browser/signin/fake_system_identity.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.h"
 #import "ios/chrome/browser/ui/infobars/banners/infobar_banner_constants.h"
-#import "ios/chrome/common/ui/confirmation_alert/confirmation_alert_view_controller.h"
-#import "ios/chrome/grit/ios_google_chrome_strings.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/earl_grey/chrome_actions.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
@@ -26,7 +23,6 @@
 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/chrome/test/earl_grey/web_http_server_chrome_test_case.h"
-#import "ios/testing/earl_grey/app_launch_manager.h"
 #import "ios/testing/earl_grey/earl_grey_test.h"
 #import "ios/testing/earl_grey/matchers.h"
 #import "net/base/mac/url_conversions.h"
@@ -75,33 +71,6 @@
   return [waitForKeyboard waitWithTimeout:kWaitForActionTimeout.InSecondsF()];
 }
 
-// Returns the matcher for the Credential Provider Promo's subtitle.
-id<GREYMatcher> SubtitleMatcher() {
-  return grey_accessibilityID(
-      kConfirmationAlertSubtitleAccessibilityIdentifier);
-}
-
-// Returns the matcher for the Credential Provider Promo's primary action
-// button.
-id<GREYMatcher> PrimaryActionButtonMatcher() {
-  return grey_accessibilityID(
-      kConfirmationAlertPrimaryActionAccessibilityIdentifier);
-}
-
-// Returns the matcher for the Credential Provider Promo's secondary action
-// button.
-id<GREYMatcher> SecondaryActionButtonMatcher() {
-  return grey_accessibilityID(
-      kConfirmationAlertSecondaryActionAccessibilityIdentifier);
-}
-
-// Returns the matcher for the Credential Provider Promo's tertiary action
-// button.
-id<GREYMatcher> TertiaryActionButtonMatcher() {
-  return grey_accessibilityID(
-      kConfirmationAlertTertiaryActionAccessibilityIdentifier);
-}
-
 }  // namespace
 
 @interface PasswordControllerEGTest : WebHttpServerChromeTestCase
@@ -137,15 +106,6 @@
     config.features_enabled.push_back(
         password_manager::features::kIOSShowPasswordStorageInSaveInfobar);
   }
-  if ([self isRunningTest:@selector
-            (testCredentialProviderPromoAppearsOnPasswordSave)]) {
-    config.additional_args.push_back(
-        std::string("--enable-features=CredentialProviderExtensionPromo:enable_"
-                    "promo_on_password_saved/true"));
-    // Without relaunch, the credential provider promo meets its impression
-    // limit and does not display in subsequent runs.
-    config.relaunch_policy = ForceRelaunchByCleanShutdown;
-  }
   return config;
 }
 
@@ -158,8 +118,13 @@
   [ChromeEarlGrey waitForWebStateContainingText:"Login form."];
 }
 
-// Logs into a website and taps on the resultant "save password" prompt.
-- (void)loginAndSavePassword {
+#pragma mark - Tests
+
+// Tests that save password prompt is shown on new login.
+// TODO(crbug.com/1192446): Reenable this test.
+- (void)DISABLED_testSavePromptAppearsOnFormSubmission {
+  [self loadLoginPage];
+
   // Simulate user interacting with fields.
   [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()]
       performAction:chrome_test_util::TapWebElementWithId(kFormUsername)];
@@ -177,28 +142,6 @@
   [[EarlGrey selectElementWithMatcher:PasswordInfobarButton(
                                           IDS_IOS_PASSWORD_MANAGER_SAVE_BUTTON)]
       performAction:grey_tap()];
-}
-
-// Checks that the Credential Provider Promo subtitle text and buttons are
-// interactable.
-void CheckThatCredentialPromoElementsAreInteractable() {
-  [[EarlGrey selectElementWithMatcher:SubtitleMatcher()]
-      assertWithMatcher:grey_interactable()];
-  [[EarlGrey selectElementWithMatcher:PrimaryActionButtonMatcher()]
-      assertWithMatcher:grey_interactable()];
-  [[EarlGrey selectElementWithMatcher:SecondaryActionButtonMatcher()]
-      assertWithMatcher:grey_interactable()];
-  [[EarlGrey selectElementWithMatcher:TertiaryActionButtonMatcher()]
-      assertWithMatcher:grey_interactable()];
-}
-
-#pragma mark - Tests
-
-// Tests that save password prompt is shown on new login.
-// TODO(crbug.com/1192446): Reenable this test.
-- (void)DISABLED_testSavePromptAppearsOnFormSubmission {
-  [self loadLoginPage];
-  [self loginAndSavePassword];
 
   // Wait until the save password infobar disappears.
   [ChromeEarlGrey
@@ -209,33 +152,6 @@
   GREYAssertEqual(1, credentialsCount, @"Wrong number of stored credentials.");
 }
 
-// Tests that the Credential Provider Extension Promo is shown after a password
-// is saved through the Save Password prompt.
-- (void)testCredentialProviderPromoAppearsOnPasswordSave {
-  [self loadLoginPage];
-  [self loginAndSavePassword];
-
-  // Check that the inital promo is visible.
-  id<GREYMatcher> initialTitleLabelMatcher = grey_text(
-      l10n_util::GetNSString(IDS_IOS_CREDENTIAL_PROVIDER_PROMO_INITIAL_TITLE));
-  [[EarlGrey selectElementWithMatcher:initialTitleLabelMatcher]
-      assertWithMatcher:grey_sufficientlyVisible()];
-  CheckThatCredentialPromoElementsAreInteractable();
-
-  // Tap the primary action button to display the `learn more` promo.
-  [[EarlGrey
-      selectElementWithMatcher:grey_allOf(PrimaryActionButtonMatcher(),
-                                          grey_sufficientlyVisible(), nil)]
-      performAction:grey_tap()];
-
-  // Check that the `learn more` promo is visible.
-  id<GREYMatcher> learnMoreTitleLabelMatcher = grey_text(l10n_util::GetNSString(
-      IDS_IOS_CREDENTIAL_PROVIDER_PROMO_LEARN_MORE_TITLE));
-  [[EarlGrey selectElementWithMatcher:learnMoreTitleLabelMatcher]
-      assertWithMatcher:grey_sufficientlyVisible()];
-  CheckThatCredentialPromoElementsAreInteractable();
-}
-
 - (void)testShowAccountStorageNoticeBeforeSaving {
   [PasswordManagerAppInterface setAccountStorageNoticeShown:NO];
   FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];
diff --git a/ios/chrome/browser/ui/browser_view/key_commands_provider_unittest.mm b/ios/chrome/browser/ui/browser_view/key_commands_provider_unittest.mm
index a44c0ca..6ef685c 100644
--- a/ios/chrome/browser/ui/browser_view/key_commands_provider_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view/key_commands_provider_unittest.mm
@@ -38,6 +38,7 @@
 #import "ios/web/find_in_page/java_script_find_in_page_manager_impl.h"
 #import "ios/web/public/test/fakes/fake_navigation_context.h"
 #import "ios/web/public/test/fakes/fake_navigation_manager.h"
+#import "ios/web/public/test/fakes/fake_web_frames_manager.h"
 #import "ios/web/public/test/fakes/fake_web_state.h"
 #import "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
@@ -284,6 +285,8 @@
 
   // Open a tab.
   web::FakeWebState* web_state = InsertNewWebState(0);
+  web_state->SetWebFramesManager(web::ContentWorld::kIsolatedWorld,
+                                 std::make_unique<web::FakeWebFramesManager>());
   web::JavaScriptFindInPageManagerImpl::CreateForWebState(web_state);
   JavaScriptFindTabHelper::CreateForWebState(web_state);
 
@@ -833,6 +836,8 @@
 TEST_F(KeyCommandsProviderTest, ValidateCommands) {
   // Open a tab.
   web::FakeWebState* web_state = InsertNewWebState(0);
+  web_state->SetWebFramesManager(web::ContentWorld::kIsolatedWorld,
+                                 std::make_unique<web::FakeWebFramesManager>());
   web::JavaScriptFindInPageManagerImpl::CreateForWebState(web_state);
   JavaScriptFindTabHelper::CreateForWebState(web_state);
 
diff --git a/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_view.mm b/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_view.mm
index 082103f..b388b53 100644
--- a/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_view.mm
+++ b/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_view.mm
@@ -149,8 +149,13 @@
     [menuButton.firstBaselineAnchor
         constraintEqualToAnchor:listTitle.firstBaselineAnchor],
   ]];
-  self.accessibilityElements =
-      @[ listTitle, menuButton, _itemsStack, _expandButton ];
+
+  if (_expandButton) {
+    self.accessibilityElements =
+        @[ listTitle, menuButton, _itemsStack, _expandButton ];
+  } else {
+    self.accessibilityElements = @[ listTitle, menuButton, _itemsStack ];
+  }
 }
 
 // Returns an array of SetUpListItemViews based on the itemsDictionary that was
diff --git a/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_view_unittest.mm b/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_view_unittest.mm
index f4db8071..d9a9197 100644
--- a/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_view_unittest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_view_unittest.mm
@@ -198,3 +198,15 @@
 
   EXPECT_TRUE(item_view.complete);
 }
+
+// Tests that with only 2 items, no expand button is present.
+TEST_F(SetUpListViewTest, NoExpandButton) {
+  NSArray<SetUpListItemViewData*>* first_two_items =
+      [_itemsData subarrayWithRange:NSMakeRange(0, 2)];
+  SetUpListView* view = [[SetUpListView alloc] initWithItems:first_two_items];
+  [_superview addSubview:view];
+
+  SetUpListItemView* expand_button =
+      (SetUpListItemView*)FindSubview(@"kSetUpListExpandButtonID");
+  EXPECT_TRUE(expand_button == nil);
+}
diff --git a/ios/chrome/browser/ui/settings/password/BUILD.gn b/ios/chrome/browser/ui/settings/password/BUILD.gn
index 13f58e7..57307f2e 100644
--- a/ios/chrome/browser/ui/settings/password/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/password/BUILD.gn
@@ -297,7 +297,6 @@
     "//ios/chrome/browser/ui/settings/password/password_details:password_details_table_view_constants",
     "//ios/chrome/browser/ui/settings/password/password_settings:password_settings_constants",
     "//ios/chrome/browser/ui/settings/password/passwords_in_other_apps:eg_test_support+eg2",
-    "//ios/chrome/common/ui/confirmation_alert",
     "//ios/chrome/common/ui/reauthentication",
     "//ios/chrome/common/ui/table_view:cells_constants",
     "//ios/chrome/test/earl_grey:eg_test_support+eg2",
diff --git a/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm b/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm
index 841021d..0940dcf 100644
--- a/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm
+++ b/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm
@@ -28,10 +28,8 @@
 #import "ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_app_interface.h"
 #import "ios/chrome/browser/ui/settings/password/passwords_table_view_constants.h"
 #import "ios/chrome/browser/ui/settings/settings_root_table_constants.h"
-#import "ios/chrome/common/ui/confirmation_alert/confirmation_alert_view_controller.h"
 #import "ios/chrome/common/ui/reauthentication/reauthentication_protocol.h"
 #import "ios/chrome/common/ui/table_view/table_view_cells_constants.h"
-#import "ios/chrome/grit/ios_google_chrome_strings.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/earl_grey/chrome_actions.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
@@ -431,46 +429,6 @@
   return SettingToolbarEditDoneButton();
 }
 
-// Returns the matcher for the Credential Provider Promo's subtitle.
-id<GREYMatcher> SubtitleMatcher() {
-  return grey_accessibilityID(
-      kConfirmationAlertSubtitleAccessibilityIdentifier);
-}
-
-// Returns the matcher for the Credential Provider Promo's primary action
-// button.
-id<GREYMatcher> PrimaryActionButtonMatcher() {
-  return grey_accessibilityID(
-      kConfirmationAlertPrimaryActionAccessibilityIdentifier);
-}
-
-// Returns the matcher for the Credential Provider Promo's secondary action
-// button.
-id<GREYMatcher> SecondaryActionButtonMatcher() {
-  return grey_accessibilityID(
-      kConfirmationAlertSecondaryActionAccessibilityIdentifier);
-}
-
-// Returns the matcher for the Credential Provider Promo's tertiary action
-// button.
-id<GREYMatcher> TertiaryActionButtonMatcher() {
-  return grey_accessibilityID(
-      kConfirmationAlertTertiaryActionAccessibilityIdentifier);
-}
-
-// Checks that the Credential Provider Promo subtitle text and buttons are
-// interactable.
-void CheckThatCredentialPromoElementsAreInteractable() {
-  [[EarlGrey selectElementWithMatcher:SubtitleMatcher()]
-      assertWithMatcher:grey_interactable()];
-  [[EarlGrey selectElementWithMatcher:PrimaryActionButtonMatcher()]
-      assertWithMatcher:grey_interactable()];
-  [[EarlGrey selectElementWithMatcher:SecondaryActionButtonMatcher()]
-      assertWithMatcher:grey_interactable()];
-  [[EarlGrey selectElementWithMatcher:TertiaryActionButtonMatcher()]
-      assertWithMatcher:grey_interactable()];
-}
-
 }  // namespace
 
 // Various tests for the main Password Manager UI.
@@ -598,15 +556,7 @@
       [self isRunningTest:@selector(testShowHidePasswordWithNotesEnabled)]) {
     config.features_enabled.push_back(syncer::kPasswordNotesWithBackup);
   }
-  if ([self isRunningTest:@selector
-            (testCredentialProviderPromoDisplayOnPasswordCopied)]) {
-    config.additional_args.push_back(
-        std::string("--enable-features=CredentialProviderExtensionPromo:enable_"
-                    "promo_on_password_copied/true"));
-    // Without relaunch, the credential provider promo meets its impression
-    // limit and does not display in subsequent runs.
-    config.relaunch_policy = ForceRelaunchByCleanShutdown;
-  }
+
   return config;
 }
 
@@ -682,57 +632,6 @@
       performAction:grey_tap()];
 }
 
-// Checks that the Credential Provider Promo is displayed after a password is
-// copied.
-- (void)testCredentialProviderPromoDisplayOnPasswordCopied {
-  if (![self groupingEnabled]) {
-    EARL_GREY_TEST_SKIPPED(
-        @"This test isn't implemented with grouped passwords disabled.");
-  }
-
-  // Saving a form is needed for using the "password details" view.
-  SaveExamplePasswordForm();
-
-  OpenPasswordManager();
-
-  [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
-                                            username:@"concrete username"]
-      performAction:grey_tap()];
-
-  // Check the snackbar in case of successful reauthentication.
-  [PasswordSettingsAppInterface setUpMockReauthenticationModule];
-  [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                    ReauthenticationResult::kSuccess];
-
-  CopyPasswordDetailWithID(IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD);
-
-  // Check that the inital promo is visible.
-  id<GREYMatcher> initialTitleLabelMatcher = grey_text(
-      l10n_util::GetNSString(IDS_IOS_CREDENTIAL_PROVIDER_PROMO_INITIAL_TITLE));
-  [[EarlGrey selectElementWithMatcher:initialTitleLabelMatcher]
-      assertWithMatcher:grey_sufficientlyVisible()];
-  CheckThatCredentialPromoElementsAreInteractable();
-
-  // Close the snackbar.
-  NSString* snackbarLabel =
-      l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_WAS_COPIED_MESSAGE);
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(snackbarLabel)]
-      performAction:grey_tap()];
-
-  // Tap the primary action button to display the `learn more` promo.
-  [[EarlGrey
-      selectElementWithMatcher:grey_allOf(PrimaryActionButtonMatcher(),
-                                          grey_sufficientlyVisible(), nil)]
-      performAction:grey_tap()];
-
-  // Check that the `learn more` promo is visible.
-  id<GREYMatcher> learnMoreTitleLabelMatcher = grey_text(l10n_util::GetNSString(
-      IDS_IOS_CREDENTIAL_PROVIDER_PROMO_LEARN_MORE_TITLE));
-  [[EarlGrey selectElementWithMatcher:learnMoreTitleLabelMatcher]
-      assertWithMatcher:grey_sufficientlyVisible()];
-  CheckThatCredentialPromoElementsAreInteractable();
-}
-
 // Checks that an attempt to show a password provides an appropriate feedback
 // when reauthentication succeeds.
 - (void)testShowPasswordAuthSucceeded {
diff --git a/ios/chrome/common/ui/confirmation_alert/confirmation_alert_view_controller.h b/ios/chrome/common/ui/confirmation_alert/confirmation_alert_view_controller.h
index be4f891c..6fad834 100644
--- a/ios/chrome/common/ui/confirmation_alert/confirmation_alert_view_controller.h
+++ b/ios/chrome/common/ui/confirmation_alert/confirmation_alert_view_controller.h
@@ -13,7 +13,6 @@
 extern NSString* const kConfirmationAlertSubtitleAccessibilityIdentifier;
 extern NSString* const kConfirmationAlertPrimaryActionAccessibilityIdentifier;
 extern NSString* const kConfirmationAlertSecondaryActionAccessibilityIdentifier;
-extern NSString* const kConfirmationAlertTertiaryActionAccessibilityIdentifier;
 
 @protocol ConfirmationAlertActionHandler;
 
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index c5b33a5..30f2b901 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-acd14c1f40263307d48f9905fcad90caf9dc8a46
\ No newline at end of file
+e23ac24212c4bb9b82016dc226a0ab14779eca22
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index 169076b..6bd74699 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-a2050577df7e714f2faca80224bd55a83c18e559
\ No newline at end of file
+6d810a264a91af37c7d9fe82f1ef65002676f98a
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index cb3c8403..075332c 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-acb274f4fa1562b8d2905745e39acd56bff956eb
\ No newline at end of file
+1d4b03b11dc670bf62139dd82e5c5cd81bc0a9b7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index b58e2512..0e1de802 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-067c196640a741dab4cb6da2b4a0915162424df6
\ No newline at end of file
+08231b5cfcc6bf626e339bcd392dc60030c0cce9
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index cf4ad05..5cb6ecf 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-3de3704a6db153486dbc1262118ddd21fea92459
\ No newline at end of file
+db7f99ec0e8be84264987aee16e00ee742acd6f7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index 96e8200..ab0770a 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-d77e5ef602d32b9b74b748bb63fdf22d9a0287f2
\ No newline at end of file
+3b073ba44b95d26fddec63e1bf54c094706417ae
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index 7db03ba3..c814bc8 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-7d4fcb3e717d33571892f13db411e95c120934b8
\ No newline at end of file
+a91bcd1940b6fd83cf4fba0d6efaf7c23999ade1
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index 9d8bc07..9986c5fe 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-57116b2c937a0d7e87b98122ed29232b7c9dd67c
\ No newline at end of file
+cfd923854276c326efb9b9433519868821732ce9
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index 336661c..a1752d6 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-3024836caaca914302dabc336c40d2a977ae4b70
\ No newline at end of file
+2381819067235ba5afd80f242ce3d0afabe9f6c0
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index 75b8ecf..e39aa149 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-24e5b4482d320aaedc0fedbcd76ea86d9c226e10
\ No newline at end of file
+a8870b3aae35cde35500e8b8ca471c3f0d8ee50f
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index ef91f74..a8bcb9c 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-891ee0a6780f7cf9718b563292f8e967cd4243ae
\ No newline at end of file
+3966205024f0f6de6a9dbf1ab280cb4b23744801
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index 1bab6de..5004fa03 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-7b070dca4feb7b21c144037e51b37a0ee8576667
\ No newline at end of file
+d49e5ede85d8340f4ceed8bede1bf9059f8fadc0
\ No newline at end of file
diff --git a/ios/web/find_in_page/java_script_find_in_page_manager_impl.h b/ios/web/find_in_page/java_script_find_in_page_manager_impl.h
index fe493e3..0c720a1 100644
--- a/ios/web/find_in_page/java_script_find_in_page_manager_impl.h
+++ b/ios/web/find_in_page/java_script_find_in_page_manager_impl.h
@@ -11,6 +11,7 @@
 #import "base/values.h"
 #import "ios/web/find_in_page/java_script_find_in_page_request.h"
 #import "ios/web/public/find_in_page/java_script_find_in_page_manager.h"
+#import "ios/web/public/js_messaging/web_frames_manager.h"
 #include "ios/web/public/web_state_observer.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -22,7 +23,8 @@
 class WebFrame;
 
 class JavaScriptFindInPageManagerImpl : public JavaScriptFindInPageManager,
-                                        public web::WebStateObserver {
+                                        public WebFramesManager::Observer,
+                                        public WebStateObserver {
  public:
   explicit JavaScriptFindInPageManagerImpl(web::WebState* web_state);
   ~JavaScriptFindInPageManagerImpl() override;
@@ -66,11 +68,13 @@
   // currently selected match.
   void SelectCurrentMatch();
 
+  // WebFramesManager::Observer
+  void WebFrameBecameAvailable(WebFramesManager* web_frames_manager,
+                               WebFrame* web_frame) override;
+  void WebFrameBecameUnavailable(WebFramesManager* web_frames_manager,
+                                 const std::string& frame_id) override;
+
   // WebStateObserver overrides
-  void WebFrameDidBecomeAvailable(WebState* web_state,
-                                  WebFrame* web_frame) override;
-  void WebFrameWillBecomeUnavailable(WebState* web_state,
-                                     WebFrame* web_frame) override;
   void WebStateDestroyed(WebState* web_state) override;
 
  protected:
diff --git a/ios/web/find_in_page/java_script_find_in_page_manager_impl.mm b/ios/web/find_in_page/java_script_find_in_page_manager_impl.mm
index c2e7206..79f7ba4 100644
--- a/ios/web/find_in_page/java_script_find_in_page_manager_impl.mm
+++ b/ios/web/find_in_page/java_script_find_in_page_manager_impl.mm
@@ -31,6 +31,10 @@
     WebState* web_state)
     : web_state_(web_state), weak_factory_(this) {
   web_state_->AddObserver(this);
+  web::WebFramesManager* web_frames_manager =
+      FindInPageJavaScriptFeature::GetInstance()->GetWebFramesManager(
+          web_state);
+  web_frames_manager->AddObserver(this);
 }
 
 void JavaScriptFindInPageManagerImpl::CreateForWebState(WebState* web_state) {
@@ -57,19 +61,18 @@
   delegate_ = delegate;
 }
 
-void JavaScriptFindInPageManagerImpl::WebFrameDidBecomeAvailable(
-    WebState* web_state,
+void JavaScriptFindInPageManagerImpl::WebFrameBecameAvailable(
+    WebFramesManager* web_frames_manager,
     WebFrame* web_frame) {
   const std::string frame_id = web_frame->GetFrameId();
   last_find_request_.AddFrame(web_frame);
 }
 
-void JavaScriptFindInPageManagerImpl::WebFrameWillBecomeUnavailable(
-    WebState* web_state,
-    WebFrame* web_frame) {
-  int match_count =
-      last_find_request_.GetMatchCountForFrame(web_frame->GetFrameId());
-  last_find_request_.RemoveFrame(web_frame->GetFrameId());
+void JavaScriptFindInPageManagerImpl::WebFrameBecameUnavailable(
+    WebFramesManager* web_frames_manager,
+    const std::string& frame_id) {
+  int match_count = last_find_request_.GetMatchCountForFrame(frame_id);
+  last_find_request_.RemoveFrame(frame_id);
 
   // Only notify the delegate if the match count has changed.
   if (delegate_ && last_find_request_.GetRequestQuery() && match_count > 0) {
@@ -103,9 +106,15 @@
 }
 
 void JavaScriptFindInPageManagerImpl::StartSearch(NSString* query) {
+  if (!web_state_) {
+    return;
+  }
+
   RecordSearchStartedAction();
-  std::set<WebFrame*> all_frames =
-      web_state_->GetPageWorldWebFramesManager()->GetAllWebFrames();
+  WebFramesManager* frames_manager =
+      FindInPageJavaScriptFeature::GetInstance()->GetWebFramesManager(
+          web_state_);
+  std::set<WebFrame*> all_frames = frames_manager->GetAllWebFrames();
   last_find_request_.Reset(query, all_frames.size());
   if (all_frames.size() == 0) {
     // No frames to search in.
@@ -143,11 +152,19 @@
 }
 
 void JavaScriptFindInPageManagerImpl::StopFinding() {
+  if (!web_state_) {
+    return;
+  }
+
   last_find_request_.Reset(/*new_query=*/nil,
                            /*new_pending_frame_call_count=*/0);
 
-  for (WebFrame* frame :
-       web_state_->GetPageWorldWebFramesManager()->GetAllWebFrames()) {
+  WebFramesManager* frames_manager =
+      FindInPageJavaScriptFeature::GetInstance()->GetWebFramesManager(
+          web_state_);
+  std::set<WebFrame*> all_frames = frames_manager->GetAllWebFrames();
+
+  for (WebFrame* frame : all_frames) {
     FindInPageJavaScriptFeature::GetInstance()->Stop(frame);
   }
   if (delegate_) {
@@ -174,7 +191,10 @@
     return;
   }
 
-  WebFrame* frame = GetWebFrameWithId(web_state_, frame_id);
+  FindInPageJavaScriptFeature* feature =
+      FindInPageJavaScriptFeature::GetInstance();
+  WebFrame* frame =
+      feature->GetWebFramesManager(web_state_)->GetFrameWithId(frame_id);
   if (!result_matches || !frame) {
     // The frame no longer exists or the function call timed out. In both cases,
     // result will be null.
@@ -184,7 +204,7 @@
     // If response is equal to kFindInPagePending, find did not finish in the
     // JavaScript. Call pumpSearch to continue find.
     if (result_matches.value() == find_in_page::kFindInPagePending) {
-      FindInPageJavaScriptFeature::GetInstance()->Pump(
+      feature->Pump(
           frame, base::BindOnce(
                      &JavaScriptFindInPageManagerImpl::ProcessFindInPageResult,
                      weak_factory_.GetWeakPtr(), frame_id, unique_id));
@@ -282,10 +302,14 @@
 }
 
 void JavaScriptFindInPageManagerImpl::SelectCurrentMatch() {
-  web::WebFrame* frame =
-      GetWebFrameWithId(web_state_, last_find_request_.GetSelectedFrameId());
+  FindInPageJavaScriptFeature* feature =
+      FindInPageJavaScriptFeature::GetInstance();
+  WebFrame* frame =
+      feature->GetWebFramesManager(web_state_)
+          ->GetFrameWithId(last_find_request_.GetSelectedFrameId());
+
   if (frame) {
-    FindInPageJavaScriptFeature::GetInstance()->SelectMatch(
+    feature->SelectMatch(
         frame, last_find_request_.GetCurrentSelectedMatchFrameIndex(),
         base::BindOnce(&JavaScriptFindInPageManagerImpl::SelectDidFinish,
                        weak_factory_.GetWeakPtr()));
diff --git a/ios/web/find_in_page/java_script_find_in_page_manager_impl_unittest.mm b/ios/web/find_in_page/java_script_find_in_page_manager_impl_unittest.mm
index ccd6fbd..6fd3b3af 100644
--- a/ios/web/find_in_page/java_script_find_in_page_manager_impl_unittest.mm
+++ b/ios/web/find_in_page/java_script_find_in_page_manager_impl_unittest.mm
@@ -39,14 +39,18 @@
   void SetUp() override {
     WebTest::SetUp();
 
+    FindInPageJavaScriptFeature* feature =
+        FindInPageJavaScriptFeature::GetInstance();
+
     fake_web_state_ = std::make_unique<FakeWebState>();
     fake_web_state_->SetBrowserState(GetBrowserState());
     auto frames_manager = std::make_unique<FakeWebFramesManager>();
     fake_web_frames_manager_ = frames_manager.get();
-    fake_web_state_->SetWebFramesManager(std::move(frames_manager));
+    fake_web_state_->SetWebFramesManager(feature->GetSupportedContentWorld(),
+                                         std::move(frames_manager));
 
     JavaScriptFeatureManager::FromBrowserState(GetBrowserState())
-        ->ConfigureFeatures({FindInPageJavaScriptFeature::GetInstance()});
+        ->ConfigureFeatures({feature});
     JavaScriptFindInPageManagerImpl::CreateForWebState(fake_web_state_.get());
     GetFindInPageManager()->SetDelegate(&fake_delegate_);
   }
diff --git a/ios/web/find_in_page/java_script_find_in_page_manager_inttest.mm b/ios/web/find_in_page/java_script_find_in_page_manager_inttest.mm
index 4ef40c8..bf30d13 100644
--- a/ios/web/find_in_page/java_script_find_in_page_manager_inttest.mm
+++ b/ios/web/find_in_page/java_script_find_in_page_manager_inttest.mm
@@ -56,6 +56,11 @@
     return web::JavaScriptFindInPageManager::FromWebState(web_state());
   }
 
+  WebFramesManager* GetWebFramesManager() {
+    return FindInPageJavaScriptFeature::GetInstance()->GetWebFramesManager(
+        web_state());
+  }
+
   // Waits until the delegate receives `index` from
   // DidSelectMatch(). Returns False if delegate never receives `index` within
   // time.
@@ -80,10 +85,7 @@
   test::LoadUrl(web_state(), test_server_.GetURL(url_spec));
 
   ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
-    return web_state()
-               ->GetPageWorldWebFramesManager()
-               ->GetAllWebFrames()
-               .size() == 2;
+    return GetWebFramesManager()->GetAllWebFrames().size() == 2;
   }));
 
   GetFindInPageManager()->Find(@"Main frame text",
@@ -104,10 +106,7 @@
       base::EscapeQueryParamValue(kFindInPageIFrameUrl, /*use_plus=*/true);
   test::LoadUrl(web_state(), test_server_.GetURL(url_spec));
   ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
-    return web_state()
-               ->GetPageWorldWebFramesManager()
-               ->GetAllWebFrames()
-               .size() == 2;
+    return GetWebFramesManager()->GetAllWebFrames().size() == 2;
   }));
 
   GetFindInPageManager()->Find(@"frame", FindInPageOptions::FindInPageSearch);
@@ -127,10 +126,7 @@
       base::EscapeQueryParamValue(kFindInPageIFrameUrl, /*use_plus=*/true);
   test::LoadUrl(web_state(), test_server_.GetURL(url_spec));
   ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
-    return web_state()
-               ->GetPageWorldWebFramesManager()
-               ->GetAllWebFrames()
-               .size() == 2;
+    return GetWebFramesManager()->GetAllWebFrames().size() == 2;
   }));
 
   GetFindInPageManager()->Find(@"foobar", FindInPageOptions::FindInPageSearch);
@@ -150,10 +146,7 @@
       base::EscapeQueryParamValue(kFindInPageIFrameUrl, /*use_plus=*/true);
   test::LoadUrl(web_state(), test_server_.GetURL(url_spec));
   ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
-    return web_state()
-               ->GetPageWorldWebFramesManager()
-               ->GetAllWebFrames()
-               .size() == 2;
+    return GetWebFramesManager()->GetAllWebFrames().size() == 2;
   }));
 
   GetFindInPageManager()->Find(@"frame", FindInPageOptions::FindInPageSearch);
@@ -182,10 +175,7 @@
       base::EscapeQueryParamValue(kFindInPageIFrameUrl, /*use_plus=*/true);
   test::LoadUrl(web_state(), test_server_.GetURL(url_spec));
   ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
-    return web_state()
-               ->GetPageWorldWebFramesManager()
-               ->GetAllWebFrames()
-               .size() == 2;
+    return GetWebFramesManager()->GetAllWebFrames().size() == 2;
   }));
 
   GetFindInPageManager()->Find(@"frame", FindInPageOptions::FindInPageSearch);
@@ -213,10 +203,7 @@
       base::EscapeQueryParamValue(kFindInPageIFrameUrl, /*use_plus=*/true);
   test::LoadUrl(web_state(), test_server_.GetURL(url_spec));
   ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
-    return web_state()
-               ->GetPageWorldWebFramesManager()
-               ->GetAllWebFrames()
-               .size() == 2;
+    return GetWebFramesManager()->GetAllWebFrames().size() == 2;
   }));
 
   GetFindInPageManager()->Find(@"iframe", FindInPageOptions::FindInPageSearch);
@@ -241,10 +228,7 @@
       base::EscapeQueryParamValue(kFindInPageIFrameUrl, /*use_plus=*/true);
   test::LoadUrl(web_state(), test_server_.GetURL(url_spec));
   ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
-    return web_state()
-               ->GetPageWorldWebFramesManager()
-               ->GetAllWebFrames()
-               .size() == 2;
+    return GetWebFramesManager()->GetAllWebFrames().size() == 2;
   }));
 
   GetFindInPageManager()->Find(@"iframe", FindInPageOptions::FindInPageSearch);
diff --git a/ios/web/js_messaging/web_frame_util.mm b/ios/web/js_messaging/web_frame_util.mm
index 862f667..3c5fabd 100644
--- a/ios/web/js_messaging/web_frame_util.mm
+++ b/ios/web/js_messaging/web_frame_util.mm
@@ -18,20 +18,6 @@
   return web_state->GetPageWorldWebFramesManager()->GetMainWebFrame();
 }
 
-std::string GetMainWebFrameId(WebState* web_state) {
-  WebFrame* main_frame = GetMainFrame(web_state);
-  if (!main_frame) {
-    return std::string();
-  }
-  return main_frame->GetFrameId();
-}
-
-WebFrame* GetWebFrameWithId(WebState* web_state, const std::string& frame_id) {
-  if (frame_id.empty())
-    return nullptr;
-  return web_state->GetPageWorldWebFramesManager()->GetFrameWithId(frame_id);
-}
-
 std::string GetWebFrameId(WebFrame* frame) {
   return frame ? frame->GetFrameId() : std::string();
 }
diff --git a/ios/web/js_messaging/web_frame_util_unittest.mm b/ios/web/js_messaging/web_frame_util_unittest.mm
index df6c7f5..794405115c 100644
--- a/ios/web/js_messaging/web_frame_util_unittest.mm
+++ b/ios/web/js_messaging/web_frame_util_unittest.mm
@@ -50,65 +50,6 @@
   EXPECT_EQ(nullptr, GetMainFrame(&fake_web_state_));
 }
 
-// Tests the GetMainWebFrameId function.
-TEST_F(WebFrameUtilTest, GetMainWebFrameId) {
-  // Still no main frame.
-  EXPECT_TRUE(GetMainWebFrameId(&fake_web_state_).empty());
-  auto iframe = FakeWebFrame::CreateChildWebFrame(GURL::EmptyGURL());
-  fake_web_frames_manager_->AddWebFrame(std::move(iframe));
-  // Still no main frame.
-  EXPECT_TRUE(GetMainWebFrameId(&fake_web_state_).empty());
-
-  auto main_frame = FakeWebFrame::CreateMainWebFrame(GURL::EmptyGURL());
-  FakeWebFrame* main_frame_ptr = main_frame.get();
-  fake_web_frames_manager_->AddWebFrame(std::move(main_frame));
-  // Now there is a main frame.
-  EXPECT_EQ(kMainFakeFrameId, GetMainWebFrameId(&fake_web_state_));
-
-  fake_web_frames_manager_->RemoveWebFrame(main_frame_ptr->GetFrameId());
-  // Now there is no main frame.
-  EXPECT_TRUE(GetMainWebFrameId(&fake_web_state_).empty());
-}
-
-// Tests the GetWebFrameWithId function.
-TEST_F(WebFrameUtilTest, GetWebFrameWithId) {
-  // Still no main frame.
-  EXPECT_EQ(nullptr, GetWebFrameWithId(&fake_web_state_, kChildFakeFrameId));
-  EXPECT_EQ(nullptr, GetWebFrameWithId(&fake_web_state_, kMainFakeFrameId));
-  EXPECT_EQ(nullptr, GetWebFrameWithId(&fake_web_state_, "unused"));
-  auto iframe = FakeWebFrame::CreateChildWebFrame(GURL::EmptyGURL());
-  FakeWebFrame* iframe_ptr = iframe.get();
-  fake_web_frames_manager_->AddWebFrame(std::move(iframe));
-  // There is an iframe.
-  EXPECT_EQ(iframe_ptr, GetWebFrameWithId(&fake_web_state_, kChildFakeFrameId));
-  EXPECT_EQ(nullptr, GetWebFrameWithId(&fake_web_state_, kMainFakeFrameId));
-  EXPECT_EQ(nullptr, GetWebFrameWithId(&fake_web_state_, "unused"));
-
-  auto main_frame = FakeWebFrame::CreateMainWebFrame(GURL::EmptyGURL());
-  FakeWebFrame* main_frame_ptr = main_frame.get();
-  fake_web_frames_manager_->AddWebFrame(std::move(main_frame));
-  // Now there is a main frame.
-  EXPECT_EQ(iframe_ptr, GetWebFrameWithId(&fake_web_state_, kChildFakeFrameId));
-  EXPECT_EQ(main_frame_ptr,
-            GetWebFrameWithId(&fake_web_state_, kMainFakeFrameId));
-  EXPECT_EQ(nullptr, GetWebFrameWithId(&fake_web_state_, "unused"));
-
-  fake_web_frames_manager_->RemoveWebFrame(main_frame_ptr->GetFrameId());
-  // Now there is only an iframe.
-  EXPECT_EQ(iframe_ptr, GetWebFrameWithId(&fake_web_state_, kChildFakeFrameId));
-  EXPECT_EQ(nullptr, GetWebFrameWithId(&fake_web_state_, kMainFakeFrameId));
-  EXPECT_EQ(nullptr, GetWebFrameWithId(&fake_web_state_, "unused"));
-
-  // Now there nothing left.
-  fake_web_frames_manager_->RemoveWebFrame(iframe_ptr->GetFrameId());
-  EXPECT_EQ(nullptr, GetWebFrameWithId(&fake_web_state_, kChildFakeFrameId));
-  EXPECT_EQ(nullptr, GetWebFrameWithId(&fake_web_state_, kMainFakeFrameId));
-  EXPECT_EQ(nullptr, GetWebFrameWithId(&fake_web_state_, "unused"));
-
-  // Test that GetWebFrameWithId returns nullptr for the empty string.
-  EXPECT_EQ(nullptr, GetWebFrameWithId(&fake_web_state_, ""));
-}
-
 // Tests the GetWebFrameId GetWebFrameId function.
 TEST_F(WebFrameUtilTest, GetWebFrameId) {
   EXPECT_EQ(std::string(), GetWebFrameId(nullptr));
diff --git a/ios/web/navigation/navigation_java_script_feature.mm b/ios/web/navigation/navigation_java_script_feature.mm
index 9d29b89..fe009ba 100644
--- a/ios/web/navigation/navigation_java_script_feature.mm
+++ b/ios/web/navigation/navigation_java_script_feature.mm
@@ -7,7 +7,8 @@
 #import "base/no_destructor.h"
 #import "ios/web/public/js_messaging/java_script_feature_util.h"
 #import "ios/web/public/js_messaging/script_message.h"
-#import "ios/web/public/js_messaging/web_frame_util.h"
+#import "ios/web/public/js_messaging/web_frame.h"
+#import "ios/web/public/js_messaging/web_frames_manager.h"
 #import "ios/web/web_state/ui/crw_web_controller.h"
 #import "ios/web/web_state/web_state_impl.h"
 
@@ -77,7 +78,9 @@
     return;
   }
 
-  std::string main_frame_id = GetMainWebFrameId(web_state);
+  WebFrame* main_frame =
+      web_state->GetPageWorldWebFramesManager()->GetMainWebFrame();
+  std::string main_frame_id = main_frame ? main_frame->GetFrameId() : "";
   if (main_frame_id != *frame_id) {
     // Frame has changed, do not send message to the web controller as it would
     // update the incorrect navigation item.
diff --git a/ios/web/public/js_messaging/web_frame_util.h b/ios/web/public/js_messaging/web_frame_util.h
index 19dff69..7e15df4 100644
--- a/ios/web/public/js_messaging/web_frame_util.h
+++ b/ios/web/public/js_messaging/web_frame_util.h
@@ -15,14 +15,6 @@
 // Returns the main WebFrame in `web_state`.
 WebFrame* GetMainFrame(WebState* web_state);
 
-// Returns the ID of the main WebFrame in `web_state`.
-// Returns "" if `web_state` does not have a main frame.
-std::string GetMainWebFrameId(WebState* web_state);
-
-// Returns the frame with ID `frame_id` in `web_state`.
-// Returns nullptr if `web_state` does not have a frame with this ID.
-WebFrame* GetWebFrameWithId(WebState* web_state, const std::string& frame_id);
-
 // Returns the ID of `frame`. Returns std::string() if `frame` is nullptr.
 std::string GetWebFrameId(WebFrame* frame);
 
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index ef7cabb..1c84f7d 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -68,6 +68,7 @@
   "public/cwv_metrics_provider.h",
   "public/cwv_navigation_action.h",
   "public/cwv_navigation_delegate.h",
+  "public/cwv_navigation_response.h",
   "public/cwv_navigation_type.h",
   "public/cwv_password.h",
   "public/cwv_preferences.h",
@@ -144,6 +145,8 @@
   "internal/cwv_lookalike_url_handler_internal.h",
   "internal/cwv_navigation_action.mm",
   "internal/cwv_navigation_action_internal.h",
+  "internal/cwv_navigation_response.mm",
+  "internal/cwv_navigation_response_internal.h",
   "internal/cwv_navigation_type.mm",
   "internal/cwv_navigation_type_internal.h",
   "internal/cwv_preferences.mm",
diff --git a/ios/web_view/internal/cwv_navigation_action.mm b/ios/web_view/internal/cwv_navigation_action.mm
index f800e5b..a70c5d0 100644
--- a/ios/web_view/internal/cwv_navigation_action.mm
+++ b/ios/web_view/internal/cwv_navigation_action.mm
@@ -11,13 +11,16 @@
 @implementation CWVNavigationAction
 @synthesize request = _request;
 @synthesize userInitiated = _userInitiated;
+@synthesize navigationType = _navigationType;
 
 - (instancetype)initWithRequest:(NSURLRequest*)request
-                  userInitiated:(BOOL)userInitiated {
+                  userInitiated:(BOOL)userInitiated
+                 navigationType:(CWVNavigationType)navigationType {
   self = [super init];
   if (self) {
     _userInitiated = userInitiated;
     _request = [request copy];
+    _navigationType = navigationType;
   }
   return self;
 }
diff --git a/ios/web_view/internal/cwv_navigation_action_internal.h b/ios/web_view/internal/cwv_navigation_action_internal.h
index 264a0faeb..a1b7727a 100644
--- a/ios/web_view/internal/cwv_navigation_action_internal.h
+++ b/ios/web_view/internal/cwv_navigation_action_internal.h
@@ -15,6 +15,7 @@
 
 - (nonnull instancetype)initWithRequest:(NSURLRequest*)request
                           userInitiated:(BOOL)userInitiated
+                         navigationType:(CWVNavigationType)navigationType
     NS_DESIGNATED_INITIALIZER;
 
 @end
diff --git a/ios/web_view/internal/cwv_navigation_response.mm b/ios/web_view/internal/cwv_navigation_response.mm
new file mode 100644
index 0000000..0b01254
--- /dev/null
+++ b/ios/web_view/internal/cwv_navigation_response.mm
@@ -0,0 +1,25 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web_view/internal/cwv_navigation_response_internal.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation CWVNavigationResponse
+@synthesize response = _response;
+@synthesize forMainFrame = _forMainFrame;
+
+- (instancetype)initWithResponse:(NSURLResponse*)response
+                    forMainFrame:(BOOL)forMainFrame {
+  self = [super init];
+  if (self) {
+    _response = response;
+    _forMainFrame = forMainFrame;
+  }
+  return self;
+}
+
+@end
diff --git a/ios/web_view/internal/cwv_navigation_response_internal.h b/ios/web_view/internal/cwv_navigation_response_internal.h
new file mode 100644
index 0000000..36e7865
--- /dev/null
+++ b/ios/web_view/internal/cwv_navigation_response_internal.h
@@ -0,0 +1,24 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_VIEW_INTERNAL_CWV_NAVIGATION_RESPONSE_INTERNAL_H_
+#define IOS_WEB_VIEW_INTERNAL_CWV_NAVIGATION_RESPONSE_INTERNAL_H_
+
+#import "ios/web_view/public/cwv_navigation_response.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CWVNavigationResponse ()
+
+- (nonnull instancetype)init NS_UNAVAILABLE;
+
+- (nonnull instancetype)initWithResponse:(NSURLResponse*)response
+                            forMainFrame:(BOOL)forMainFrame
+    NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif  // IOS_WEB_VIEW_INTERNAL_CWV_NAVIGATION_RESPONSE_INTERNAL_H_
diff --git a/ios/web_view/internal/cwv_web_view.mm b/ios/web_view/internal/cwv_web_view.mm
index a0aab9b..dd76614 100644
--- a/ios/web_view/internal/cwv_web_view.mm
+++ b/ios/web_view/internal/cwv_web_view.mm
@@ -538,9 +538,15 @@
 
   NSURLRequest* request =
       [[NSURLRequest alloc] initWithURL:net::NSURLWithGURL(URL)];
+
+  // The current implemention can't get the real navigation type for the
+  // navigation action which causes a new web view be created. So uses
+  // `CWVNavigationTypeNewWindow` before the real navigation type can be gotten
+  // here.
   CWVNavigationAction* navigationAction =
       [[CWVNavigationAction alloc] initWithRequest:request
-                                     userInitiated:initiatedByUser];
+                                     userInitiated:initiatedByUser
+                                    navigationType:CWVNavigationTypeNewWindow];
   CWVWebView* webView = [_UIDelegate webView:self
               createWebViewWithConfiguration:_configuration
                          forNavigationAction:navigationAction];
diff --git a/ios/web_view/internal/web_view_web_state_policy_decider.h b/ios/web_view/internal/web_view_web_state_policy_decider.h
index 561f78c..b7339b63 100644
--- a/ios/web_view/internal/web_view_web_state_policy_decider.h
+++ b/ios/web_view/internal/web_view_web_state_policy_decider.h
@@ -18,8 +18,15 @@
 namespace ios_web_view {
 
 // An implementation of web::WebStatePolicyDecider which delegates to:
+// DEPRECATED:
 //   [web_view.navigationDelegate webView:shouldStartLoadWithRequest:]
 //   [web_view.navigationDelegate webView:shouldContinueLoadWithResponse:]
+//
+// RECOMMENDED:
+//   [web_view.navigationDelegate
+//   webView:decidePolicyForNavigationAction:decisionHandler:]
+//   [web_view.navigationDelegate
+//   webView:decidePolicyForNavigationResponse:decisionHandler:]
 class WebViewWebStatePolicyDecider : public web::WebStatePolicyDecider {
  public:
   WebViewWebStatePolicyDecider(web::WebState* web_state, CWVWebView* web_view);
diff --git a/ios/web_view/internal/web_view_web_state_policy_decider.mm b/ios/web_view/internal/web_view_web_state_policy_decider.mm
index 23f4d1cb..86a080d 100644
--- a/ios/web_view/internal/web_view_web_state_policy_decider.mm
+++ b/ios/web_view/internal/web_view_web_state_policy_decider.mm
@@ -4,6 +4,8 @@
 
 #import "ios/web_view/internal/web_view_web_state_policy_decider.h"
 
+#import "ios/web_view/internal/cwv_navigation_action_internal.h"
+#import "ios/web_view/internal/cwv_navigation_response_internal.h"
 #import "ios/web_view/internal/cwv_navigation_type_internal.h"
 #import "ios/web_view/public/cwv_navigation_delegate.h"
 #import "ios/web_view/public/cwv_web_view.h"
@@ -24,14 +26,48 @@
     web::WebStatePolicyDecider::RequestInfo request_info,
     web::WebStatePolicyDecider::PolicyDecisionCallback callback) {
   id<CWVNavigationDelegate> delegate = web_view_.navigationDelegate;
+
+  // CWVNavigationType is virtually the same as ui::PageTransition. But
+  // ui::PageTransition must not be used in the public API of //ios/web_view
+  // because its API must be in pure Objective-C. It cannot use a type defined
+  // in a C++ header //ui/base/page_transition_types.h.
+  CWVNavigationType navigation_type =
+      CWVNavigationTypeFromPageTransition(request_info.transition_type);
+
+  if ([delegate respondsToSelector:@selector
+                (webView:decidePolicyForNavigationAction:decisionHandler:)]) {
+    CWVNavigationAction* navigation_action = [[CWVNavigationAction alloc]
+        initWithRequest:request
+          userInitiated:request_info.has_user_gesture
+         navigationType:navigation_type];
+
+    __block web::WebStatePolicyDecider::PolicyDecisionCallback block_callback =
+        std::move(callback);
+
+    [delegate webView:web_view_
+        decidePolicyForNavigationAction:navigation_action
+                        decisionHandler:^(CWVNavigationActionPolicy policy) {
+                          switch (policy) {
+                            case CWVNavigationActionPolicyCancel:
+                              std::move(block_callback)
+                                  .Run(web::WebStatePolicyDecider::
+                                           PolicyDecision::Cancel());
+                              break;
+                            case CWVNavigationActionPolicyAllow:
+                              std::move(block_callback)
+                                  .Run(web::WebStatePolicyDecider::
+                                           PolicyDecision::Allow());
+                              break;
+                          }
+                        }];
+    return;
+  }
+
+  // Deprected API, will consider using asynchronous API
+  // `-[CWVNavigationDelegate
+  // webView:decidePolicyForNavigationAction:decisionHandler:]` first.
   if ([delegate respondsToSelector:@selector
                 (webView:shouldStartLoadWithRequest:navigationType:)]) {
-    // CWVNavigationType is virtually the same as ui::PageTransition. But
-    // ui::PageTransition must not be used in the public API of //ios/web_view
-    // because its API must be in pure Objective-C. It cannot use a type defined
-    // in a C++ header //ui/base/page_transition_types.h.
-    CWVNavigationType navigation_type =
-        CWVNavigationTypeFromPageTransition(request_info.transition_type);
     BOOL allow = [delegate webView:web_view_
         shouldStartLoadWithRequest:request
                     navigationType:navigation_type];
@@ -40,6 +76,7 @@
           web::WebStatePolicyDecider::PolicyDecision::Cancel());
     }
   }
+
   std::move(callback).Run(web::WebStatePolicyDecider::PolicyDecision::Allow());
 }
 
@@ -49,6 +86,39 @@
     web::WebStatePolicyDecider::PolicyDecisionCallback callback) {
   id<CWVNavigationDelegate> delegate = web_view_.navigationDelegate;
   if ([delegate respondsToSelector:@selector
+                (webView:decidePolicyForNavigationResponse:decisionHandler:)]) {
+    CWVNavigationResponse* cwv_navigation_response =
+        [[CWVNavigationResponse alloc]
+            initWithResponse:response
+                forMainFrame:response_info.for_main_frame];
+
+    __block web::WebStatePolicyDecider::PolicyDecisionCallback block_callback =
+        std::move(callback);
+
+    [delegate webView:web_view_
+        decidePolicyForNavigationResponse:cwv_navigation_response
+                          decisionHandler:^(
+                              CWVNavigationResponsePolicy policy) {
+                            switch (policy) {
+                              case CWVNavigationResponsePolicyCancel:
+                                std::move(block_callback)
+                                    .Run(web::WebStatePolicyDecider::
+                                             PolicyDecision::Cancel());
+                                break;
+                              case CWVNavigationResponsePolicyAllow:
+                                std::move(block_callback)
+                                    .Run(web::WebStatePolicyDecider::
+                                             PolicyDecision::Allow());
+                                break;
+                            }
+                          }];
+    return;
+  }
+
+  // Deprected API, will consider using asynchronous API
+  // `-[CWVNavigationDelegate
+  // webView:decidePolicyForNavigationResponse:decisionHandler:]` first.
+  if ([delegate respondsToSelector:@selector
                 (webView:shouldContinueLoadWithResponse:forMainFrame:)]) {
     BOOL allow = [delegate webView:web_view_
         shouldContinueLoadWithResponse:response
@@ -58,6 +128,7 @@
           web::WebStatePolicyDecider::PolicyDecision::Cancel());
     };
   }
+
   std::move(callback).Run(web::WebStatePolicyDecider::PolicyDecision::Allow());
 }
 
diff --git a/ios/web_view/public/cwv_defines.h b/ios/web_view/public/cwv_defines.h
index 268d487..92f39555 100644
--- a/ios/web_view/public/cwv_defines.h
+++ b/ios/web_view/public/cwv_defines.h
@@ -76,4 +76,10 @@
 // -[CWVUserContentController removeMessageHandlerForCommand] APIs.
 #define IOS_WEB_VIEW_SUPPORTS_USER_CONTENT_CONTROLLER_MESSAGE_HANDLERS 1
 
+// Supports -[CWVNavigationDelegate
+// webView:decidePolicyForNavigationAction:decisionHandler:] and
+// -[CWVNavigationDelegate
+// webView:decidePolicyForNavigationResponse:decisionHandler:] APIs.
+#define IOS_WEB_VIEW_SUPPORTS_ASYNCCHRONOUS_POLICY_DECISION_HANDLER 1
+
 #endif  // IOS_WEB_VIEW_PUBLIC_CWV_DEFINES_H_
diff --git a/ios/web_view/public/cwv_navigation_action.h b/ios/web_view/public/cwv_navigation_action.h
index def82f596..a983e04 100644
--- a/ios/web_view/public/cwv_navigation_action.h
+++ b/ios/web_view/public/cwv_navigation_action.h
@@ -8,6 +8,7 @@
 #import <Foundation/Foundation.h>
 
 #import "cwv_export.h"
+#import "cwv_navigation_type.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
@@ -19,6 +20,8 @@
 @property(nonatomic, copy, readonly) NSURLRequest* request;
 // YES if the action was caused by a user action (e.g. link tap).
 @property(nonatomic, readonly, getter=isUserInitiated) BOOL userInitiated;
+// The type of action that triggered the navigation.
+@property(nonatomic, readonly) CWVNavigationType navigationType;
 
 @end
 
diff --git a/ios/web_view/public/cwv_navigation_delegate.h b/ios/web_view/public/cwv_navigation_delegate.h
index 0d6bda1..0ebe5c3 100644
--- a/ios/web_view/public/cwv_navigation_delegate.h
+++ b/ios/web_view/public/cwv_navigation_delegate.h
@@ -14,28 +14,66 @@
 
 @class CWVDownloadTask;
 @class CWVLookalikeURLHandler;
+@class CWVNavigationAction;
+@class CWVNavigationResponse;
 @class CWVSSLErrorHandler;
 @class CWVUnsafeURLHandler;
 @class CWVWebView;
 
+typedef NS_ENUM(NSInteger, CWVNavigationActionPolicy) {
+  // Cancel the navigation
+  CWVNavigationActionPolicyCancel,
+  // Allow the navigation to continue.
+  CWVNavigationActionPolicyAllow,
+};
+
+typedef NS_ENUM(NSInteger, CWVNavigationResponsePolicy) {
+  // Cancel the navigation
+  CWVNavigationResponsePolicyCancel,
+  // Allow the navigation to continue.
+  CWVNavigationResponsePolicyAllow,
+};
+
 // Navigation delegate protocol for CWVWebViews.  Allows embedders to hook
 // page loading and receive events for navigation.
 @protocol CWVNavigationDelegate<NSObject>
 @optional
 
-// Asks delegate if WebView should start the load. WebView will
-// load the request if this method is not implemented.
+// DEPRECATED: Use `-[CWVNavigationDelegate
+// webView:decidePolicyForNavigationAction:decisionHandler:]` instead, this
+// method will not work when recommended API is implemented.
+//
+// Asks delegate if WebView should start the load. WebView will load the request
+// if this method is not implemented.
 - (BOOL)webView:(CWVWebView*)webView
     shouldStartLoadWithRequest:(NSURLRequest*)request
                 navigationType:(CWVNavigationType)navigationType;
 
-// Asks delegate if WebView should continue the load. WebView
-// will load the response if this method is not implemented.
-// |forMainFrame| indicates whether the frame being navigated is the main frame.
+// DEPRECATED: Use `-[CWVNavigationDelegate
+// webView:decidePolicyForNavigationResponse:decisionHandler:]` instead, this
+// method will not work when recommended API is implemented.
+//
+// Asks delegate if WebView should continue the load. WebView will load the
+// response if this method is not implemented. `forMainFrame` indicates whether
+// the frame being navigated is the main frame.
 - (BOOL)webView:(CWVWebView*)webView
     shouldContinueLoadWithResponse:(NSURLResponse*)response
                       forMainFrame:(BOOL)forMainFrame;
 
+// Decides whether to allow or cancel a navigation. WebView will load the
+// response if this method is not implemented.
+- (void)webView:(CWVWebView*)webView
+    decidePolicyForNavigationAction:(CWVNavigationAction*)navigationAction
+                    decisionHandler:
+                        (void (^)(CWVNavigationActionPolicy))decisionHandler;
+
+// Decides whether to allow or cancel a navigation after its response is known.
+// WebView will load the response if this method is not implemented.
+- (void)webView:(CWVWebView*)webView
+    decidePolicyForNavigationResponse:(CWVNavigationResponse*)navigationResponse
+                      decisionHandler:(void (^)(CWVNavigationResponsePolicy))
+                                          decisionHandler;
+
 // Notifies the delegate that main frame navigation has started.
 // Deprecated, use |webViewDidStartNavigation| instead.
 - (void)webViewDidStartProvisionalNavigation:(CWVWebView*)webView;
diff --git a/ios/web_view/public/cwv_navigation_response.h b/ios/web_view/public/cwv_navigation_response.h
new file mode 100644
index 0000000..2e5e576
--- /dev/null
+++ b/ios/web_view/public/cwv_navigation_response.h
@@ -0,0 +1,30 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_VIEW_PUBLIC_CWV_NAVIGATION_RESPONSE_H_
+#define IOS_WEB_VIEW_PUBLIC_CWV_NAVIGATION_RESPONSE_H_
+
+#import <Foundation/Foundation.h>
+
+#import "cwv_export.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+// Contains information about a navigation response, used for making policy
+// decisions.
+CWV_EXPORT
+@interface CWVNavigationResponse : NSObject
+
+// A Boolean value indicating whether the frame being navigated is the main
+// frame.
+@property(nonatomic, readonly, getter=isForMainFrame) BOOL forMainFrame;
+
+// The frame's response.
+@property(nonatomic, readonly, copy) NSURLResponse* response;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif  // IOS_WEB_VIEW_PUBLIC_CWV_NAVIGATION_RESPONSE_H_
diff --git a/ios/web_view/public/cwv_navigation_type.h b/ios/web_view/public/cwv_navigation_type.h
index c14f5b4..dc2b4f8 100644
--- a/ios/web_view/public/cwv_navigation_type.h
+++ b/ios/web_view/public/cwv_navigation_type.h
@@ -86,8 +86,13 @@
   // KEYWORD for more details.
   CWVNavigationTypeKeywordGenerated = 10,
 
+  // Corresponds to a navigation causing the new web view to be created.
+  // It's only used in [web_view.UIDelegate
+  // webView:createWebViewWithConfiguration:forNavigationAction:]
+  CWVNavigationTypeNewWindow = 11,
+
   // ADDING NEW CORE VALUE? Be sure to update ui::PageTransition too.
-  CWVNavigationTypeLastCore = CWVNavigationTypeKeywordGenerated,
+  CWVNavigationTypeLastCore = CWVNavigationTypeNewWindow,
   CWVNavigationTypeCoreMask = 0xFF,
 
   // Qualifiers
diff --git a/ios/web_view/shell/shell_view_controller.m b/ios/web_view/shell/shell_view_controller.m
index 1c9a21a2..5d00996 100644
--- a/ios/web_view/shell/shell_view_controller.m
+++ b/ios/web_view/shell/shell_view_controller.m
@@ -1308,6 +1308,8 @@
 
 #pragma mark CWVNavigationDelegate methods
 
+// Deprecated: this method will not work when `-[CWVNavigationDelegate
+// webView:decidePolicyForNavigationAction:decisionHandler:]` is implemented
 - (BOOL)webView:(CWVWebView*)webView
     shouldStartLoadWithRequest:(NSURLRequest*)request
                 navigationType:(CWVNavigationType)navigationType {
@@ -1315,6 +1317,8 @@
   return YES;
 }
 
+// Deprecated: this method will not work when `-[CWVNavigationDelegate
+// webView:decidePolicyForNavigationResponse:decisionHandler:]` is implemented
 - (BOOL)webView:(CWVWebView*)webView
     shouldContinueLoadWithResponse:(NSURLResponse*)response
                       forMainFrame:(BOOL)forMainFrame {
@@ -1322,6 +1326,22 @@
   return YES;
 }
 
+- (void)webView:(CWVWebView*)webView
+    decidePolicyForNavigationAction:(CWVNavigationAction*)navigationAction
+                    decisionHandler:
+                        (void (^)(CWVNavigationActionPolicy))decisionHandler {
+  NSLog(@"%@", NSStringFromSelector(_cmd));
+  decisionHandler(CWVNavigationActionPolicyAllow);
+}
+
+- (void)webView:(CWVWebView*)webView
+    decidePolicyForNavigationResponse:(CWVNavigationResponse*)navigationResponse
+                      decisionHandler:(void (^)(CWVNavigationResponsePolicy))
+                                          decisionHandler {
+  NSLog(@"%@", NSStringFromSelector(_cmd));
+  decisionHandler(CWVNavigationResponsePolicyAllow);
+}
+
 - (void)webViewDidStartNavigation:(CWVWebView*)webView {
   NSLog(@"%@", NSStringFromSelector(_cmd));
   [self updateToolbar];
diff --git a/ios/web_view/test/navigation_delegate_inttest.mm b/ios/web_view/test/navigation_delegate_inttest.mm
index 5f8ff3ed..3399b9b5 100644
--- a/ios/web_view/test/navigation_delegate_inttest.mm
+++ b/ios/web_view/test/navigation_delegate_inttest.mm
@@ -42,12 +42,21 @@
     return net::NSURLWithGURL(test_server_->GetURL("/close-socket"));
   }
 
-  id ArgWithURL(NSURL* url) {
-    return [OCMArg checkWithBlock:^(id object) {
-      return [[object URL] isEqual:url];
+  id NavigationActionArg(NSURL* url, CWVNavigationType navigation_type) {
+    return [OCMArg checkWithBlock:^(CWVNavigationAction* navigation_action) {
+      return [navigation_action.request.URL isEqual:url] &&
+             navigation_action.navigationType == navigation_type;
     }];
   }
 
+  id NavigationResponseArg(NSURL* url, bool for_main_frame) {
+    return
+        [OCMArg checkWithBlock:^(CWVNavigationResponse* navigation_response) {
+          return [navigation_response.response.URL isEqual:url] &&
+                 navigation_response.forMainFrame == for_main_frame;
+        }];
+  }
+
   id<CWVNavigationDelegate> mock_delegate_;
 };
 
@@ -55,15 +64,30 @@
 TEST_F(NavigationDelegateTest, RequestSucceeds) {
   // A request made with -loadRequest: has type CWVNavigationTypeTyped.
   OCMExpect([mock_delegate_ webView:web_view_
-                shouldStartLoadWithRequest:ArgWithURL(GetEchoURL())
-                            navigationType:CWVNavigationTypeTyped])
-      .andReturn(YES);
+                decidePolicyForNavigationAction:NavigationActionArg(
+                                                    GetEchoURL(),
+                                                    CWVNavigationTypeTyped)
+                                decisionHandler:[OCMArg any]])
+      .andDo(^(NSInvocation* invocation) {
+        __weak void (^decisionHandler)(CWVNavigationActionPolicy);
+        [invocation getArgument:&decisionHandler atIndex:4];
+        if (decisionHandler) {
+          decisionHandler(CWVNavigationActionPolicyAllow);
+        }
+      });
   OCMExpect([mock_delegate_ webViewDidStartProvisionalNavigation:web_view_]);
   OCMExpect([mock_delegate_ webViewDidStartNavigation:web_view_]);
   OCMExpect([mock_delegate_ webView:web_view_
-                shouldContinueLoadWithResponse:ArgWithURL(GetEchoURL())
-                                  forMainFrame:YES])
-      .andReturn(YES);
+                decidePolicyForNavigationResponse:NavigationResponseArg(
+                                                      GetEchoURL(), YES)
+                                  decisionHandler:[OCMArg any]])
+      .andDo(^(NSInvocation* invocation) {
+        __weak void (^decisionHandler)(CWVNavigationResponsePolicy);
+        [invocation getArgument:&decisionHandler atIndex:4];
+        if (decisionHandler) {
+          decisionHandler(CWVNavigationResponsePolicyAllow);
+        }
+      });
   OCMExpect([mock_delegate_ webViewDidCommitNavigation:web_view_]);
   OCMExpect([mock_delegate_ webViewDidFinishNavigation:web_view_]);
 
@@ -74,9 +98,17 @@
 // Tests that expected delegate methods are called for a failed request.
 TEST_F(NavigationDelegateTest, RequestFails) {
   OCMExpect([mock_delegate_ webView:web_view_
-                shouldStartLoadWithRequest:ArgWithURL(GetCloseSocketURL())
-                            navigationType:CWVNavigationTypeTyped])
-      .andReturn(YES);
+                decidePolicyForNavigationAction:NavigationActionArg(
+                                                    GetCloseSocketURL(),
+                                                    CWVNavigationTypeTyped)
+                                decisionHandler:[OCMArg any]])
+      .andDo(^(NSInvocation* invocation) {
+        __weak void (^decisionHandler)(CWVNavigationActionPolicy);
+        [invocation getArgument:&decisionHandler atIndex:4];
+        if (decisionHandler) {
+          decisionHandler(CWVNavigationActionPolicyAllow);
+        }
+      });
   OCMExpect([mock_delegate_ webViewDidStartProvisionalNavigation:web_view_]);
   OCMExpect([mock_delegate_ webViewDidStartNavigation:web_view_]);
   OCMExpect([mock_delegate_ webViewDidCommitNavigation:web_view_]);
@@ -96,9 +128,17 @@
 // when -shouldStartLoadWithRequest:navigationType: returns NO.
 TEST_F(NavigationDelegateTest, CancelRequest) {
   OCMExpect([mock_delegate_ webView:web_view_
-                shouldStartLoadWithRequest:ArgWithURL(GetEchoURL())
-                            navigationType:CWVNavigationTypeTyped])
-      .andReturn(NO);
+                decidePolicyForNavigationAction:NavigationActionArg(
+                                                    GetEchoURL(),
+                                                    CWVNavigationTypeTyped)
+                                decisionHandler:[OCMArg any]])
+      .andDo(^(NSInvocation* invocation) {
+        __weak void (^decisionHandler)(CWVNavigationActionPolicy);
+        [invocation getArgument:&decisionHandler atIndex:4];
+        if (decisionHandler) {
+          decisionHandler(CWVNavigationActionPolicyCancel);
+        }
+      });
 
   ASSERT_TRUE(test::LoadUrl(web_view_, GetEchoURL()));
   [(id)mock_delegate_ verify];
@@ -108,15 +148,30 @@
 // when -shouldContinueLoadWithResponse:forMainFrame: returns NO.
 TEST_F(NavigationDelegateTest, CancelResponse) {
   OCMExpect([mock_delegate_ webView:web_view_
-                shouldStartLoadWithRequest:ArgWithURL(GetEchoURL())
-                            navigationType:CWVNavigationTypeTyped])
-      .andReturn(YES);
+                decidePolicyForNavigationAction:NavigationActionArg(
+                                                    GetEchoURL(),
+                                                    CWVNavigationTypeTyped)
+                                decisionHandler:[OCMArg any]])
+      .andDo(^(NSInvocation* invocation) {
+        __weak void (^decisionHandler)(CWVNavigationActionPolicy);
+        [invocation getArgument:&decisionHandler atIndex:4];
+        if (decisionHandler) {
+          decisionHandler(CWVNavigationActionPolicyAllow);
+        }
+      });
   OCMExpect([mock_delegate_ webViewDidStartProvisionalNavigation:web_view_]);
   OCMExpect([mock_delegate_ webViewDidStartNavigation:web_view_]);
   OCMExpect([mock_delegate_ webView:web_view_
-                shouldContinueLoadWithResponse:ArgWithURL(GetEchoURL())
-                                  forMainFrame:YES])
-      .andReturn(NO);
+                decidePolicyForNavigationResponse:NavigationResponseArg(
+                                                      GetEchoURL(), YES)
+                                  decisionHandler:[OCMArg any]])
+      .andDo(^(NSInvocation* invocation) {
+        __weak void (^decisionHandler)(CWVNavigationResponsePolicy);
+        [invocation getArgument:&decisionHandler atIndex:4];
+        if (decisionHandler) {
+          decisionHandler(CWVNavigationResponsePolicyCancel);
+        }
+      });
 
   ASSERT_TRUE(test::LoadUrl(web_view_, GetEchoURL()));
   [(id)mock_delegate_ verify];
@@ -126,15 +181,30 @@
 TEST_F(NavigationDelegateTest, SameDocumentNavigations) {
   // A request made with -loadRequest: has type CWVNavigationTypeTyped.
   OCMExpect([mock_delegate_ webView:web_view_
-                shouldStartLoadWithRequest:ArgWithURL(GetEchoURL())
-                            navigationType:CWVNavigationTypeTyped])
-      .andReturn(YES);
+                decidePolicyForNavigationAction:NavigationActionArg(
+                                                    GetEchoURL(),
+                                                    CWVNavigationTypeTyped)
+                                decisionHandler:[OCMArg any]])
+      .andDo(^(NSInvocation* invocation) {
+        __weak void (^decisionHandler)(CWVNavigationActionPolicy);
+        [invocation getArgument:&decisionHandler atIndex:4];
+        if (decisionHandler) {
+          decisionHandler(CWVNavigationActionPolicyAllow);
+        }
+      });
   OCMExpect([mock_delegate_ webViewDidStartProvisionalNavigation:web_view_]);
   OCMExpect([mock_delegate_ webViewDidStartNavigation:web_view_]);
   OCMExpect([mock_delegate_ webView:web_view_
-                shouldContinueLoadWithResponse:ArgWithURL(GetEchoURL())
-                                  forMainFrame:YES])
-      .andReturn(YES);
+                decidePolicyForNavigationResponse:NavigationResponseArg(
+                                                      GetEchoURL(), YES)
+                                  decisionHandler:[OCMArg any]])
+      .andDo(^(NSInvocation* invocation) {
+        __weak void (^decisionHandler)(CWVNavigationResponsePolicy);
+        [invocation getArgument:&decisionHandler atIndex:4];
+        if (decisionHandler) {
+          decisionHandler(CWVNavigationResponsePolicyAllow);
+        }
+      });
   OCMExpect([mock_delegate_ webViewDidCommitNavigation:web_view_]);
   OCMExpect([mock_delegate_ webViewDidFinishNavigation:web_view_]);
 
diff --git a/media/gpu/v4l2/test/av1_decoder.cc b/media/gpu/v4l2/test/av1_decoder.cc
index 2ed608a..90896d8 100644
--- a/media/gpu/v4l2/test/av1_decoder.cc
+++ b/media/gpu/v4l2/test/av1_decoder.cc
@@ -20,6 +20,7 @@
 namespace v4l2_test {
 
 namespace {
+constexpr uint32_t kDriverCodecFourcc = V4L2_PIX_FMT_AV1_FRAME;
 
 constexpr uint32_t kNumberOfBuffersInCaptureQueue = 10;
 
@@ -529,11 +530,8 @@
 
 Av1Decoder::Av1Decoder(std::unique_ptr<IvfParser> ivf_parser,
                        std::unique_ptr<V4L2IoctlShim> v4l2_ioctl,
-                       std::unique_ptr<V4L2Queue> OUTPUT_queue,
-                       std::unique_ptr<V4L2Queue> CAPTURE_queue)
-    : VideoDecoder::VideoDecoder(std::move(v4l2_ioctl),
-                                 std::move(OUTPUT_queue),
-                                 std::move(CAPTURE_queue)),
+                       gfx::Size display_resolution)
+    : VideoDecoder::VideoDecoder(std::move(v4l2_ioctl), display_resolution),
       ivf_parser_(std::move(ivf_parser)),
       buffer_pool_(std::make_unique<libgav1::BufferPool>(
           /*on_frame_buffer_size_changed=*/nullptr,
@@ -553,8 +551,6 @@
 // static
 std::unique_ptr<Av1Decoder> Av1Decoder::Create(
     const base::MemoryMappedFile& stream) {
-  constexpr uint32_t kDriverCodecFourcc = V4L2_PIX_FMT_AV1_FRAME;
-
   VLOG(2) << "Attempting to create decoder with codec "
           << media::FourccToString(kDriverCodecFourcc);
 
@@ -587,23 +583,8 @@
 
   const gfx::Size bitstream_coded_size = GetResolutionFromBitstream(stream);
 
-  // TODO(stevecho): might need to consider using more than 1 file descriptor
-  // (fd) & buffer with the output queue for 4K60 requirement.
-  // https://buganizer.corp.google.com/issues/202214561#comment31
-  auto OUTPUT_queue = std::make_unique<V4L2Queue>(
-      V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, bitstream_coded_size, V4L2_MEMORY_MMAP,
-      kNumberOfBuffersInOutputQueue);
-  OUTPUT_queue->set_fourcc(kDriverCodecFourcc);
-
-  // TODO(stevecho): enable V4L2_MEMORY_DMABUF memory for CAPTURE queue.
-  // https://www.kernel.org/doc/html/v5.16/userspace-api/media/v4l/pixfmt-v4l2-mplane.html#c.V4L.v4l2_plane_pix_format
-  auto CAPTURE_queue = std::make_unique<V4L2Queue>(
-      V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, bitstream_coded_size,
-      V4L2_MEMORY_MMAP, kNumberOfBuffersInCaptureQueue);
-
-  return base::WrapUnique(
-      new Av1Decoder(std::move(ivf_parser), std::move(v4l2_ioctl),
-                     std::move(OUTPUT_queue), std::move(CAPTURE_queue)));
+  return base::WrapUnique(new Av1Decoder(
+      std::move(ivf_parser), std::move(v4l2_ioctl), bitstream_coded_size));
 }
 
 Av1Decoder::ParsingResult Av1Decoder::ReadNextFrame(
@@ -982,6 +963,11 @@
     return VideoDecoder::kEOStream;
   }
 
+  const bool isOUTPUTQueueNew = !OUTPUT_queue_;
+  if (!OUTPUT_queue_) {
+    CreateOUTPUTQueue(kDriverCodecFourcc);
+  }
+
   libgav1::ObuFrameHeader current_frame_header = obu_parser_->frame_header();
 
   if (obu_parser_->sequence_header_changed())
@@ -1079,10 +1065,18 @@
   struct v4l2_ext_controls ext_ctrls = {.count = base::checked_cast<__u32>(ext_ctrl_vectors.size()),
                                         .controls = &ext_ctrl_vectors[0]};
 
-  v4l2_ioctl_->SetExtCtrls(OUTPUT_queue_, &ext_ctrls);
-
+  // Before the CAPTURE queue is set up the first frame must be parsed by the
+  // driver. This is done so that when VIDIOC_G_FMT is called the frame
+  // dimensions and format will be ready. Specifying V4L2_CTRL_WHICH_CUR_VAL
+  // when VIDIOC_S_EXT_CTRLS processes the request immediately so that the frame
+  // is parsed by the driver and the state is readied.
+  v4l2_ioctl_->SetExtCtrls(OUTPUT_queue_, &ext_ctrls, isOUTPUTQueueNew);
   v4l2_ioctl_->MediaRequestIocQueue(OUTPUT_queue_);
 
+  if (!CAPTURE_queue_) {
+    CreateCAPTUREQueue(kNumberOfBuffersInCaptureQueue);
+  }
+
   uint32_t buffer_id;
   v4l2_ioctl_->DQBuf(CAPTURE_queue_, &buffer_id);
 
diff --git a/media/gpu/v4l2/test/av1_decoder.h b/media/gpu/v4l2/test/av1_decoder.h
index d3dd28dd..ec4d24a 100644
--- a/media/gpu/v4l2/test/av1_decoder.h
+++ b/media/gpu/v4l2/test/av1_decoder.h
@@ -55,8 +55,7 @@
 
   Av1Decoder(std::unique_ptr<IvfParser> ivf_parser,
              std::unique_ptr<V4L2IoctlShim> v4l2_ioctl,
-             std::unique_ptr<V4L2Queue> OUTPUT_queue,
-             std::unique_ptr<V4L2Queue> CAPTURE_queue);
+             gfx::Size display_resolution);
 
   // Reads an OBU frame, if there is one available. If an |obu_parser_|
   // didn't exist and there is data to be read, |obu_parser_| will be
diff --git a/media/gpu/v4l2/test/v4l2_ioctl_shim.cc b/media/gpu/v4l2/test/v4l2_ioctl_shim.cc
index bd940c1..500e338 100644
--- a/media/gpu/v4l2/test/v4l2_ioctl_shim.cc
+++ b/media/gpu/v4l2/test/v4l2_ioctl_shim.cc
@@ -367,6 +367,14 @@
 void V4L2IoctlShim::SetFmt(const std::unique_ptr<V4L2Queue>& queue) const {
   struct v4l2_format fmt;
 
+  if (queue->type() == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+    // TODO(stevecho): remove VIDIOC_ENUM_FRAMESIZES ioctl call
+    //   after b/193237015 is resolved.
+    if (!EnumFrameSizes(queue->fourcc())) {
+      LOG(INFO) << "EnumFrameSizes for OUTPUT queue failed.";
+    }
+  }
+
   memset(&fmt, 0, sizeof(fmt));
   fmt.type = queue->type();
   fmt.fmt.pix_mp.pixelformat = queue->fourcc();
diff --git a/media/gpu/v4l2/test/video_decoder.cc b/media/gpu/v4l2/test/video_decoder.cc
index 0e1d3e7..59805211 100644
--- a/media/gpu/v4l2/test/video_decoder.cc
+++ b/media/gpu/v4l2/test/video_decoder.cc
@@ -135,12 +135,7 @@
       << static_cast<uint32_t>(fmt.fmt.pix_mp.num_planes);
 }
 
-void VideoDecoder::Initialize(bool resolution_changed) {
-  // TODO(stevecho): remove VIDIOC_ENUM_FRAMESIZES ioctl call
-  //   after b/193237015 is resolved.
-  if (!v4l2_ioctl_->EnumFrameSizes(OUTPUT_queue_->fourcc()))
-    LOG(INFO) << "EnumFrameSizes for OUTPUT queue failed.";
-
+void VideoDecoder::Initialize() {
   v4l2_ioctl_->SetFmt(OUTPUT_queue_);
 
   NegotiateCAPTUREFormat();
@@ -149,16 +144,9 @@
                  .Contains(gfx::Rect(OUTPUT_queue_->resolution())))
       << "Display size is not contained within the coded size. DRC?";
 
-  // If there is a dynamic resolution change, the Initialization sequence will
-  // be performed again, minus the allocation of OUTPUT queue buffers.
-  if (resolution_changed) {
-    v4l2_ioctl_->ReqBufsWithCount(CAPTURE_queue_,
-                                  number_of_buffers_in_capture_queue_);
-  } else {
-    v4l2_ioctl_->ReqBufs(OUTPUT_queue_);
-    v4l2_ioctl_->QueryAndMmapQueueBuffers(OUTPUT_queue_);
-    v4l2_ioctl_->ReqBufs(CAPTURE_queue_);
-  }
+  v4l2_ioctl_->ReqBufs(OUTPUT_queue_);
+  v4l2_ioctl_->QueryAndMmapQueueBuffers(OUTPUT_queue_);
+  v4l2_ioctl_->ReqBufs(CAPTURE_queue_);
 
   v4l2_ioctl_->QueryAndMmapQueueBuffers(CAPTURE_queue_);
 
@@ -184,12 +172,6 @@
       kNumberOfBuffersInOutputQueue);
   OUTPUT_queue_->set_fourcc(compressed_fourcc);
 
-  // TODO(stevecho): remove VIDIOC_ENUM_FRAMESIZES ioctl call
-  //   after b/193237015 is resolved.
-  if (!v4l2_ioctl_->EnumFrameSizes(OUTPUT_queue_->fourcc())) {
-    LOG(INFO) << "EnumFrameSizes for OUTPUT queue failed.";
-  }
-
   v4l2_ioctl_->SetFmt(OUTPUT_queue_);
   v4l2_ioctl_->ReqBufs(OUTPUT_queue_);
   v4l2_ioctl_->QueryAndMmapQueueBuffers(OUTPUT_queue_);
@@ -235,6 +217,10 @@
   v4l2_ioctl_->StreamOff(OUTPUT_queue_->type());
   v4l2_ioctl_->StreamOff(CAPTURE_queue_->type());
 
+  // Store the buffer count before clearing so the amount to reallocate
+  // is known.
+  const uint32_t num_buffers = CAPTURE_queue_->num_buffers();
+
   // Free all CAPTURE buffers from the driver side by calling VIDIOC_REQBUFS()
   // on the CAPTURE queue with a buffer count of zero.
   v4l2_ioctl_->ReqBufsWithCount(CAPTURE_queue_, 0);
@@ -245,9 +231,21 @@
   // Set the new resolution on OUTPUT queue. The driver will then pick up
   // the new resolution to be set on the coded size for CAPTURE queue.
   OUTPUT_queue_->set_resolution(new_resolution);
+  v4l2_ioctl_->SetFmt(OUTPUT_queue_);
 
-  // Perform the initialization sequence again
-  Initialize(/* resolution_changed*/ true);
+  NegotiateCAPTUREFormat();
+
+  v4l2_ioctl_->ReqBufsWithCount(CAPTURE_queue_, num_buffers);
+  v4l2_ioctl_->QueryAndMmapQueueBuffers(CAPTURE_queue_);
+
+  // Only 1 CAPTURE buffer is needed for 1st key frame decoding. Remaining
+  // CAPTURE buffers will be queued after that.
+  if (!v4l2_ioctl_->QBuf(CAPTURE_queue_, 0)) {
+    LOG(FATAL) << "VIDIOC_QBUF failed for CAPTURE queue.";
+  }
+
+  v4l2_ioctl_->StreamOn(OUTPUT_queue_->type());
+  v4l2_ioctl_->StreamOn(CAPTURE_queue_->type());
 }
 
 void VideoDecoder::ConvertToYUV(std::vector<uint8_t>& dest_y,
diff --git a/media/gpu/v4l2/test/video_decoder.h b/media/gpu/v4l2/test/video_decoder.h
index 7fb139b..fb4be48 100644
--- a/media/gpu/v4l2/test/video_decoder.h
+++ b/media/gpu/v4l2/test/video_decoder.h
@@ -46,7 +46,7 @@
 
   // Initializes setup needed for decoding.
   // https://www.kernel.org/doc/html/v5.10/userspace-api/media/v4l/dev-stateless-decoder.html#initialization
-  void Initialize(bool is_resolution_changed = false);
+  void Initialize();
 
   void CreateOUTPUTQueue(uint32_t compressed_fourcc);
   void CreateCAPTUREQueue(uint32_t num_buffers);
@@ -98,9 +98,6 @@
   // Whether the last decoded frame was visible.
   bool last_decoded_frame_visible_ = false;
 
-  // Number of buffers in CAPTURE queue varied by different codecs.
-  uint32_t number_of_buffers_in_capture_queue_;
-
   // resolution from the bitstream header
   gfx::Size display_resolution_;
 
diff --git a/media/gpu/v4l2/test/vp8_decoder.cc b/media/gpu/v4l2/test/vp8_decoder.cc
index 83bb4e8..599ab4ef 100644
--- a/media/gpu/v4l2/test/vp8_decoder.cc
+++ b/media/gpu/v4l2/test/vp8_decoder.cc
@@ -21,6 +21,8 @@
 #include "media/parsers/vp8_parser.h"
 
 namespace {
+constexpr uint32_t kDriverCodecFourcc = V4L2_PIX_FMT_VP8_FRAME;
+
 constexpr size_t kVp8FrameLast = 0;
 constexpr size_t kVp8FrameGolden = 1;
 constexpr size_t kVp8FrameAltref = 2;
@@ -239,18 +241,14 @@
 
 Vp8Decoder::Vp8Decoder(std::unique_ptr<IvfParser> ivf_parser,
                        std::unique_ptr<V4L2IoctlShim> v4l2_ioctl,
-                       std::unique_ptr<V4L2Queue> OUTPUT_queue,
-                       std::unique_ptr<V4L2Queue> CAPTURE_queue)
-    : VideoDecoder::VideoDecoder(std::move(v4l2_ioctl),
-                                 std::move(OUTPUT_queue),
-                                 std::move(CAPTURE_queue)),
+                       gfx::Size display_resolution)
+    : VideoDecoder::VideoDecoder(std::move(v4l2_ioctl), display_resolution),
       ivf_parser_(std::move(ivf_parser)),
       vp8_parser_(std::make_unique<Vp8Parser>()) {
   DCHECK(v4l2_ioctl_);
   DCHECK(v4l2_ioctl_->QueryCtrl(V4L2_CID_STATELESS_VP8_FRAME));
 
   std::fill(ref_frames_.begin(), ref_frames_.end(), nullptr);
-  number_of_buffers_in_capture_queue_ = kNumberOfBuffersInCaptureQueue;
 }
 
 Vp8Decoder::~Vp8Decoder() = default;
@@ -258,8 +256,6 @@
 // static
 std::unique_ptr<Vp8Decoder> Vp8Decoder::Create(
     const base::MemoryMappedFile& stream) {
-  constexpr uint32_t kDriverCodecFourcc = V4L2_PIX_FMT_VP8_FRAME;
-
   VLOG(2) << "Attempting to create decoder with codec "
           << media::FourccToString(kDriverCodecFourcc);
 
@@ -290,28 +286,12 @@
     return nullptr;
   }
 
-  LOG(INFO) << "Ivf file header: " << file_header.width << " x "
-            << file_header.height;
-
   const gfx::Size bitstream_coded_size = GetResolutionFromBitstream(stream);
+  LOG(INFO) << "Ivf file header: "
+            << gfx::Size(file_header.width, file_header.height).ToString();
 
-  // TODO(b/256251694): might need to consider using more than 1 file descriptor
-  // (fd) & buffer with the output queue for 4K60 requirement.
-  // https://buganizer.corp.google.com/issues/202214561#comment31
-  auto OUTPUT_queue = std::make_unique<V4L2Queue>(
-      V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, bitstream_coded_size, V4L2_MEMORY_MMAP,
-      kNumberOfBuffersInOutputQueue);
-  OUTPUT_queue->set_fourcc(kDriverCodecFourcc);
-
-  // TODO(b/256543928): enable V4L2_MEMORY_DMABUF memory for CAPTURE queue.
-  // https://www.kernel.org/doc/html/v5.10/userspace-api/media/v4l/pixfmt-v4l2-mplane.html#c.V4L.v4l2_plane_pix_format
-  auto CAPTURE_queue = std::make_unique<V4L2Queue>(
-      V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, bitstream_coded_size,
-      V4L2_MEMORY_MMAP, kNumberOfBuffersInCaptureQueue);
-
-  return base::WrapUnique(
-      new Vp8Decoder(std::move(ivf_parser), std::move(v4l2_ioctl),
-                     std::move(OUTPUT_queue), std::move(CAPTURE_queue)));
+  return base::WrapUnique(new Vp8Decoder(
+      std::move(ivf_parser), std::move(v4l2_ioctl), bitstream_coded_size));
 }
 
 struct v4l2_ctrl_vp8_frame Vp8Decoder::SetupFrameHeaders(
@@ -551,6 +531,11 @@
       break;
   }
 
+  const bool isOUTPUTQueueNew = !OUTPUT_queue_;
+  if (!OUTPUT_queue_) {
+    CreateOUTPUTQueue(kDriverCodecFourcc);
+  }
+
   const bool resolution_changed =
       frame_hdr.width != OUTPUT_queue_->resolution().width() ||
       frame_hdr.height != OUTPUT_queue_->resolution().height();
@@ -589,10 +574,19 @@
 
   struct v4l2_ext_controls ext_ctrls = {.count = 1, .controls = &ext_ctrl};
 
-  v4l2_ioctl_->SetExtCtrls(OUTPUT_queue_, &ext_ctrls);
-
+  // Before the CAPTURE queue is set up the first frame must be parsed by the
+  // driver. This is done so that when VIDIOC_G_FMT is called the frame
+  // dimensions and format will be ready. Specifying V4L2_CTRL_WHICH_CUR_VAL
+  // when VIDIOC_S_EXT_CTRLS processes the request immediately so that the frame
+  // is parsed by the driver and the state is readied.
+  v4l2_ioctl_->SetExtCtrls(OUTPUT_queue_, &ext_ctrls,
+                           isOUTPUTQueueNew && cur_val_is_supported_);
   v4l2_ioctl_->MediaRequestIocQueue(OUTPUT_queue_);
 
+  if (!CAPTURE_queue_) {
+    CreateCAPTUREQueue(kNumberOfBuffersInCaptureQueue);
+  }
+
   v4l2_ioctl_->DQBuf(CAPTURE_queue_, &buffer_id);
   CAPTURE_queue_->DequeueBufferId(buffer_id);
 
diff --git a/media/gpu/v4l2/test/vp8_decoder.h b/media/gpu/v4l2/test/vp8_decoder.h
index b585839..6fd0d07 100644
--- a/media/gpu/v4l2/test/vp8_decoder.h
+++ b/media/gpu/v4l2/test/vp8_decoder.h
@@ -47,8 +47,7 @@
  private:
   Vp8Decoder(std::unique_ptr<IvfParser> ivf_parser,
              std::unique_ptr<V4L2IoctlShim> v4l2_ioctl,
-             std::unique_ptr<V4L2Queue> OUTPUT_queue,
-             std::unique_ptr<V4L2Queue> CAPTURE_queue);
+             gfx::Size display_resolution);
   enum ParseResult { kOk, kEOStream, kError };
 
   // Reads next frame from IVF stream into |vp8_frame_header|
diff --git a/media/gpu/windows/d3d11_video_decoder.cc b/media/gpu/windows/d3d11_video_decoder.cc
index 512680b5..e28078ba 100644
--- a/media/gpu/windows/d3d11_video_decoder.cc
+++ b/media/gpu/windows/d3d11_video_decoder.cc
@@ -907,11 +907,16 @@
 
   base::TimeDelta timestamp = picture_buffer->timestamp_;
 
+  // Prefer the frame color space over what's in the config.
+  gfx::ColorSpace picture_color_space =
+      (picture->get_colorspace().IsSpecified() ? picture->get_colorspace()
+                                               : config_.color_space_info())
+          .ToGfxColorSpace();
+
   MailboxHolderArray mailbox_holders;
   gfx::ColorSpace output_color_space;
   D3D11Status result = picture_buffer->ProcessTexture(
-      picture->get_colorspace().ToGfxColorSpace(), &mailbox_holders,
-      &output_color_space);
+      picture_color_space, &mailbox_holders, &output_color_space);
   if (!result.is_ok()) {
     NotifyError(std::move(result).AddHere());
     return false;
diff --git a/net/base/address_tracker_linux.cc b/net/base/address_tracker_linux.cc
index 59f84a3..997530b 100644
--- a/net/base/address_tracker_linux.cc
+++ b/net/base/address_tracker_linux.cc
@@ -179,6 +179,13 @@
 
 AddressTrackerLinux::~AddressTrackerLinux() = default;
 
+void AddressTrackerLinux::InitWithFdForTesting(base::ScopedFD fd) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  netlink_fd_ = std::move(fd);
+  DumpInitialAddressesAndWatch();
+}
+
 void AddressTrackerLinux::Init() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 #if BUILDFLAG(IS_ANDROID)
@@ -216,63 +223,7 @@
     }
   }
 
-  // Request dump of addresses.
-  struct sockaddr_nl peer = {};
-  peer.nl_family = AF_NETLINK;
-
-  struct {
-    struct nlmsghdr header;
-    struct rtgenmsg msg;
-  } request = {};
-
-  request.header.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg));
-  request.header.nlmsg_type = RTM_GETADDR;
-  request.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
-  request.header.nlmsg_pid = 0;  // This field is opaque to netlink.
-  request.msg.rtgen_family = AF_UNSPEC;
-
-  rv = HANDLE_EINTR(
-      sendto(netlink_fd_.get(), &request, request.header.nlmsg_len, 0,
-             reinterpret_cast<struct sockaddr*>(&peer), sizeof(peer)));
-  if (rv < 0) {
-    PLOG(ERROR) << "Could not send NETLINK request";
-    AbortAndForceOnline();
-    return;
-  }
-
-  // Consume pending message to populate the AddressMap, but don't notify.
-  // Sending another request without first reading responses results in EBUSY.
-  bool address_changed;
-  bool link_changed;
-  bool tunnel_changed;
-  ReadMessages(&address_changed, &link_changed, &tunnel_changed);
-
-  // Request dump of link state
-  request.header.nlmsg_type = RTM_GETLINK;
-
-  rv = HANDLE_EINTR(
-      sendto(netlink_fd_.get(), &request, request.header.nlmsg_len, 0,
-             reinterpret_cast<struct sockaddr*>(&peer), sizeof(peer)));
-  if (rv < 0) {
-    PLOG(ERROR) << "Could not send NETLINK request";
-    AbortAndForceOnline();
-    return;
-  }
-
-  // Consume pending message to populate links_online_, but don't notify.
-  ReadMessages(&address_changed, &link_changed, &tunnel_changed);
-  {
-    AddressTrackerAutoLock lock(*this, connection_type_lock_);
-    connection_type_initialized_ = true;
-    connection_type_initialized_cv_.Broadcast();
-  }
-
-  if (tracking_) {
-    watcher_ = base::FileDescriptorWatcher::WatchReadable(
-        netlink_fd_.get(),
-        base::BindRepeating(&AddressTrackerLinux::OnFileCanReadWithoutBlocking,
-                            base::Unretained(this)));
-  }
+  DumpInitialAddressesAndWatch();
 }
 
 bool AddressTrackerLinux::DidTrackingInitSucceedForTesting() const {
@@ -352,6 +303,68 @@
   return current_connection_type_;
 }
 
+void AddressTrackerLinux::DumpInitialAddressesAndWatch() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // Request dump of addresses.
+  struct sockaddr_nl peer = {};
+  peer.nl_family = AF_NETLINK;
+
+  struct {
+    struct nlmsghdr header;
+    struct rtgenmsg msg;
+  } request = {};
+
+  request.header.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg));
+  request.header.nlmsg_type = RTM_GETADDR;
+  request.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+  request.header.nlmsg_pid = 0;  // This field is opaque to netlink.
+  request.msg.rtgen_family = AF_UNSPEC;
+
+  int rv = HANDLE_EINTR(
+      sendto(netlink_fd_.get(), &request, request.header.nlmsg_len, 0,
+             reinterpret_cast<struct sockaddr*>(&peer), sizeof(peer)));
+  if (rv < 0) {
+    PLOG(ERROR) << "Could not send NETLINK request";
+    AbortAndForceOnline();
+    return;
+  }
+
+  // Consume pending message to populate the AddressMap, but don't notify.
+  // Sending another request without first reading responses results in EBUSY.
+  bool address_changed;
+  bool link_changed;
+  bool tunnel_changed;
+  ReadMessages(&address_changed, &link_changed, &tunnel_changed);
+
+  // Request dump of link state
+  request.header.nlmsg_type = RTM_GETLINK;
+
+  rv = HANDLE_EINTR(
+      sendto(netlink_fd_.get(), &request, request.header.nlmsg_len, 0,
+             reinterpret_cast<struct sockaddr*>(&peer), sizeof(peer)));
+  if (rv < 0) {
+    PLOG(ERROR) << "Could not send NETLINK request";
+    AbortAndForceOnline();
+    return;
+  }
+
+  // Consume pending message to populate links_online_, but don't notify.
+  ReadMessages(&address_changed, &link_changed, &tunnel_changed);
+  {
+    AddressTrackerAutoLock lock(*this, connection_type_lock_);
+    connection_type_initialized_ = true;
+    connection_type_initialized_cv_.Broadcast();
+  }
+
+  if (tracking_) {
+    watcher_ = base::FileDescriptorWatcher::WatchReadable(
+        netlink_fd_.get(),
+        base::BindRepeating(&AddressTrackerLinux::OnFileCanReadWithoutBlocking,
+                            base::Unretained(this)));
+  }
+}
+
 void AddressTrackerLinux::ReadMessages(bool* address_changed,
                                        bool* link_changed,
                                        bool* tunnel_changed) {
diff --git a/net/base/address_tracker_linux.h b/net/base/address_tracker_linux.h
index 64ae26a..2e65307 100644
--- a/net/base/address_tracker_linux.h
+++ b/net/base/address_tracker_linux.h
@@ -34,6 +34,10 @@
 #include "net/base/net_export.h"
 #include "net/base/network_change_notifier.h"
 
+namespace net::test {
+class AddressTrackerLinuxTest;
+}
+
 namespace net::internal {
 
 // Keeps track of network interface addresses using rtnetlink. Used by
@@ -75,6 +79,10 @@
   // GetAddressMap().
   void Init();
 
+  // Same as Init(), except instead of creating and binding a netlink socket,
+  // this AddressTrackerLinux will send and receive messages from |fd|.
+  void InitWithFdForTesting(base::ScopedFD fd);
+
   // AddressMapOwnerLinux implementation (callable on any thread):
   AddressMap GetAddressMap() const override;
   // Returns set of interface indices for online interfaces.
@@ -117,7 +125,7 @@
   static bool IsTunnelInterfaceName(const char* name);
 
  private:
-  friend class AddressTrackerLinuxTest;
+  friend class net::test::AddressTrackerLinuxTest;
   FRIEND_TEST_ALL_PREFIXES(AddressTrackerLinuxNetlinkTest,
                            TestInitializeTwoTrackers);
   FRIEND_TEST_ALL_PREFIXES(AddressTrackerLinuxNetlinkTest,
@@ -144,6 +152,10 @@
   // function should return a pointer to |ifname|.
   typedef char* (*GetInterfaceNameFunction)(int interface_index, char* ifname);
 
+  // Retrieves a dump of the current AddressMap and set of online links as part
+  // of initialization. Expects |netlink_fd_| to exist already.
+  void DumpInitialAddressesAndWatch();
+
   // Sets |*address_changed| to indicate whether |address_map_| changed and
   // sets |*link_changed| to indicate if |online_links_| changed and sets
   // |*tunnel_changed| to indicate if |online_links_| changed with regards to a
diff --git a/net/base/address_tracker_linux_fuzzer.cc b/net/base/address_tracker_linux_fuzzer.cc
index 7a0fd53..5aa66be 100644
--- a/net/base/address_tracker_linux_fuzzer.cc
+++ b/net/base/address_tracker_linux_fuzzer.cc
@@ -8,8 +8,10 @@
 #include "base/functional/callback_helpers.h"
 #include "net/base/address_tracker_linux.h"
 
-namespace net {
-namespace internal {
+using net::internal::AddressTrackerLinux;
+
+namespace net::test {
+
 class AddressTrackerLinuxTest {
  public:
   static void TestHandleMessage(const char* buffer, size_t length) {
@@ -31,5 +33,4 @@
   return 0;
 }
 
-}  // namespace internal
-}  // namespace net
+}  // namespace net::test
diff --git a/net/base/address_tracker_linux_test_util.cc b/net/base/address_tracker_linux_test_util.cc
index 1a7453a..2aad8489 100644
--- a/net/base/address_tracker_linux_test_util.cc
+++ b/net/base/address_tracker_linux_test_util.cc
@@ -4,9 +4,136 @@
 
 #include "net/base/address_tracker_linux_test_util.h"
 
+#include <linux/if.h>
+#include <linux/netlink.h>
 #include <linux/rtnetlink.h>
+#include <stdint.h>
 #include <string.h>
 
+#include <vector>
+
+#include "base/check_op.h"
+#include "base/logging.h"
+#include "net/base/ip_address.h"
+
 bool operator==(const struct ifaddrmsg& lhs, const struct ifaddrmsg& rhs) {
   return memcmp(&lhs, &rhs, sizeof(struct ifaddrmsg)) == 0;
 }
+
+namespace net::test {
+
+NetlinkMessage::NetlinkMessage(uint16_t type) : buffer_(NLMSG_HDRLEN) {
+  header()->nlmsg_type = type;
+  Align();
+}
+
+NetlinkMessage::~NetlinkMessage() = default;
+
+void NetlinkMessage::AddPayload(const void* data, size_t length) {
+  CHECK_EQ(static_cast<size_t>(NLMSG_HDRLEN), buffer_.size())
+      << "Payload must be added first";
+  Append(data, length);
+  Align();
+}
+
+void NetlinkMessage::AddAttribute(uint16_t type,
+                                  const void* data,
+                                  size_t length) {
+  struct nlattr attr;
+  attr.nla_len = NLA_HDRLEN + length;
+  attr.nla_type = type;
+  Append(&attr, sizeof(attr));
+  Align();
+  Append(data, length);
+  Align();
+}
+
+void NetlinkMessage::AppendTo(NetlinkBuffer* output) const {
+  CHECK_EQ(NLMSG_ALIGN(output->size()), output->size());
+  output->insert(output->end(), buffer_.begin(), buffer_.end());
+}
+
+void NetlinkMessage::Append(const void* data, size_t length) {
+  const char* chardata = reinterpret_cast<const char*>(data);
+  buffer_.insert(buffer_.end(), chardata, chardata + length);
+}
+
+void NetlinkMessage::Align() {
+  header()->nlmsg_len = buffer_.size();
+  buffer_.resize(NLMSG_ALIGN(buffer_.size()));
+  CHECK(NLMSG_OK(header(), buffer_.size()));
+}
+
+#define INFINITY_LIFE_TIME 0xFFFFFFFF
+
+void MakeAddrMessageWithCacheInfo(uint16_t type,
+                                  uint8_t flags,
+                                  uint8_t family,
+                                  int index,
+                                  const IPAddress& address,
+                                  const IPAddress& local,
+                                  uint32_t preferred_lifetime,
+                                  NetlinkBuffer* output) {
+  NetlinkMessage nlmsg(type);
+  struct ifaddrmsg msg = {};
+  msg.ifa_family = family;
+  msg.ifa_flags = flags;
+  msg.ifa_index = index;
+  nlmsg.AddPayload(msg);
+  if (address.size()) {
+    nlmsg.AddAttribute(IFA_ADDRESS, address.bytes().data(), address.size());
+  }
+  if (local.size()) {
+    nlmsg.AddAttribute(IFA_LOCAL, local.bytes().data(), local.size());
+  }
+  struct ifa_cacheinfo cache_info = {};
+  cache_info.ifa_prefered = preferred_lifetime;
+  cache_info.ifa_valid = INFINITY_LIFE_TIME;
+  nlmsg.AddAttribute(IFA_CACHEINFO, &cache_info, sizeof(cache_info));
+  nlmsg.AppendTo(output);
+}
+
+void MakeAddrMessage(uint16_t type,
+                     uint8_t flags,
+                     uint8_t family,
+                     int index,
+                     const IPAddress& address,
+                     const IPAddress& local,
+                     NetlinkBuffer* output) {
+  MakeAddrMessageWithCacheInfo(type, flags, family, index, address, local,
+                               INFINITY_LIFE_TIME, output);
+}
+
+void MakeLinkMessage(uint16_t type,
+                     uint32_t flags,
+                     uint32_t index,
+                     NetlinkBuffer* output) {
+  NetlinkMessage nlmsg(type);
+  struct ifinfomsg msg = {};
+  msg.ifi_index = index;
+  msg.ifi_flags = flags;
+  msg.ifi_change = 0xFFFFFFFF;
+  nlmsg.AddPayload(msg);
+  output->clear();
+  nlmsg.AppendTo(output);
+}
+
+// Creates a netlink message generated by wireless_send_event. These events
+// should be ignored.
+void MakeWirelessLinkMessage(uint16_t type,
+                             uint32_t flags,
+                             uint32_t index,
+                             NetlinkBuffer* output) {
+  NetlinkMessage nlmsg(type);
+  struct ifinfomsg msg = {};
+  msg.ifi_index = index;
+  msg.ifi_flags = flags;
+  msg.ifi_change = 0;
+  nlmsg.AddPayload(msg);
+  char data[8] = {0};
+  nlmsg.AddAttribute(IFLA_WIRELESS, data, sizeof(data));
+  output->clear();
+  nlmsg.AppendTo(output);
+}
+
+}  // namespace net::test
diff --git a/net/base/address_tracker_linux_test_util.h b/net/base/address_tracker_linux_test_util.h
index 4506292..0c637bf 100644
--- a/net/base/address_tracker_linux_test_util.h
+++ b/net/base/address_tracker_linux_test_util.h
@@ -5,8 +5,70 @@
 #ifndef NET_BASE_ADDRESS_TRACKER_LINUX_TEST_UTIL_H_
 #define NET_BASE_ADDRESS_TRACKER_LINUX_TEST_UTIL_H_
 
+#include <linux/netlink.h>
 #include <linux/rtnetlink.h>
+#include <stdint.h>
+
+#include <vector>
 
 bool operator==(const struct ifaddrmsg& lhs, const struct ifaddrmsg& rhs);
 
+namespace net {
+class IPAddress;
+}
+
+namespace net::test {
+
+using NetlinkBuffer = std::vector<char>;
+
+class NetlinkMessage {
+ public:
+  explicit NetlinkMessage(uint16_t type);
+  ~NetlinkMessage();
+  void AddPayload(const void* data, size_t length);
+  template <typename T>
+  void AddPayload(const T& data) {
+    AddPayload(&data, sizeof(data));
+  }
+  void AddAttribute(uint16_t type, const void* data, size_t length);
+  void AppendTo(NetlinkBuffer* output) const;
+
+ private:
+  void Append(const void* data, size_t length);
+  void Align();
+  struct nlmsghdr* header() {
+    return reinterpret_cast<struct nlmsghdr*>(buffer_.data());
+  }
+
+  NetlinkBuffer buffer_;
+};
+
+void MakeAddrMessageWithCacheInfo(uint16_t type,
+                                  uint8_t flags,
+                                  uint8_t family,
+                                  int index,
+                                  const IPAddress& address,
+                                  const IPAddress& local,
+                                  uint32_t preferred_lifetime,
+                                  NetlinkBuffer* output);
+
+void MakeAddrMessage(uint16_t type,
+                     uint8_t flags,
+                     uint8_t family,
+                     int index,
+                     const IPAddress& address,
+                     const IPAddress& local,
+                     NetlinkBuffer* output);
+
+void MakeLinkMessage(uint16_t type,
+                     uint32_t flags,
+                     uint32_t index,
+                     NetlinkBuffer* output);
+
+void MakeWirelessLinkMessage(uint16_t type,
+                             uint32_t flags,
+                             uint32_t index,
+                             NetlinkBuffer* output);
+}  // namespace net::test
+
 #endif  // NET_BASE_ADDRESS_TRACKER_LINUX_TEST_UTIL_H_
diff --git a/net/base/address_tracker_linux_unittest.cc b/net/base/address_tracker_linux_unittest.cc
index 9c4b27e4..4ef8576 100644
--- a/net/base/address_tracker_linux_unittest.cc
+++ b/net/base/address_tracker_linux_unittest.cc
@@ -27,6 +27,7 @@
 #include "base/threading/simple_thread.h"
 #include "build/build_config.h"
 #include "net/base/address_map_cache_linux.h"
+#include "net/base/address_map_linux.h"
 #include "net/base/address_tracker_linux_test_util.h"
 #include "net/base/ip_address.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -40,7 +41,9 @@
 #define IFA_F_HOMEADDRESS 0x10
 #endif
 
-namespace net::internal {
+using net::internal::AddressTrackerLinux;
+
+namespace net::test {
 namespace {
 
 const int kTestInterfaceEth = 1;
@@ -65,8 +68,6 @@
 
 }  // namespace
 
-typedef std::vector<char> Buffer;
-
 class AddressTrackerLinuxTest : public testing::Test {
  protected:
   AddressTrackerLinuxTest() = default;
@@ -90,8 +91,8 @@
     tracker_->get_interface_name_ = TestGetInterfaceName;
   }
 
-  bool HandleAddressMessage(const Buffer& buf) {
-    Buffer writable_buf = buf;
+  bool HandleAddressMessage(const NetlinkBuffer& buf) {
+    NetlinkBuffer writable_buf = buf;
     bool address_changed = false;
     bool link_changed = false;
     bool tunnel_changed = false;
@@ -102,8 +103,8 @@
     return address_changed;
   }
 
-  bool HandleLinkMessage(const Buffer& buf) {
-    Buffer writable_buf = buf;
+  bool HandleLinkMessage(const NetlinkBuffer& buf) {
+    NetlinkBuffer writable_buf = buf;
     bool address_changed = false;
     bool link_changed = false;
     bool tunnel_changed = false;
@@ -114,8 +115,8 @@
     return link_changed;
   }
 
-  bool HandleTunnelMessage(const Buffer& buf) {
-    Buffer writable_buf = buf;
+  bool HandleTunnelMessage(const NetlinkBuffer& buf) {
+    NetlinkBuffer writable_buf = buf;
     bool address_changed = false;
     bool link_changed = false;
     bool tunnel_changed = false;
@@ -173,125 +174,6 @@
 
 namespace {
 
-class NetlinkMessage {
- public:
-  explicit NetlinkMessage(uint16_t type) : buffer_(NLMSG_HDRLEN) {
-    header()->nlmsg_type = type;
-    Align();
-  }
-
-  void AddPayload(const void* data, size_t length) {
-    CHECK_EQ(static_cast<size_t>(NLMSG_HDRLEN),
-             buffer_.size()) << "Payload must be added first";
-    Append(data, length);
-    Align();
-  }
-
-  void AddAttribute(uint16_t type, const void* data, size_t length) {
-    struct nlattr attr;
-    attr.nla_len = NLA_HDRLEN + length;
-    attr.nla_type = type;
-    Append(&attr, sizeof(attr));
-    Align();
-    Append(data, length);
-    Align();
-  }
-
-  void AppendTo(Buffer* output) const {
-    CHECK_EQ(NLMSG_ALIGN(output->size()), output->size());
-    output->reserve(output->size() + NLMSG_LENGTH(buffer_.size()));
-    output->insert(output->end(), buffer_.begin(), buffer_.end());
-  }
-
- private:
-  void Append(const void* data, size_t length) {
-    const char* chardata = reinterpret_cast<const char*>(data);
-    buffer_.insert(buffer_.end(), chardata, chardata + length);
-  }
-
-  void Align() {
-    header()->nlmsg_len = buffer_.size();
-    buffer_.insert(buffer_.end(), NLMSG_ALIGN(buffer_.size()) - buffer_.size(),
-                   0);
-    CHECK(NLMSG_OK(header(), buffer_.size()));
-  }
-
-  struct nlmsghdr* header() {
-    return reinterpret_cast<struct nlmsghdr*>(&buffer_[0]);
-  }
-
-  Buffer buffer_;
-};
-
-#define INFINITY_LIFE_TIME 0xFFFFFFFF
-
-void MakeAddrMessageWithCacheInfo(uint16_t type,
-                                  uint8_t flags,
-                                  uint8_t family,
-                                  int index,
-                                  const IPAddress& address,
-                                  const IPAddress& local,
-                                  uint32_t preferred_lifetime,
-                                  Buffer* output) {
-  NetlinkMessage nlmsg(type);
-  struct ifaddrmsg msg = {};
-  msg.ifa_family = family;
-  msg.ifa_flags = flags;
-  msg.ifa_index = index;
-  nlmsg.AddPayload(&msg, sizeof(msg));
-  if (address.size())
-    nlmsg.AddAttribute(IFA_ADDRESS, address.bytes().data(), address.size());
-  if (local.size())
-    nlmsg.AddAttribute(IFA_LOCAL, local.bytes().data(), local.size());
-  struct ifa_cacheinfo cache_info = {};
-  cache_info.ifa_prefered = preferred_lifetime;
-  cache_info.ifa_valid = INFINITY_LIFE_TIME;
-  nlmsg.AddAttribute(IFA_CACHEINFO, &cache_info, sizeof(cache_info));
-  nlmsg.AppendTo(output);
-}
-
-void MakeAddrMessage(uint16_t type,
-                     uint8_t flags,
-                     uint8_t family,
-                     int index,
-                     const IPAddress& address,
-                     const IPAddress& local,
-                     Buffer* output) {
-  MakeAddrMessageWithCacheInfo(type, flags, family, index, address, local,
-                               INFINITY_LIFE_TIME, output);
-}
-
-void MakeLinkMessage(uint16_t type,
-                     uint32_t flags,
-                     uint32_t index,
-                     Buffer* output) {
-  NetlinkMessage nlmsg(type);
-  struct ifinfomsg msg = {};
-  msg.ifi_index = index;
-  msg.ifi_flags = flags;
-  nlmsg.AddPayload(&msg, sizeof(msg));
-  output->clear();
-  nlmsg.AppendTo(output);
-}
-
-// Creates a netlink message generated by wireless_send_event. These events
-// should be ignored.
-void MakeWirelessLinkMessage(uint16_t type,
-                             uint32_t flags,
-                             uint32_t index,
-                             Buffer* output) {
-  NetlinkMessage nlmsg(type);
-  struct ifinfomsg msg = {};
-  msg.ifi_index = index;
-  msg.ifi_flags = flags;
-  msg.ifi_change = 0;
-  nlmsg.AddPayload(&msg, sizeof(msg));
-  char data[8] = {0};
-  nlmsg.AddAttribute(IFLA_WIRELESS, data, sizeof(data));
-  output->clear();
-  nlmsg.AppendTo(output);
-}
-
 const unsigned char kAddress0[] = { 127, 0, 0, 1 };
 const unsigned char kAddress1[] = { 10, 0, 0, 1 };
 const unsigned char kAddress2[] = { 192, 168, 0, 1 };
@@ -307,7 +189,7 @@
   const IPAddress kAddr2(kAddress2);
   const IPAddress kAddr3(kAddress3);
 
-  Buffer buffer;
+  NetlinkBuffer buffer;
   MakeAddrMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kTestInterfaceEth,
                   kAddr0, kEmpty, &buffer);
   EXPECT_TRUE(HandleAddressMessage(buffer));
@@ -341,7 +223,7 @@
   const IPAddress kEmpty;
   const IPAddress kAddr0(kAddress0);
 
-  Buffer buffer;
+  NetlinkBuffer buffer;
   MakeAddrMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kTestInterfaceEth,
                   kAddr0, kEmpty, &buffer);
   EXPECT_TRUE(HandleAddressMessage(buffer));
@@ -376,7 +258,7 @@
 
   const IPAddress kAddr0(kAddress0);
 
-  Buffer buffer;
+  NetlinkBuffer buffer;
   MakeAddrMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kTestInterfaceEth,
                   kAddr0, kAddr0, &buffer);
   EXPECT_TRUE(HandleAddressMessage(buffer));
@@ -399,7 +281,7 @@
   const IPAddress kAddr1(kAddress1);
   const IPAddress kAddr2(kAddress2);
 
-  Buffer buffer;
+  NetlinkBuffer buffer;
   MakeAddrMessage(RTM_NEWADDR, 0, AF_INET, kTestInterfaceEth, kAddr0, kEmpty,
                   &buffer);
   MakeAddrMessage(RTM_NEWADDR, 0, AF_INET, kTestInterfaceEth, kAddr1, kAddr2,
@@ -439,7 +321,7 @@
   const IPAddress kEmpty;
   const IPAddress kAddr3(kAddress3);
 
-  Buffer buffer;
+  NetlinkBuffer buffer;
   MakeAddrMessage(RTM_NEWADDR, 0, AF_INET6, kTestInterfaceEth, kEmpty, kAddr3,
                   &buffer);
   EXPECT_TRUE(HandleAddressMessage(buffer));
@@ -483,7 +365,7 @@
   const IPAddress kAddr0(kAddress0);
   const IPAddress kAddr3(kAddress3);
 
-  Buffer buffer;
+  NetlinkBuffer buffer;
   // Ignored family.
   MakeAddrMessage(RTM_NEWADDR, 0, AF_UNSPEC, kTestInterfaceEth, kAddr3, kAddr0,
                   &buffer);
@@ -500,7 +382,7 @@
   NetlinkMessage nlmsg(RTM_NEWADDR);
   struct ifaddrmsg msg = {};
   msg.ifa_family = AF_INET;
-  nlmsg.AddPayload(&msg, sizeof(msg));
+  nlmsg.AddPayload(msg);
   // Ignored attribute.
   struct ifa_cacheinfo cache_info = {};
   nlmsg.AddAttribute(IFA_CACHEINFO, &cache_info, sizeof(cache_info));
@@ -514,7 +396,7 @@
 TEST_F(AddressTrackerLinuxTest, AddInterface) {
   InitializeAddressTracker(true);
 
-  Buffer buffer;
+  NetlinkBuffer buffer;
 
   // Ignores loopback.
   MakeLinkMessage(RTM_NEWLINK,
@@ -567,7 +449,7 @@
 TEST_F(AddressTrackerLinuxTest, RemoveInterface) {
   InitializeAddressTracker(true);
 
-  Buffer buffer;
+  NetlinkBuffer buffer;
 
   // Should disappear when not IFF_LOWER_UP.
   MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING,
@@ -620,7 +502,7 @@
   IgnoreInterface(kIgnoredInterfaceName);
   InitializeAddressTracker(true);
 
-  Buffer buffer;
+  NetlinkBuffer buffer;
   const IPAddress kEmpty;
   const IPAddress kAddr0(kAddress0);
 
@@ -642,7 +524,7 @@
   IgnoreInterface(kIgnoredInterfaceName);
   InitializeAddressTracker(true);
 
-  Buffer buffer;
+  NetlinkBuffer buffer;
   const IPAddress kEmpty;
   const IPAddress kAddr0(kAddress0);
 
@@ -663,7 +545,7 @@
 TEST_F(AddressTrackerLinuxTest, TunnelInterface) {
   InitializeAddressTracker(true);
 
-  Buffer buffer;
+  NetlinkBuffer buffer;
 
   // Ignores without "tun" prefixed name.
   MakeLinkMessage(RTM_NEWLINK,
@@ -719,7 +601,7 @@
   const IPAddress kEmpty;
   const IPAddress kAddr0(kAddress0);
 
-  Buffer buffer;
+  NetlinkBuffer buffer;
   MakeAddrMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kTestInterfaceEth,
                   kAddr0, kEmpty, &buffer);
   EXPECT_TRUE(HandleAddressMessage(buffer));
@@ -808,6 +690,9 @@
 }
 
 }  // namespace
+}  // namespace net::test
+
+namespace net::internal {
 
 // This is a regression test for https://crbug.com/1224428.
 //
diff --git a/net/base/network_change_notifier_linux.cc b/net/base/network_change_notifier_linux.cc
index 79e6431e..1f6b0f9 100644
--- a/net/base/network_change_notifier_linux.cc
+++ b/net/base/network_change_notifier_linux.cc
@@ -36,9 +36,11 @@
     return &address_tracker_;
   }
 
-  // Begin watching for DNS and netlink changes.
+  // Begin watching for netlink changes.
   void Init();
 
+  void InitForTesting(base::ScopedFD netlink_fd);  // IN-TEST
+
  private:
   void OnIPAddressChanged();
   void OnLinkChanged();
@@ -65,6 +67,12 @@
   last_type_ = GetCurrentConnectionType();
 }
 
+void NetworkChangeNotifierLinux::BlockingThreadObjects::InitForTesting(
+    base::ScopedFD netlink_fd) {
+  address_tracker_.InitWithFdForTesting(std::move(netlink_fd));  // IN-TEST
+  last_type_ = GetCurrentConnectionType();
+}
+
 void NetworkChangeNotifierLinux::BlockingThreadObjects::OnIPAddressChanged() {
   NetworkChangeNotifier::NotifyObserversOfIPAddressChange();
   // When the IP address of a network interface is added/deleted, the
@@ -84,8 +92,29 @@
   }
 }
 
+// static
+std::unique_ptr<NetworkChangeNotifierLinux>
+NetworkChangeNotifierLinux::CreateWithSocketForTesting(
+    const std::unordered_set<std::string>& ignored_interfaces,
+    base::ScopedFD netlink_fd) {
+  auto ncn_linux = std::make_unique<NetworkChangeNotifierLinux>(
+      ignored_interfaces, /*initialize_blocking_thread_objects=*/false,
+      base::PassKey<NetworkChangeNotifierLinux>());
+  ncn_linux->InitBlockingThreadObjectsForTesting(  // IN-TEST
+      std::move(netlink_fd));
+  return ncn_linux;
+}
+
 NetworkChangeNotifierLinux::NetworkChangeNotifierLinux(
     const std::unordered_set<std::string>& ignored_interfaces)
+    : NetworkChangeNotifierLinux(ignored_interfaces,
+                                 /*initialize_blocking_thread_objects*/ true,
+                                 base::PassKey<NetworkChangeNotifierLinux>()) {}
+
+NetworkChangeNotifierLinux::NetworkChangeNotifierLinux(
+    const std::unordered_set<std::string>& ignored_interfaces,
+    bool initialize_blocking_thread_objects,
+    base::PassKey<NetworkChangeNotifierLinux>)
     : NetworkChangeNotifier(NetworkChangeCalculatorParamsLinux()),
       blocking_thread_runner_(
           base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})),
@@ -96,12 +125,14 @@
           // NetworkChangeNotifierLinux outlives
           // TaskEnvironment. https://crbug.com/938126
           base::OnTaskRunnerDeleter(blocking_thread_runner_)) {
-  blocking_thread_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&NetworkChangeNotifierLinux::BlockingThreadObjects::Init,
-                     // The Unretained pointer is safe here because it's
-                     // posted before the deleter can post.
-                     base::Unretained(blocking_thread_objects_.get())));
+  if (initialize_blocking_thread_objects) {
+    blocking_thread_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&NetworkChangeNotifierLinux::BlockingThreadObjects::Init,
+                       // The Unretained pointer is safe here because it's
+                       // posted before the deleter can post.
+                       base::Unretained(blocking_thread_objects_.get())));
+  }
 }
 
 NetworkChangeNotifierLinux::~NetworkChangeNotifierLinux() {
@@ -121,6 +152,19 @@
   return params;
 }
 
+void NetworkChangeNotifierLinux::InitBlockingThreadObjectsForTesting(
+    base::ScopedFD netlink_fd) {
+  DCHECK(blocking_thread_objects_);
+  blocking_thread_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          &NetworkChangeNotifierLinux::BlockingThreadObjects::InitForTesting,
+          // The Unretained pointer is safe here because it's
+          // posted before the deleter can post.
+          base::Unretained(blocking_thread_objects_.get()),
+          std::move(netlink_fd)));
+}
+
 NetworkChangeNotifier::ConnectionType
 NetworkChangeNotifierLinux::GetCurrentConnectionType() const {
   return blocking_thread_objects_->GetCurrentConnectionType();
diff --git a/net/base/network_change_notifier_linux.h b/net/base/network_change_notifier_linux.h
index 1fe1eb8..926011b5 100644
--- a/net/base/network_change_notifier_linux.h
+++ b/net/base/network_change_notifier_linux.h
@@ -9,7 +9,9 @@
 #include <unordered_set>
 
 #include "base/compiler_specific.h"
+#include "base/files/scoped_file.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/types/pass_key.h"
 #include "net/base/net_export.h"
 #include "net/base/network_change_notifier.h"
 
@@ -23,6 +25,12 @@
 class NET_EXPORT_PRIVATE NetworkChangeNotifierLinux
     : public NetworkChangeNotifier {
  public:
+  // Creates the object mostly like normal, but the AddressTrackerLinux will use
+  // |netlink_fd| instead of creating and binding its own netlink socket.
+  static std::unique_ptr<NetworkChangeNotifierLinux> CreateWithSocketForTesting(
+      const std::unordered_set<std::string>& ignored_interfaces,
+      base::ScopedFD netlink_fd);
+
   // Creates NetworkChangeNotifierLinux with a list of ignored interfaces.
   // |ignored_interfaces| is the list of interfaces to ignore. An ignored
   // interface will not trigger IP address or connection type notifications.
@@ -32,6 +40,15 @@
   explicit NetworkChangeNotifierLinux(
       const std::unordered_set<std::string>& ignored_interfaces);
 
+  // This constructor can leave the BlockingThreadObjects uninitialized. This
+  // is useful in tests that want to mock the netlink dependency of
+  // AddressTrackerLinux. The PassKey makes this essentially a private
+  // constructor.
+  NetworkChangeNotifierLinux(
+      const std::unordered_set<std::string>& ignored_interfaces,
+      bool initialize_blocking_thread_objects,
+      base::PassKey<NetworkChangeNotifierLinux>);
+
   NetworkChangeNotifierLinux(const NetworkChangeNotifierLinux&) = delete;
   NetworkChangeNotifierLinux& operator=(const NetworkChangeNotifierLinux&) =
       delete;
@@ -43,6 +60,10 @@
  private:
   class BlockingThreadObjects;
 
+  // Initializes BlockingThreadObjects, but AddressTrackerLinux will listen to
+  // |netlink_fd| rather than the kernel.
+  void InitBlockingThreadObjectsForTesting(base::ScopedFD netlink_fd);
+
   // NetworkChangeNotifier:
   ConnectionType GetCurrentConnectionType() const override;
 
@@ -53,7 +74,6 @@
   // A collection of objects that must live on blocking sequences. These objects
   // listen for notifications and relay the notifications to the registered
   // observers without posting back to the thread the object was created on.
-  // Also used for DnsConfigService which also must live on blocking sequences.
   std::unique_ptr<BlockingThreadObjects, base::OnTaskRunnerDeleter>
       blocking_thread_objects_;
 };
diff --git a/net/dns/dns_util.cc b/net/dns/dns_util.cc
index 55432110..1f4f38e 100644
--- a/net/dns/dns_util.cc
+++ b/net/dns/dns_util.cc
@@ -52,8 +52,13 @@
   for (const auto& server : dns_servers) {
     for (const auto* entry : providers) {
       // DoH servers should only be added once.
-      if (base::FeatureList::IsEnabled(entry->feature) &&
-          base::Contains(entry->ip_addresses, server.address()) &&
+      // Note: Check whether the provider is enabled *after* we've determined
+      // that the IP addresses match so that if we are doing experimentation via
+      // Finch, the experiment only includes possible users of the
+      // corresponding DoH provider (since the client will be included in the
+      // experiment if the provider feature flag is checked).
+      if (base::Contains(entry->ip_addresses, server.address()) &&
+          base::FeatureList::IsEnabled(entry->feature) &&
           !base::Contains(entries, entry)) {
         entries.push_back(entry);
       }
@@ -156,8 +161,13 @@
     return doh_servers;
 
   for (const auto* entry : DohProviderEntry::GetList()) {
-    if (base::FeatureList::IsEnabled(entry->feature) &&
-        base::Contains(entry->dns_over_tls_hostnames, dot_server)) {
+    // Note: Check whether the provider is enabled *after* we've determined that
+    // the hostnames match so that if we are doing experimentation via Finch,
+    // the experiment only includes possible users of the corresponding DoH
+    // provider (since the client will be included in the experiment if the
+    // provider feature flag is checked).
+    if (base::Contains(entry->dns_over_tls_hostnames, dot_server) &&
+        base::FeatureList::IsEnabled(entry->feature)) {
       doh_servers.push_back(entry->doh_server_config);
     }
   }
diff --git a/ppapi/proxy/ppapi_command_buffer_proxy.cc b/ppapi/proxy/ppapi_command_buffer_proxy.cc
index d096a77..e92622a 100644
--- a/ppapi/proxy/ppapi_command_buffer_proxy.cc
+++ b/ppapi/proxy/ppapi_command_buffer_proxy.cc
@@ -119,7 +119,6 @@
 scoped_refptr<gpu::Buffer> PpapiCommandBufferProxy::CreateTransferBuffer(
     uint32_t size,
     int32_t* id,
-    uint32_t alignment,
     gpu::TransferBufferAllocationOption option) {
   *id = -1;
 
diff --git a/ppapi/proxy/ppapi_command_buffer_proxy.h b/ppapi/proxy/ppapi_command_buffer_proxy.h
index 403e97d..0a8feb3 100644
--- a/ppapi/proxy/ppapi_command_buffer_proxy.h
+++ b/ppapi/proxy/ppapi_command_buffer_proxy.h
@@ -55,7 +55,6 @@
   scoped_refptr<gpu::Buffer> CreateTransferBuffer(
       uint32_t size,
       int32_t* id,
-      uint32_t alignment = 0,
       gpu::TransferBufferAllocationOption option =
           gpu::TransferBufferAllocationOption::kLoseContextOnOOM) override;
   void DestroyTransferBuffer(int32_t id) override;
diff --git a/remoting/base/typed_buffer_unittest.cc b/remoting/base/typed_buffer_unittest.cc
index 893ca08..0973d260 100644
--- a/remoting/base/typed_buffer_unittest.cc
+++ b/remoting/base/typed_buffer_unittest.cc
@@ -59,12 +59,12 @@
   EXPECT_TRUE(right.get());
   EXPECT_EQ(right.length(), sizeof(int));
 
-  Data* raw_ptr = right.get();
+  Data* ptr = right.get();
   left = std::move(right);
 
   // Verify that passing ownership transfers both the buffer pointer and its
   // length.
-  EXPECT_EQ(left.get(), raw_ptr);
+  EXPECT_EQ(left.get(), ptr);
   EXPECT_EQ(left.length(), sizeof(int));
 
   // Verify that the original object was cleared.
diff --git a/services/BUILD.gn b/services/BUILD.gn
index b0893845..491c68b4 100644
--- a/services/BUILD.gn
+++ b/services/BUILD.gn
@@ -46,6 +46,7 @@
       "//services/viz/public/cpp/compositing:tests",
       "//services/viz/public/cpp/gpu:tests",
       "//services/viz/public/cpp/hit_test:tests",
+      "//services/webnn:tests",
     ]
   }
 
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index 78347f4..61e5014a2 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -2302,6 +2302,17 @@
     return false;
   }
 
+  if (url_request_->was_cached() && !seen_raw_request_headers_) {
+    // If a response in a redirect chain has been cached,
+    // we need to clear the emitted_devtools_raw_request_ and
+    // emitted_devtools_raw_response_ flags to prevent misreporting
+    // that extra info was available on the response. We also suppress
+    // reporting the extra info events here.
+    emitted_devtools_raw_request_ = false;
+    emitted_devtools_raw_response_ = false;
+    return false;
+  }
+
   std::vector<network::mojom::HttpRawHeaderPairPtr> header_array;
 
   // This is gated by enable_reporting_raw_headers_ to be backwards compatible
diff --git a/services/webnn/BUILD.gn b/services/webnn/BUILD.gn
new file mode 100644
index 0000000..a048328
--- /dev/null
+++ b/services/webnn/BUILD.gn
@@ -0,0 +1,38 @@
+# Copyright 2023 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("webnn") {
+  sources = [
+    "webnn_context_impl.cc",
+    "webnn_context_impl.h",
+    "webnn_context_provider_impl.cc",
+    "webnn_context_provider_impl.h",
+    "webnn_graph_impl.cc",
+    "webnn_graph_impl.h",
+    "webnn_service.cc",
+    "webnn_service.h",
+  ]
+
+  deps = [
+    "//base",
+    "//mojo/public/cpp/bindings",
+    "//services/webnn/public/mojom",
+  ]
+}
+
+source_set("tests") {
+  testonly = true
+
+  sources = [ "webnn_context_impl_unittest.cc" ]
+
+  deps = [
+    ":webnn",
+    "//base",
+    "//base/test:test_support",
+    "//mojo/public/cpp/bindings",
+    "//mojo/public/cpp/test_support:test_utils",
+    "//services/webnn/public/mojom",
+    "//testing/gtest",
+  ]
+}
diff --git a/services/webnn/OWNERS b/services/webnn/OWNERS
new file mode 100644
index 0000000..73f064f1
--- /dev/null
+++ b/services/webnn/OWNERS
@@ -0,0 +1,5 @@
+rafael.cintron@microsoft.com
+kbr@chromium.org
+# Use the above owners as much as possible.
+amoylan@chromium.org
+qjw@chromium.org
diff --git a/services/webnn/README.md b/services/webnn/README.md
new file mode 100644
index 0000000..9f4e8ef
--- /dev/null
+++ b/services/webnn/README.md
@@ -0,0 +1,6 @@
+The WebNN service exists to facilitate neural network inference with accessing
+the hardware accelerated OS machine learning API.
+
+WebNN explainer: https://github.com/webmachinelearning/webnn/blob/main/explainer.md
+WebNN spec: https://www.w3.org/TR/webnn/
+WebNN service design doc: https://docs.google.com/document/d/1TMs36IE9wL9rNuh8lriGr51S8MU1JezU2SCZy-YqJ3Y/edit#heading=h.3z6obdxyjeka
diff --git a/services/webnn/public/mojom/BUILD.gn b/services/webnn/public/mojom/BUILD.gn
new file mode 100644
index 0000000..fa345293
--- /dev/null
+++ b/services/webnn/public/mojom/BUILD.gn
@@ -0,0 +1,16 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojom") {
+  sources = [
+    "webnn_graph.mojom",
+    "webnn_service.mojom",
+  ]
+  deps = [
+    "//mojo/public/mojom/base",
+    "//sandbox/policy/mojom",
+  ]
+}
diff --git a/services/webnn/public/mojom/OWNERS b/services/webnn/public/mojom/OWNERS
new file mode 100644
index 0000000..08850f4
--- /dev/null
+++ b/services/webnn/public/mojom/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/services/webnn/public/mojom/webnn_graph.mojom b/services/webnn/public/mojom/webnn_graph.mojom
new file mode 100644
index 0000000..4c3479e0
--- /dev/null
+++ b/services/webnn/public/mojom/webnn_graph.mojom
@@ -0,0 +1,13 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module webnn.mojom;
+
+// WebNNGraph runs in the GPU process and is called by the renderer process to
+// compile and execute a computational graph. Graph building and execution is
+// performed by calling hardware accelerated OS machine learning APIs.
+interface WebNNGraph {
+  // TODO(crbug.com/1273291): Add `Build` and `Compute` method to compile and
+  // execute computational graph with system framework.
+};
diff --git a/services/webnn/public/mojom/webnn_service.mojom b/services/webnn/public/mojom/webnn_service.mojom
new file mode 100644
index 0000000..753dbb1
--- /dev/null
+++ b/services/webnn/public/mojom/webnn_service.mojom
@@ -0,0 +1,62 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module webnn.mojom;
+
+import "services/webnn/public/mojom/webnn_graph.mojom";
+import "sandbox/policy/mojom/sandbox.mojom";
+
+enum PowerPreference {
+  // Let the user agent select the most suitable behavior.
+  kDefault = 0,
+  // Prioritizes execution speed over power consumption.
+  kHighPerformance = 1,
+  // Prioritizes power consumption over other considerations such as execution
+  // speed.
+  kLowPower = 2,
+};
+
+// Represents options of creating `WebNNContext` interface.
+struct CreateContextOptions {
+  // The power preference for power consumption.
+  PowerPreference power_preference;
+};
+
+enum CreateContextResult {
+  kOk,
+  kUnknownError,
+  // The input configuration is not supported.
+  kNotSupported,
+};
+
+// Represents the `MLContext` object in the WebIDL definition that is a global
+// state of neural network compute workload and execution processes. This
+// interface runs in the GPU process and is called from the renderer process.
+interface WebNNContext {
+  // Called by the renderer process to create `WebNNGraph` message pipe for
+  // compiling and executing computational graph
+  CreateGraph() => (pending_remote<WebNNGraph>? remote);
+};
+
+// This interface runs in the GPU process and is called from the renderer
+// process to create `WebNNContext` interface.
+interface WebNNContextProvider {
+  // Called by the renderer process to create a message pipe for `MLContext`,
+  // the `CreatContextResult::kNotSupported` with `mojo::NullRemote` will be
+  // thrown if the configuration of options isn't supported.
+  CreateWebNNContext(CreateContextOptions options)
+      => (CreateContextResult result, pending_remote<WebNNContext>? remote);
+};
+
+// Represents the WebNN service to infer computational graph. There is only
+// one service running in GPU process to access the hardware accelerated OS
+// machine learning API (e.g. Direct Machine Learning (DirectML) on Windows).
+[ServiceSandbox=sandbox.mojom.Sandbox.kGpu,
+ RequireContext=sandbox.mojom.Context.kBrowser]
+interface WebNNService {
+  // Bind `WebNNContextProvider` interface for every `navigator.ml` object which
+  // is called by the renderer with `BrowserInterfaceBroker's GetInterface()`
+  // method to create a `WebNNContext` interface.
+  BindWebNNContextProvider(pending_receiver<WebNNContextProvider> receiver);
+};
diff --git a/services/webnn/webnn_context_impl.cc b/services/webnn/webnn_context_impl.cc
new file mode 100644
index 0000000..16309ff
--- /dev/null
+++ b/services/webnn/webnn_context_impl.cc
@@ -0,0 +1,36 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/webnn/webnn_context_impl.h"
+
+#include <memory>
+#include <utility>
+
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "services/webnn/webnn_graph_impl.h"
+
+namespace webnn {
+
+WebNNContextImpl::WebNNContextImpl() = default;
+
+WebNNContextImpl::~WebNNContextImpl() = default;
+
+// static
+void WebNNContextImpl::Create(
+    mojo::PendingReceiver<mojom::WebNNContext> receiver) {
+  mojo::MakeSelfOwnedReceiver<mojom::WebNNContext>(
+      std::make_unique<WebNNContextImpl>(), std::move(receiver));
+}
+
+void WebNNContextImpl::CreateGraph(
+    mojom::WebNNContext::CreateGraphCallback callback) {
+  // The remote sent to the renderer.
+  mojo::PendingRemote<mojom::WebNNGraph> blink_remote;
+  // The receiver bound to WebNNGraphImpl.
+  WebNNGraphImpl::Create(blink_remote.InitWithNewPipeAndPassReceiver());
+
+  std::move(callback).Run(std::move(blink_remote));
+}
+
+}  // namespace webnn
diff --git a/services/webnn/webnn_context_impl.h b/services/webnn/webnn_context_impl.h
new file mode 100644
index 0000000..9d2060c
--- /dev/null
+++ b/services/webnn/webnn_context_impl.h
@@ -0,0 +1,31 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_WEBNN_WEBNN_CONTEXT_IMPL_H_
+#define SERVICES_WEBNN_WEBNN_CONTEXT_IMPL_H_
+
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "services/webnn/public/mojom/webnn_service.mojom.h"
+
+namespace webnn {
+
+class WebNNContextImpl : public mojom::WebNNContext {
+ public:
+  WebNNContextImpl();
+
+  WebNNContextImpl(const WebNNContextImpl&) = delete;
+  WebNNContextImpl& operator=(const WebNNContextImpl&) = delete;
+
+  ~WebNNContextImpl() override;
+
+  static void Create(mojo::PendingReceiver<mojom::WebNNContext> receiver);
+
+ private:
+  // mojom::WebNNContext
+  void CreateGraph(CreateGraphCallback callback) override;
+};
+
+}  // namespace webnn
+
+#endif  // SERVICES_WEBNN_WEBNN_CONTEXT_IMPL_H_
diff --git a/services/webnn/webnn_context_impl_unittest.cc b/services/webnn/webnn_context_impl_unittest.cc
new file mode 100644
index 0000000..585f5587
--- /dev/null
+++ b/services/webnn/webnn_context_impl_unittest.cc
@@ -0,0 +1,75 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/webnn/webnn_context_provider_impl.h"
+
+#include "base/run_loop.h"
+#include "base/test/bind.h"
+#include "base/test/task_environment.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "services/webnn/public/mojom/webnn_graph.mojom.h"
+#include "services/webnn/public/mojom/webnn_service.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace webnn {
+
+class WebNNContextImplTest : public testing::Test {
+ public:
+  WebNNContextImplTest(const WebNNContextImplTest&) = delete;
+  WebNNContextImplTest& operator=(const WebNNContextImplTest&) = delete;
+
+ protected:
+  WebNNContextImplTest() = default;
+  ~WebNNContextImplTest() override = default;
+
+ private:
+  base::test::TaskEnvironment task_environment_;
+};
+
+TEST_F(WebNNContextImplTest, CreateWebNNGraphTest) {
+  mojo::Remote<mojom::WebNNContextProvider> provider_remote;
+  mojo::Remote<mojom::WebNNContext> webnn_context_remote;
+
+  WebNNContextProviderImpl::Create(
+      provider_remote.BindNewPipeAndPassReceiver());
+
+  bool is_callback_called = false;
+  base::RunLoop run_loop_create_context;
+  auto options = mojom::CreateContextOptions::New();
+  provider_remote->CreateWebNNContext(
+      std::move(options),
+      base::BindLambdaForTesting(
+          [&](mojom::CreateContextResult result,
+              mojo::PendingRemote<mojom::WebNNContext> remote) {
+#if BUILDFLAG(IS_WIN)
+            EXPECT_EQ(result, mojom::CreateContextResult::kOk);
+            webnn_context_remote.Bind(std::move(remote));
+#else
+            EXPECT_EQ(result, mojom::CreateContextResult::kNotSupported);
+#endif
+            is_callback_called = true;
+            run_loop_create_context.Quit();
+          }));
+  run_loop_create_context.Run();
+  EXPECT_TRUE(is_callback_called);
+
+  if (!webnn_context_remote.is_bound()) {
+    // Don't continue testing for unsupported platforms.
+    return;
+  }
+
+  base::RunLoop run_loop_create_graph;
+  is_callback_called = false;
+  webnn_context_remote->CreateGraph(base::BindLambdaForTesting(
+      [&](mojo::PendingRemote<mojom::WebNNGraph> remote) {
+        EXPECT_TRUE(remote.is_valid());
+        is_callback_called = true;
+        run_loop_create_graph.Quit();
+      }));
+  run_loop_create_graph.Run();
+  EXPECT_TRUE(is_callback_called);
+}
+
+}  // namespace webnn
diff --git a/services/webnn/webnn_context_provider_impl.cc b/services/webnn/webnn_context_provider_impl.cc
new file mode 100644
index 0000000..928dbfe
--- /dev/null
+++ b/services/webnn/webnn_context_provider_impl.cc
@@ -0,0 +1,51 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/webnn/webnn_context_provider_impl.h"
+
+#include <memory>
+#include <utility>
+
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "services/webnn/webnn_context_impl.h"
+
+namespace webnn {
+
+namespace {
+
+using webnn::mojom::CreateContextOptionsPtr;
+using webnn::mojom::WebNNContextProvider;
+
+}  // namespace
+
+WebNNContextProviderImpl::WebNNContextProviderImpl() = default;
+
+WebNNContextProviderImpl::~WebNNContextProviderImpl() = default;
+
+// static
+void WebNNContextProviderImpl::Create(
+    mojo::PendingReceiver<WebNNContextProvider> receiver) {
+  mojo::MakeSelfOwnedReceiver<WebNNContextProvider>(
+      std::make_unique<WebNNContextProviderImpl>(), std::move(receiver));
+}
+
+void WebNNContextProviderImpl::CreateWebNNContext(
+    CreateContextOptionsPtr options,
+    WebNNContextProvider::CreateWebNNContextCallback callback) {
+#if BUILDFLAG(IS_WIN)
+  // The remote sent to the renderer.
+  mojo::PendingRemote<mojom::WebNNContext> blink_remote;
+  // The receiver bound to WebNNContextImpl.
+  WebNNContextImpl::Create(blink_remote.InitWithNewPipeAndPassReceiver());
+  std::move(callback).Run(mojom::CreateContextResult::kOk,
+                          std::move(blink_remote));
+#else
+  // TODO(crbug.com/1273291): Supporting WebNN Service on the platform.
+  std::move(callback).Run(mojom::CreateContextResult::kNotSupported,
+                          mojo::NullRemote());
+  DLOG(ERROR) << "Platform not supported for WebNN Service.";
+#endif
+}
+
+}  // namespace webnn
diff --git a/services/webnn/webnn_context_provider_impl.h b/services/webnn/webnn_context_provider_impl.h
new file mode 100644
index 0000000..bfb5ca4
--- /dev/null
+++ b/services/webnn/webnn_context_provider_impl.h
@@ -0,0 +1,33 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_WEBNN_WEBNN_CONTEXT_PROVIDER_IMPL_H_
+#define SERVICES_WEBNN_WEBNN_CONTEXT_PROVIDER_IMPL_H_
+
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "services/webnn/public/mojom/webnn_service.mojom.h"
+
+namespace webnn {
+
+class WebNNContextProviderImpl : public mojom::WebNNContextProvider {
+ public:
+  WebNNContextProviderImpl();
+
+  WebNNContextProviderImpl(const WebNNContextProviderImpl&) = delete;
+  WebNNContextProviderImpl& operator=(const WebNNContextProviderImpl&) = delete;
+
+  ~WebNNContextProviderImpl() override;
+
+  static void Create(
+      mojo::PendingReceiver<mojom::WebNNContextProvider> receiver);
+
+ private:
+  // mojom::WebNNContextProvider
+  void CreateWebNNContext(mojom::CreateContextOptionsPtr options,
+                          CreateWebNNContextCallback callback) override;
+};
+
+}  // namespace webnn
+
+#endif  // SERVICES_WEBNN_WEBNN_CONTEXT_PROVIDER_IMPL_H_
diff --git a/services/webnn/webnn_graph_impl.cc b/services/webnn/webnn_graph_impl.cc
new file mode 100644
index 0000000..fbf4ceb4
--- /dev/null
+++ b/services/webnn/webnn_graph_impl.cc
@@ -0,0 +1,24 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/webnn/webnn_graph_impl.h"
+
+#include <memory>
+#include <utility>
+
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+
+namespace webnn {
+
+WebNNGraphImpl::WebNNGraphImpl() = default;
+
+WebNNGraphImpl::~WebNNGraphImpl() = default;
+
+// static
+void WebNNGraphImpl::Create(mojo::PendingReceiver<mojom::WebNNGraph> receiver) {
+  mojo::MakeSelfOwnedReceiver<mojom::WebNNGraph>(
+      std::make_unique<WebNNGraphImpl>(), std::move(receiver));
+}
+
+}  // namespace webnn
diff --git a/services/webnn/webnn_graph_impl.h b/services/webnn/webnn_graph_impl.h
new file mode 100644
index 0000000..5e1d88a
--- /dev/null
+++ b/services/webnn/webnn_graph_impl.h
@@ -0,0 +1,25 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_WEBNN_WEBNN_GRAPH_IMPL_H_
+#define SERVICES_WEBNN_WEBNN_GRAPH_IMPL_H_
+
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "services/webnn/public/mojom/webnn_graph.mojom.h"
+
+namespace webnn {
+
+class WebNNGraphImpl : public mojom::WebNNGraph {
+ public:
+  WebNNGraphImpl();
+  WebNNGraphImpl(const WebNNGraphImpl&) = delete;
+  WebNNGraphImpl& operator=(const WebNNGraphImpl&) = delete;
+  ~WebNNGraphImpl() override;
+
+  static void Create(mojo::PendingReceiver<mojom::WebNNGraph> receiver);
+};
+
+}  // namespace webnn
+
+#endif  // SERVICES_WEBNN_WEBNN_GRAPH_IMPL_H_
diff --git a/services/webnn/webnn_service.cc b/services/webnn/webnn_service.cc
new file mode 100644
index 0000000..b68a6e5
--- /dev/null
+++ b/services/webnn/webnn_service.cc
@@ -0,0 +1,23 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/webnn/webnn_service.h"
+
+#include "base/no_destructor.h"
+#include "build/buildflag.h"
+#include "services/webnn/webnn_context_provider_impl.h"
+
+namespace webnn {
+
+WebNNService::WebNNService(mojo::PendingReceiver<mojom::WebNNService> receiver)
+    : receiver_(this, std::move(receiver)) {}
+
+WebNNService::~WebNNService() = default;
+
+void WebNNService::BindWebNNContextProvider(
+    mojo::PendingReceiver<mojom::WebNNContextProvider> receiver) {
+  WebNNContextProviderImpl::Create(std::move(receiver));
+}
+
+}  // namespace webnn
diff --git a/services/webnn/webnn_service.h b/services/webnn/webnn_service.h
new file mode 100644
index 0000000..1d2835fb
--- /dev/null
+++ b/services/webnn/webnn_service.h
@@ -0,0 +1,32 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_WEBNN_WEBNN_SERVICE_H_
+#define SERVICES_WEBNN_WEBNN_SERVICE_H_
+
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "services/webnn/public/mojom/webnn_service.mojom.h"
+
+namespace webnn {
+
+class WebNNService : public mojom::WebNNService {
+ public:
+  explicit WebNNService(mojo::PendingReceiver<mojom::WebNNService> receiver);
+
+  WebNNService(const WebNNService&) = delete;
+  WebNNService& operator=(const WebNNService&) = delete;
+
+  ~WebNNService() override;
+
+  void BindWebNNContextProvider(
+      mojo::PendingReceiver<mojom::WebNNContextProvider> receiver) override;
+
+ private:
+  mojo::Receiver<mojom::WebNNService> receiver_;
+};
+
+}  // namespace webnn
+
+#endif  // SERVICES_WEBNN_WEBNN_SERVICE_H_
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 89f8c6cb..9343d78 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -6509,7 +6509,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -6572,7 +6572,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -6634,7 +6634,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -6695,7 +6695,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -6748,7 +6748,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -6800,7 +6800,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -6860,7 +6860,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -6920,7 +6920,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -6980,7 +6980,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -7041,7 +7041,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -7102,7 +7102,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -7162,7 +7162,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -7223,7 +7223,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -7283,7 +7283,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -7344,7 +7344,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -7404,7 +7404,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -7475,7 +7475,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -7613,7 +7613,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -7674,7 +7674,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -7738,7 +7738,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -7799,7 +7799,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -7863,7 +7863,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -7926,7 +7926,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -7988,7 +7988,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -8053,7 +8053,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -8115,7 +8115,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -8175,7 +8175,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -8236,7 +8236,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -8296,7 +8296,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -8356,7 +8356,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -8416,7 +8416,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -8476,7 +8476,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -8536,7 +8536,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -8599,7 +8599,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -8660,7 +8660,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -8720,7 +8720,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -8780,7 +8780,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -8840,7 +8840,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -8900,7 +8900,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -8960,7 +8960,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9020,7 +9020,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9080,7 +9080,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9141,7 +9141,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9201,7 +9201,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9261,7 +9261,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9321,7 +9321,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9381,7 +9381,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9444,7 +9444,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9504,7 +9504,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9565,7 +9565,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9626,7 +9626,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9686,7 +9686,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9746,7 +9746,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9806,7 +9806,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9866,7 +9866,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9926,7 +9926,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -9986,7 +9986,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -10046,7 +10046,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -10106,7 +10106,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -10166,7 +10166,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -10227,7 +10227,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -10287,7 +10287,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -10348,7 +10348,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -10409,7 +10409,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -10469,7 +10469,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -10535,7 +10535,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -10604,7 +10604,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -10677,7 +10677,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -10739,7 +10739,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -10799,7 +10799,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -10859,7 +10859,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
@@ -10915,7 +10915,7 @@
               "cpu": "x86-64",
               "device_os": null,
               "device_type": null,
-              "os": "Ubuntu-18.04",
+              "os": "Ubuntu-22.04",
               "pool": "chromium.tests.avd"
             }
           ],
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 1a3652c..f9645f1 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5585,9 +5585,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5720.0",
+        "description": "Run with ash-chrome version 114.0.5721.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5598,8 +5598,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5720.0",
-              "revision": "version:114.0.5720.0"
+              "location": "lacros_version_skew_tests_v114.0.5721.0",
+              "revision": "version:114.0.5721.0"
             }
           ],
           "dimension_sets": [
@@ -5752,9 +5752,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5720.0",
+        "description": "Run with ash-chrome version 114.0.5721.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5765,8 +5765,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5720.0",
-              "revision": "version:114.0.5720.0"
+              "location": "lacros_version_skew_tests_v114.0.5721.0",
+              "revision": "version:114.0.5721.0"
             }
           ],
           "dimension_sets": [
@@ -5901,9 +5901,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5720.0",
+        "description": "Run with ash-chrome version 114.0.5721.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5914,8 +5914,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5720.0",
-              "revision": "version:114.0.5720.0"
+              "location": "lacros_version_skew_tests_v114.0.5721.0",
+              "revision": "version:114.0.5721.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json
index dcc9c770..bbcfc9d0 100644
--- a/testing/buildbot/chromium.coverage.json
+++ b/testing/buildbot/chromium.coverage.json
@@ -25211,9 +25211,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5720.0",
+        "description": "Run with ash-chrome version 114.0.5721.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25224,8 +25224,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5720.0",
-              "revision": "version:114.0.5720.0"
+              "location": "lacros_version_skew_tests_v114.0.5721.0",
+              "revision": "version:114.0.5721.0"
             }
           ],
           "dimension_sets": [
@@ -25378,9 +25378,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5720.0",
+        "description": "Run with ash-chrome version 114.0.5721.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25391,8 +25391,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5720.0",
-              "revision": "version:114.0.5720.0"
+              "location": "lacros_version_skew_tests_v114.0.5721.0",
+              "revision": "version:114.0.5721.0"
             }
           ],
           "dimension_sets": [
@@ -25527,9 +25527,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5720.0",
+        "description": "Run with ash-chrome version 114.0.5721.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25540,8 +25540,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5720.0",
-              "revision": "version:114.0.5720.0"
+              "location": "lacros_version_skew_tests_v114.0.5721.0",
+              "revision": "version:114.0.5721.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 80d2e94d..2a47a172 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -33947,9 +33947,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5720.0",
+        "description": "Run with ash-chrome version 114.0.5721.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -33959,8 +33959,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5720.0",
-              "revision": "version:114.0.5720.0"
+              "location": "lacros_version_skew_tests_v114.0.5721.0",
+              "revision": "version:114.0.5721.0"
             }
           ],
           "dimension_sets": [
@@ -34114,9 +34114,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5720.0",
+        "description": "Run with ash-chrome version 114.0.5721.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -34126,8 +34126,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5720.0",
-              "revision": "version:114.0.5720.0"
+              "location": "lacros_version_skew_tests_v114.0.5721.0",
+              "revision": "version:114.0.5721.0"
             }
           ],
           "dimension_sets": [
@@ -34263,9 +34263,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5720.0",
+        "description": "Run with ash-chrome version 114.0.5721.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -34275,8 +34275,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5720.0",
-              "revision": "version:114.0.5720.0"
+              "location": "lacros_version_skew_tests_v114.0.5721.0",
+              "revision": "version:114.0.5721.0"
             }
           ],
           "dimension_sets": [
@@ -35705,9 +35705,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5720.0",
+        "description": "Run with ash-chrome version 114.0.5721.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -35717,8 +35717,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5720.0",
-              "revision": "version:114.0.5720.0"
+              "location": "lacros_version_skew_tests_v114.0.5721.0",
+              "revision": "version:114.0.5721.0"
             }
           ],
           "dimension_sets": [
@@ -35872,9 +35872,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5720.0",
+        "description": "Run with ash-chrome version 114.0.5721.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -35884,8 +35884,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5720.0",
-              "revision": "version:114.0.5720.0"
+              "location": "lacros_version_skew_tests_v114.0.5721.0",
+              "revision": "version:114.0.5721.0"
             }
           ],
           "dimension_sets": [
@@ -36021,9 +36021,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5720.0",
+        "description": "Run with ash-chrome version 114.0.5721.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -36033,8 +36033,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5720.0",
-              "revision": "version:114.0.5720.0"
+              "location": "lacros_version_skew_tests_v114.0.5721.0",
+              "revision": "version:114.0.5721.0"
             }
           ],
           "dimension_sets": [
@@ -36752,9 +36752,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5720.0",
+        "description": "Run with ash-chrome version 114.0.5721.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -36764,8 +36764,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5720.0",
-              "revision": "version:114.0.5720.0"
+              "location": "lacros_version_skew_tests_v114.0.5721.0",
+              "revision": "version:114.0.5721.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 81ce880..a9ea3d3f 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -17723,12 +17723,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 114.0.5720.0",
+        "description": "Run with ash-chrome version 114.0.5721.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -17739,8 +17739,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5720.0",
-              "revision": "version:114.0.5720.0"
+              "location": "lacros_version_skew_tests_v114.0.5721.0",
+              "revision": "version:114.0.5721.0"
             }
           ],
           "dimension_sets": [
@@ -17910,12 +17910,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 114.0.5720.0",
+        "description": "Run with ash-chrome version 114.0.5721.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -17926,8 +17926,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5720.0",
-              "revision": "version:114.0.5720.0"
+              "location": "lacros_version_skew_tests_v114.0.5721.0",
+              "revision": "version:114.0.5721.0"
             }
           ],
           "dimension_sets": [
@@ -18074,12 +18074,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 114.0.5720.0",
+        "description": "Run with ash-chrome version 114.0.5721.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -18090,8 +18090,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5720.0",
-              "revision": "version:114.0.5720.0"
+              "location": "lacros_version_skew_tests_v114.0.5721.0",
+              "revision": "version:114.0.5721.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 4831a45..edbe5e5 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1519,6 +1519,12 @@
           '--avd-config=../../tools/android/avd/proto/generic_playstore_android31.textpb',
         ],
         'swarming': {
+          'dimension_sets': [
+            {
+              # TODO(crbug.com/1434504): Move this to jammy.
+              'os': 'Ubuntu-18.04',
+            },
+          ],
           # soft affinity so that bots with caches will be picked first
           'optional_dimensions': {
             '60': [
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index fffe62a..8178d557 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -22,16 +22,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5720.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5721.0/test_ash_chrome',
     ],
-    'description': 'Run with ash-chrome version 114.0.5720.0',
+    'description': 'Run with ash-chrome version 114.0.5721.0',
     'identifier': 'Lacros version skew testing ash canary',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v114.0.5720.0',
-          'revision': 'version:114.0.5720.0',
+          'location': 'lacros_version_skew_tests_v114.0.5721.0',
+          'revision': 'version:114.0.5721.0',
         },
       ],
     },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index d14fc5f..32c58177 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -733,7 +733,7 @@
           '12-x64-emulator',
           'emulator-8-cores',
           'has_native_resultdb_integration',
-          'linux-bionic',
+          'linux-jammy',
           'x86-64',
         ],
         'args': [
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index b783b01..0f954b2 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -12155,6 +12155,29 @@
             ]
         }
     ],
+    "SpeculationRulesPrerenderMemoryLimit": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "chromeos_lacros",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "ExperimentalMemoryLimit60_20230412",
+                    "params": {
+                        "acceptable_percent_of_system_memory": "60"
+                    },
+                    "enable_features": [
+                        "Prerender2MemoryControls"
+                    ]
+                }
+            ]
+        }
+    ],
     "SpeculativeServiceWorkerStartup": [
         {
             "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 2ae6a3f..232b07402 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -349,15 +349,6 @@
     kSharedStorageMaxAllowedFencedFrameDepthForSelectURL = {
         &kSharedStorageAPI,
         "SharedStorageMaxAllowedFencedFrameDepthForSelectURL", 1};
-const base::FeatureParam<SharedStorageWorkletImplementationType>::Option
-    shared_storage_worklet_implementation_types[] = {
-        {SharedStorageWorkletImplementationType::kLegacy, "legacy"},
-        {SharedStorageWorkletImplementationType::kBlinkStyle, "blink_style"}};
-const base::FeatureParam<SharedStorageWorkletImplementationType>
-    kSharedStorageWorkletImplementationType = {
-        &kSharedStorageAPI, "SharedStorageWorkletImplementationType",
-        SharedStorageWorkletImplementationType::kBlinkStyle,
-        &shared_storage_worklet_implementation_types};
 
 BASE_FEATURE(kSharedStorageSelectURLLimit,
              "SharedStorageSelectURLLimit",
@@ -1494,6 +1485,10 @@
              "ThreadedPreloadScanner",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kEnableMachineLearningNeuralNetworkService,
+             "MachineLearningNeuralNetworkService",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kFileSystemUrlNavigation,
              "FileSystemUrlNavigation",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/third_party/blink/public/common/associated_interfaces/associated_interface_provider.h b/third_party/blink/public/common/associated_interfaces/associated_interface_provider.h
index f1da4b9..342a194 100644
--- a/third_party/blink/public/common/associated_interfaces/associated_interface_provider.h
+++ b/third_party/blink/public/common/associated_interfaces/associated_interface_provider.h
@@ -68,7 +68,13 @@
 
   template <typename Interface>
   void GetInterface(mojo::AssociatedRemote<Interface>* remote) {
-    GetInterface(remote->BindNewEndpointAndPassReceiver(task_runner_));
+    GetInterface(remote->BindNewEndpointAndPassReceiver(GetTaskRunner()));
+  }
+
+  // Returns the task runner for this provider so callers can generate pending
+  // receivers if needed.
+  scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() {
+    return task_runner_;
   }
 
   // If there is an override for `name`, passing in a null `binder` removes the
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index d4e103e..496d8918 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -91,16 +91,6 @@
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(
     kPrivateAggregationApiFledgeExtensionsLocalTestingOverride);
 
-enum class SharedStorageWorkletImplementationType {
-  // The worklet thread is created via base::SequenceBound, and JS bindings are
-  // added with native v8 and/or Gin library.
-  kLegacy,
-
-  // Use the blink worklet pattern (i.e. blink::ThreadedWorkletMessagingProxy,
-  // blink::WorkerThread, IDL, etc.) to create the thread and add JS bindings.
-  kBlinkStyle,
-};
-
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kSharedStorageAPI);
 // Maximum number of URLs allowed to be included in the input parameter for
 // runURLSelectionOperation().
@@ -155,10 +145,6 @@
 // main frame has fenced frame depth 1, etc).
 BLINK_COMMON_EXPORT extern const base::FeatureParam<int>
     kSharedStorageMaxAllowedFencedFrameDepthForSelectURL;
-// The implementation type of the worklet.
-BLINK_COMMON_EXPORT extern const base::FeatureParam<
-    SharedStorageWorkletImplementationType>
-    kSharedStorageWorkletImplementationType;
 
 // If enabled, limits the number of times per origin per pageload that
 // `sharedStorage.selectURL()` is allowed to be invoked.
@@ -761,6 +747,12 @@
 // If enabled, allows the use of WebSQL in non-secure contexts.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kWebSQLNonSecureContextAccess);
 
+// Enables the Web Machine Learning Neural Network Service to access hardware
+// acceleration out of renderer process. Explainer:
+// https://github.com/webmachinelearning/webnn/blob/main/explainer.md
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(
+    kEnableMachineLearningNeuralNetworkService);
+
 // Switch to temporary turn back on file system url navigation.
 // TODO(https://crbug.com/1332598): Remove this feature.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kFileSystemUrlNavigation);
diff --git a/third_party/blink/renderer/core/frame/viewport_data.cc b/third_party/blink/renderer/core/frame/viewport_data.cc
index 6928985..bd9f942 100644
--- a/third_party/blink/renderer/core/frame/viewport_data.cc
+++ b/third_party/blink/renderer/core/frame/viewport_data.cc
@@ -6,6 +6,7 @@
 
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
@@ -18,10 +19,13 @@
 
 namespace blink {
 
-ViewportData::ViewportData(Document& document) : document_(document) {}
+ViewportData::ViewportData(Document& document)
+    : document_(document),
+      display_cutout_host_(document_->GetExecutionContext()) {}
 
 void ViewportData::Trace(Visitor* visitor) const {
   visitor->Trace(document_);
+  visitor->Trace(display_cutout_host_);
 }
 
 void ViewportData::Shutdown() {
@@ -100,7 +104,9 @@
                 ->GetRemoteNavigationAssociatedInterfaces()) {
       // Bind the mojo interface.
       if (!display_cutout_host_.is_bound()) {
-        provider->GetInterface(&display_cutout_host_);
+        provider->GetInterface(
+            display_cutout_host_.BindNewEndpointAndPassReceiver(
+                provider->GetTaskRunner()));
         DCHECK(display_cutout_host_.is_bound());
       }
 
diff --git a/third_party/blink/renderer/core/frame/viewport_data.h b/third_party/blink/renderer/core/frame/viewport_data.h
index 0d9b5f00..2becceb 100644
--- a/third_party/blink/renderer/core/frame/viewport_data.h
+++ b/third_party/blink/renderer/core/frame/viewport_data.h
@@ -5,12 +5,12 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_VIEWPORT_DATA_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_VIEWPORT_DATA_H_
 
-#include "mojo/public/cpp/bindings/associated_remote.h"
 #include "third_party/blink/public/mojom/page/display_cutout.mojom-blink-forward.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/page/viewport_description.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote.h"
 #include "third_party/blink/renderer/platform/wtf/gc_plugin.h"
 
 namespace blink {
@@ -60,8 +60,8 @@
   mojom::ViewportFit viewport_fit_ = blink::mojom::ViewportFit::kAuto;
   bool force_expand_display_cutout_ = false;
 
-  GC_PLUGIN_IGNORE("https://crbug.com/1381979")
-  mojo::AssociatedRemote<mojom::blink::DisplayCutoutHost> display_cutout_host_;
+  HeapMojoAssociatedRemote<mojom::blink::DisplayCutoutHost>
+      display_cutout_host_;
 };
 
 inline bool ViewportData::ShouldOverrideLegacyDescription(
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn
index 0799581..855d335 100644
--- a/third_party/blink/renderer/modules/BUILD.gn
+++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -282,6 +282,7 @@
     "//services/device/public/mojom:mojom_blink_headers",
     "//services/device/public/mojom:usb_blink_headers",
     "//services/shape_detection/public/mojom:mojom_blink_headers",
+    "//services/webnn/public/mojom:mojom_blink_headers",
     "//third_party/blink/public/mojom:mojom_modules_blink_headers",
     "//third_party/blink/renderer/bindings/modules/v8:generated",
     "//third_party/blink/renderer/core:core_event_interfaces",
diff --git a/third_party/blink/renderer/modules/accessibility/blink_ax_tree_source.cc b/third_party/blink/renderer/modules/accessibility/blink_ax_tree_source.cc
index 2ce5b792..480f956f6 100644
--- a/third_party/blink/renderer/modules/accessibility/blink_ax_tree_source.cc
+++ b/third_party/blink/renderer/modules/accessibility/blink_ax_tree_source.cc
@@ -280,7 +280,6 @@
 
 AXObject* BlinkAXTreeSource::GetFromId(int32_t id) const {
   AXObject* result = ax_object_cache_->ObjectFromAXID(id);
-  DCHECK(result);
   if (result && !result->AccessibilityIsIncludedInTree()) {
     DCHECK(false) << "Should not serialize an unincluded object:"
                   << "\nChild: " << result->ToString(true).Utf8();
diff --git a/third_party/blink/renderer/modules/ml/BUILD.gn b/third_party/blink/renderer/modules/ml/BUILD.gn
index e678743..2391625 100644
--- a/third_party/blink/renderer/modules/ml/BUILD.gn
+++ b/third_party/blink/renderer/modules/ml/BUILD.gn
@@ -43,6 +43,7 @@
   deps = [
     ":buildflags",
     "//components/ml/mojom:mojom_blink",
+    "//services/webnn/public/mojom:mojom_blink",
   ]
 
   if (build_webnn_with_xnnpack) {
@@ -65,6 +66,17 @@
       "//third_party/tflite:tflite_public_headers",
     ]
   }
+
+  if (!is_chromeos) {
+    sources += [
+      # MLGraphMojo is platform independent which packages the model information
+      # into a neutral struct type, it will be built and executed with hardware
+      # accelerated OS machine learning API in WebNN Service which run out of
+      # renderer process.
+      "webnn/ml_graph_mojo.cc",
+      "webnn/ml_graph_mojo.h",
+    ]
+  }
 }
 
 source_set("unit_tests") {
@@ -83,6 +95,7 @@
 
   deps = [
     "//components/ml/mojom:mojom_blink",
+    "//services/webnn/public/mojom:mojom_blink",
     "//testing/gtest",
     "//third_party/blink/public:test_headers",
     "//third_party/blink/renderer/controller:blink_bindings_test_sources",
@@ -105,4 +118,8 @@
     sources += [ "webnn/ml_graph_test_cros.cc" ]
     deps += [ "//third_party/tflite" ]
   }
+
+  if (!is_chromeos) {
+    sources += [ "webnn/ml_graph_test_mojo.cc" ]
+  }
 }
diff --git a/third_party/blink/renderer/modules/ml/DEPS b/third_party/blink/renderer/modules/ml/DEPS
index a1d3fc9c..41b4e49 100644
--- a/third_party/blink/renderer/modules/ml/DEPS
+++ b/third_party/blink/renderer/modules/ml/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
-    "+components/ml/mojom"
+    "+components/ml/mojom",
+    "+services/webnn/public/mojom",
 ]
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/ml/ml.cc b/third_party/blink/renderer/modules/ml/ml.cc
index 8749b16..8dce516 100644
--- a/third_party/blink/renderer/modules/ml/ml.cc
+++ b/third_party/blink/renderer/modules/ml/ml.cc
@@ -21,18 +21,33 @@
 
 ML::ML(ExecutionContext* execution_context)
     : ExecutionContextClient(execution_context),
-      remote_service_(execution_context) {}
+      model_loader_service_(execution_context),
+      webnn_context_provider_(execution_context) {}
 
 void ML::CreateModelLoader(ScriptState* script_state,
                            CreateModelLoaderOptionsPtr options,
                            MLService::CreateModelLoaderCallback callback) {
-  BootstrapMojoConnectionIfNeeded(script_state);
+  EnsureModelLoaderServiceConnection(script_state);
 
-  remote_service_->CreateModelLoader(std::move(options), std::move(callback));
+  model_loader_service_->CreateModelLoader(std::move(options),
+                                           std::move(callback));
+}
+
+void ML::CreateWebNNContext(
+    webnn::mojom::blink::CreateContextOptionsPtr options,
+    webnn::mojom::blink::WebNNContextProvider::CreateWebNNContextCallback
+        callback) {
+  // Connect WebNN Service if needed.
+  EnsureWebNNServiceConnection();
+
+  // Create `WebNNGraph` message pipe with `WebNNContext` mojo interface.
+  webnn_context_provider_->CreateWebNNContext(std::move(options),
+                                              std::move(callback));
 }
 
 void ML::Trace(Visitor* visitor) const {
-  visitor->Trace(remote_service_);
+  visitor->Trace(model_loader_service_);
+  visitor->Trace(webnn_context_provider_);
   ExecutionContextClient::Trace(visitor);
   ScriptWrappable::Trace(visitor);
 }
@@ -78,7 +93,7 @@
       options->modelFormat(), options->numThreads(), this);
 }
 
-void ML::BootstrapMojoConnectionIfNeeded(ScriptState* script_state) {
+void ML::EnsureModelLoaderServiceConnection(ScriptState* script_state) {
   // The execution context of this navigator is valid here because it has been
   // verified at the beginning of `MLModelLoader::load()` function.
   CHECK(script_state->ContextIsValid());
@@ -87,11 +102,20 @@
   // the ScriptState passed in may not be guaranteed to match the execution
   // context associated with this navigator, especially with
   // cross-browsing-context calls.
-  if (!remote_service_.is_bound()) {
+  if (!model_loader_service_.is_bound()) {
     GetExecutionContext()->GetBrowserInterfaceBroker().GetInterface(
-        remote_service_.BindNewPipeAndPassReceiver(
+        model_loader_service_.BindNewPipeAndPassReceiver(
             GetExecutionContext()->GetTaskRunner(TaskType::kInternalDefault)));
   }
 }
 
+void ML::EnsureWebNNServiceConnection() {
+  if (webnn_context_provider_.is_bound()) {
+    return;
+  }
+  GetExecutionContext()->GetBrowserInterfaceBroker().GetInterface(
+      webnn_context_provider_.BindNewPipeAndPassReceiver(
+          GetExecutionContext()->GetTaskRunner(TaskType::kInternalDefault)));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/ml.h b/third_party/blink/renderer/modules/ml/ml.h
index 2209148..fcf9a0f6 100644
--- a/third_party/blink/renderer/modules/ml/ml.h
+++ b/third_party/blink/renderer/modules/ml/ml.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_ML_ML_H_
 
 #include "components/ml/mojom/ml_service.mojom-blink.h"
+#include "services/webnn/public/mojom/webnn_service.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
@@ -40,6 +41,13 @@
       ml::model_loader::mojom::blink::MLService::CreateModelLoaderCallback
           callback);
 
+  // Create `WebNNContext` message pipe with `WebNNContextProvider` mojo
+  // interface.
+  void CreateWebNNContext(
+      webnn::mojom::blink::CreateContextOptionsPtr options,
+      webnn::mojom::blink::WebNNContextProvider::CreateWebNNContextCallback
+          callback);
+
   void Trace(blink::Visitor*) const override;
 
   // IDL interface:
@@ -51,12 +59,25 @@
                                ExceptionState& exception_state);
 
  private:
-  // Binds the Mojo connection to browser process if needed.
+  // Binds the ModelLoader Mojo connection to browser process if needed.
   // Caller is responsible to ensure `script_state` has a valid
   // `ExecutionContext`.
-  void BootstrapMojoConnectionIfNeeded(ScriptState* script_state);
+  void EnsureModelLoaderServiceConnection(ScriptState* script_state);
+  HeapMojoRemote<ml::model_loader::mojom::blink::MLService>
+      model_loader_service_;
 
-  HeapMojoRemote<ml::model_loader::mojom::blink::MLService> remote_service_;
+  // There is only one WebNN service running out of renderer process to access
+  // the hardware accelerated OS machine learning API. Every `navigator.ml`
+  // object has one `WebNNContextProvider` message pipe to create `WebNNContext`
+  // mojo interface.
+  void EnsureWebNNServiceConnection();
+
+  // WebNN support multiple types of neural network inference hardware
+  // acceleration such as CPU, GPU and ML specialized accelerator, the context
+  // of webnn in service is used to map different device and represent a state
+  // of graph execution processes.
+  HeapMojoRemote<webnn::mojom::blink::WebNNContextProvider>
+      webnn_context_provider_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/ml_context.cc b/third_party/blink/renderer/modules/ml/ml_context.cc
index 29786a7f7..1be0f92 100644
--- a/third_party/blink/renderer/modules/ml/ml_context.cc
+++ b/third_party/blink/renderer/modules/ml/ml_context.cc
@@ -21,7 +21,8 @@
       power_preference_(power_preference),
       model_format_(model_format),
       num_threads_(num_threads),
-      ml_(ml) {}
+      ml_(ml),
+      webnn_context_(ml->GetExecutionContext()) {}
 
 MLContext::~MLContext() = default;
 
@@ -67,6 +68,7 @@
 void MLContext::Trace(Visitor* visitor) const {
   visitor->Trace(ml_);
   visitor->Trace(ml_model_loader_);
+  visitor->Trace(webnn_context_);
 
   ScriptWrappable::Trace(visitor);
 }
@@ -110,4 +112,56 @@
   graph->ComputeSync(inputs, outputs, exception_state);
 }
 
+void MLContext::CreateWebNNGraph(ScriptState* script_state,
+                                 CreateWebNNGraphCallback callback) {
+  if (!webnn_context_.is_bound()) {
+    // Needs to create `WebNNContext` interface first.
+    auto options = webnn::mojom::blink::CreateContextOptions::New();
+    // TODO(crbug.com/1273291): Set power preference in the context option.
+    ml_->CreateWebNNContext(
+        std::move(options),
+        WTF::BindOnce(&MLContext::OnCreateWebNNContext, WrapPersistent(this),
+                      WrapPersistent(script_state), std::move(callback)));
+  } else {
+    // Directly use `WebNNContext` to create `WebNNGraph` message pipe.
+    webnn_context_->CreateGraph(
+        WTF::BindOnce(std::move(callback), CreateWebNNGraphResult::kOk));
+  }
+}
+
+void MLContext::OnCreateWebNNContext(
+    ScriptState* script_state,
+    CreateWebNNGraphCallback callback,
+    webnn::mojom::blink::CreateContextResult result,
+    mojo::PendingRemote<webnn::mojom::blink::WebNNContext>
+        pending_remote_context) {
+  if (!script_state->ContextIsValid()) {
+    std::move(callback).Run(CreateWebNNGraphResult::kUnknownError,
+                            mojo::NullRemote());
+    return;
+  }
+  switch (result) {
+    case webnn::mojom::blink::CreateContextResult::kUnknownError: {
+      std::move(callback).Run(CreateWebNNGraphResult::kUnknownError,
+                              mojo::NullRemote());
+      return;
+    }
+    case webnn::mojom::blink::CreateContextResult::kNotSupported: {
+      std::move(callback).Run(CreateWebNNGraphResult::kNotSupported,
+                              mojo::NullRemote());
+      return;
+    }
+    case webnn::mojom::blink::CreateContextResult::kOk: {
+      auto* execution_context = ExecutionContext::From(script_state);
+      webnn_context_.Bind(
+          std::move(pending_remote_context),
+          execution_context->GetTaskRunner(TaskType::kInternalDefault));
+
+      webnn_context_->CreateGraph(
+          WTF::BindOnce(std::move(callback), CreateWebNNGraphResult::kOk));
+      return;
+    }
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/ml_context.h b/third_party/blink/renderer/modules/ml/ml_context.h
index 0abbd39..fffc8b13 100644
--- a/third_party/blink/renderer/modules/ml/ml_context.h
+++ b/third_party/blink/renderer/modules/ml/ml_context.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ML_ML_CONTEXT_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_ML_ML_CONTEXT_H_
 
+#include "services/webnn/public/mojom/webnn_service.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_device_preference.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_model_format.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_power_preference.h"
@@ -14,6 +15,7 @@
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 
 namespace blink {
 
@@ -60,6 +62,15 @@
                    const MLNamedArrayBufferViews& outputs,
                    ExceptionState& exception_state);
 
+  enum CreateWebNNGraphResult { kOk, kUnknownError, kNotSupported };
+  // Return `kNotSupported` with `mojo::NullRemote` if the input configuration
+  // of creating `WebNNContext` is not supported.
+  using CreateWebNNGraphCallback = base::OnceCallback<void(
+      CreateWebNNGraphResult result,
+      mojo::PendingRemote<webnn::mojom::blink::WebNNGraph>)>;
+  void CreateWebNNGraph(ScriptState* script_state,
+                        CreateWebNNGraphCallback callback);
+
  private:
   V8MLDevicePreference device_preference_;
   V8MLPowerPreference power_preference_;
@@ -69,6 +80,18 @@
   Member<ML> ml_;
   // WebNN uses this MLModelLoader to build a computational graph.
   Member<MLModelLoader> ml_model_loader_;
+
+  // The callback of creating context called from WebNN server side.
+  void OnCreateWebNNContext(
+      ScriptState* script_state,
+      CreateWebNNGraphCallback callback,
+      webnn::mojom::blink::CreateContextResult result,
+      mojo::PendingRemote<webnn::mojom::blink::WebNNContext>
+          pending_remote_context);
+  // WebNN support multiple types of neural network inference hardware
+  // acceleration, the context of WebNN in server side is used to map different
+  // device and represent a state of graph execution processes.
+  HeapMojoRemote<webnn::mojom::blink::WebNNContext> webnn_context_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/webnn/OWNERS b/third_party/blink/renderer/modules/ml/webnn/OWNERS
new file mode 100644
index 0000000..608fe8f
--- /dev/null
+++ b/third_party/blink/renderer/modules/ml/webnn/OWNERS
@@ -0,0 +1,2 @@
+per-file ml_graph_mojo.*=ningxin.hu@intel.com
+per-file ml_graph_mojo.*=rafael.cintron@microsoft.com
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
index 4dff6c0..9850d46 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
@@ -34,6 +34,11 @@
 #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_cros.h"
 #endif
 
+#if !BUILDFLAG(IS_CHROMEOS)
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.h"
+#endif
+
 namespace blink {
 
 namespace {
@@ -1930,6 +1935,19 @@
   }
 #endif
 
+#if !BUILDFLAG(IS_CHROMEOS)
+  // The runtime enable feature is used to disable the cross process hardware
+  // acceleration by default.
+  if (base::FeatureList::IsEnabled(
+          blink::features::kEnableMachineLearningNeuralNetworkService)) {
+    // Reject unsupported error on unimplemented platform when getting
+    // `WebNNContext` mojo interface with BrowserInterfaceBroker's
+    // GetInterface() method before creating `WebNNGraph` message pipe.
+    MLGraphMojo::ValidateAndBuildAsync(ml_context_, named_outputs, resolver);
+    return promise;
+  }
+#endif
+
   resolver->Reject(MakeGarbageCollected<DOMException>(
       DOMExceptionCode::kNotSupportedError, "Not implemented"));
   return promise;
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.cc
new file mode 100644
index 0000000..04d3051
--- /dev/null
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.cc
@@ -0,0 +1,107 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.h"
+
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/modules/ml/ml.h"
+
+namespace blink {
+
+// static
+void MLGraphMojo::ValidateAndBuildAsync(MLContext* context,
+                                        const MLNamedOperands& named_outputs,
+                                        ScriptPromiseResolver* resolver) {
+  auto* graph =
+      MakeGarbageCollected<MLGraphMojo>(resolver->GetScriptState(), context);
+  graph->BuildAsync(named_outputs, resolver);
+}
+
+MLGraphMojo::MLGraphMojo(ScriptState* script_state, MLContext* context)
+    : MLGraph(context), remote_graph_(ExecutionContext::From(script_state)) {}
+
+MLGraphMojo::~MLGraphMojo() = default;
+
+void MLGraphMojo::Trace(Visitor* visitor) const {
+  visitor->Trace(remote_graph_);
+  MLGraph::Trace(visitor);
+}
+
+void MLGraphMojo::BuildAsyncImpl(const MLNamedOperands& outputs,
+                                 ScriptPromiseResolver* resolver) {
+  auto* named_outputs = MakeGarbageCollected<MLNamedOperands>(outputs);
+  // Create `WebNNGraph` message pipe with `WebNNContext` mojo interface.
+  auto* script_state = resolver->GetScriptState();
+  ml_context_->CreateWebNNGraph(
+      script_state,
+      WTF::BindOnce(&MLGraphMojo::OnCreateWebNNGraph, WrapPersistent(this),
+                    WrapPersistent(resolver), WrapPersistent(named_outputs)));
+}
+
+MLGraph* MLGraphMojo::BuildSyncImpl(const MLNamedOperands& named_outputs,
+                                    ExceptionState& exception_state) {
+  // TODO(crbug.com/1273291): Support sync build that is only exposed to
+  // dedicated worker.
+  NOTIMPLEMENTED();
+  exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
+                                    "Sync build not implemented.");
+  return nullptr;
+}
+
+void MLGraphMojo::ComputeAsyncImpl(const MLNamedArrayBufferViews& inputs,
+                                   const MLNamedArrayBufferViews& outputs,
+                                   ScriptPromiseResolver* resolver,
+                                   ExceptionState& exception_state) {
+  // TODO(crbug.com/1273291): Support async compute.
+  NOTIMPLEMENTED();
+  resolver->Reject(MakeGarbageCollected<DOMException>(
+      DOMExceptionCode::kNotSupportedError, "Async compute not implemented."));
+}
+
+void MLGraphMojo::ComputeSyncImpl(const MLNamedArrayBufferViews& inputs,
+                                  const MLNamedArrayBufferViews& outputs,
+                                  ExceptionState& exception_state) {
+  // TODO(crbug.com/1273291): Support sync compute that is only exposed to
+  // dedicated worker.
+  NOTIMPLEMENTED();
+  exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
+                                    "Sync compute not implemented");
+}
+
+void MLGraphMojo::OnCreateWebNNGraph(
+    ScriptPromiseResolver* resolver,
+    const MLNamedOperands* named_output,
+    MLContext::CreateWebNNGraphResult result,
+    mojo::PendingRemote<webnn::mojom::blink::WebNNGraph> pending_remote) {
+  switch (result) {
+    case MLContext::CreateWebNNGraphResult::kUnknownError: {
+      resolver->Reject(MakeGarbageCollected<DOMException>(
+          DOMExceptionCode::kUnknownError, "Internal error."));
+      return;
+    }
+    case MLContext::CreateWebNNGraphResult::kNotSupported: {
+      resolver->Reject(MakeGarbageCollected<DOMException>(
+          DOMExceptionCode::kNotSupportedError,
+          "Input configuration not supported."));
+      return;
+    }
+    case MLContext::CreateWebNNGraphResult::kOk: {
+      auto* script_state = resolver->GetScriptState();
+      auto* execution_context = ExecutionContext::From(script_state);
+      // Bind the end point of `WebNNGraph` mojo interface in the blink side.
+      remote_graph_.Bind(
+          std::move(pending_remote),
+          execution_context->GetTaskRunner(TaskType::kInternalDefault));
+
+      // TODO(crbug.com/1273291): Build the graph in the WebNN Service.
+      resolver->Resolve(this);
+      return;
+    }
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.h
new file mode 100644
index 0000000..548a70f
--- /dev/null
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.h
@@ -0,0 +1,71 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_MOJO_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_MOJO_H_
+
+#include "services/webnn/public/mojom/webnn_graph.mojom-blink.h"
+#include "services/webnn/public/mojom/webnn_service.mojom-blink.h"
+#include "third_party/blink/renderer/modules/ml/ml_context.h"
+#include "third_party/blink/renderer/modules/ml/webnn/ml_graph.h"
+#include "third_party/blink/renderer/modules/ml/webnn/ml_operand.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
+
+namespace blink {
+
+class ScriptPromiseResolver;
+
+// The `Mojo` in the class name means this graph is backed by a service running
+// outside of Blink.
+class MODULES_EXPORT MLGraphMojo final : public MLGraph {
+ public:
+  // Create and build an MLGraphMojo object. Resolve the promise with
+  // this concrete object if the graph builds successfully out of renderer
+  // process. Launch WebNN service and bind `WebNNContext` mojo interface
+  // to create `WebNNGraph` message pipe if needed.
+  static void ValidateAndBuildAsync(MLContext* context,
+                                    const MLNamedOperands& named_outputs,
+                                    ScriptPromiseResolver* resolver);
+
+  MLGraphMojo(ScriptState* script_state, MLContext* context);
+  ~MLGraphMojo() override;
+
+  void Trace(Visitor* visitor) const override;
+
+ private:
+  // Create `WebNNGraph` message pipe with `WebNNContext` mojo interface, then
+  // build the computational graph with the hardware accelerated OS machine
+  // learning API in the WebNN Service.
+  void BuildAsyncImpl(const MLNamedOperands& outputs,
+                      ScriptPromiseResolver* resolver) override;
+
+  MLGraph* BuildSyncImpl(const MLNamedOperands& named_outputs,
+                         ExceptionState& exception_state) override;
+
+  void ComputeAsyncImpl(const MLNamedArrayBufferViews& inputs,
+                        const MLNamedArrayBufferViews& outputs,
+                        ScriptPromiseResolver* resolver,
+                        ExceptionState& exception_state) override;
+
+  void ComputeSyncImpl(const MLNamedArrayBufferViews& inputs,
+                       const MLNamedArrayBufferViews& outputs,
+                       ExceptionState& exception_state) override;
+
+  // The callback of creating `WebNNGraph` mojo interface from WebNN Service.
+  // Return `CreatGraphResult::kNotSupported` with `mojo::NullRemote` on
+  // non-supported input configuration.
+  void OnCreateWebNNGraph(ScriptPromiseResolver* resolver,
+                          const MLNamedOperands* named_outputs,
+                          MLContext::CreateWebNNGraphResult result,
+                          mojo::PendingRemote<webnn::mojom::blink::WebNNGraph>);
+
+  // The `WebNNGraph` mojo interface is used to build and execute graph in the
+  // WebNN Service.
+  HeapMojoRemote<webnn::mojom::blink::WebNNGraph> remote_graph_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_MOJO_H_
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_mojo.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_mojo.cc
new file mode 100644
index 0000000..1f7e8a0
--- /dev/null
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_mojo.cc
@@ -0,0 +1,186 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_feature_list.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "services/webnn/public/mojom/webnn_graph.mojom-blink.h"
+#include "services/webnn/public/mojom/webnn_service.mojom-blink.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_dom_exception.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_context_options.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.h"
+#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.h"
+
+namespace blink {
+
+namespace blink_mojom = webnn::mojom::blink;
+
+class FakeWebNNGraph : public blink_mojom::WebNNGraph {
+ public:
+  FakeWebNNGraph() = default;
+  FakeWebNNGraph(const FakeWebNNGraph&) = delete;
+  FakeWebNNGraph(FakeWebNNGraph&&) = delete;
+  ~FakeWebNNGraph() override = default;
+
+ private:
+  // Override methods from webnn::mojom::WebNNGraph.
+  // TODO(crbug.com/1273291): Add build and compute methods.
+};
+
+class FakeWebNNContext : public blink_mojom::WebNNContext {
+ public:
+  FakeWebNNContext() = default;
+  FakeWebNNContext(const FakeWebNNContext&) = delete;
+  FakeWebNNContext(FakeWebNNContext&&) = delete;
+  ~FakeWebNNContext() override = default;
+
+ private:
+  // Override methods from webnn::mojom::WebNNContext.
+  void CreateGraph(CreateGraphCallback callback) override {
+    mojo::PendingRemote<blink_mojom::WebNNGraph> blink_remote;
+    // The receiver bind to FakeWebNNGraph.
+    mojo::MakeSelfOwnedReceiver<blink_mojom::WebNNGraph>(
+        std::make_unique<FakeWebNNGraph>(),
+        blink_remote.InitWithNewPipeAndPassReceiver());
+
+    std::move(callback).Run(std::move(blink_remote));
+  }
+};
+
+class FakeWebNNContextProvider : public blink_mojom::WebNNContextProvider {
+ public:
+  FakeWebNNContextProvider() : receiver_(this) {}
+  FakeWebNNContextProvider(const FakeWebNNContextProvider&) = delete;
+  FakeWebNNContextProvider(FakeWebNNContextProvider&&) = delete;
+  ~FakeWebNNContextProvider() override = default;
+
+  void BindRequest(mojo::ScopedMessagePipeHandle handle) {
+    DCHECK(!receiver_.is_bound());
+    receiver_.Bind(mojo::PendingReceiver<blink_mojom::WebNNContextProvider>(
+        std::move(handle)));
+    receiver_.set_disconnect_handler(WTF::BindOnce(
+        &FakeWebNNContextProvider::OnConnectionError, WTF::Unretained(this)));
+  }
+
+  bool IsBound() const { return receiver_.is_bound(); }
+
+  void OnConnectionError() { receiver_.reset(); }
+
+ private:
+  // Override methods from webnn::mojom::WebNNContextProvider.
+  void CreateWebNNContext(blink_mojom::CreateContextOptionsPtr options,
+                          CreateWebNNContextCallback callback) override {
+    mojo::PendingRemote<blink_mojom::WebNNContext> blink_remote;
+    // The receiver bind to FakeWebNNContext.
+    mojo::MakeSelfOwnedReceiver<blink_mojom::WebNNContext>(
+        std::make_unique<FakeWebNNContext>(),
+        blink_remote.InitWithNewPipeAndPassReceiver());
+
+    std::move(callback).Run(blink_mojom::CreateContextResult::kOk,
+                            std::move(blink_remote));
+  }
+
+  mojo::Receiver<blink_mojom::WebNNContextProvider> receiver_;
+};
+
+class ScopedWebNNServiceBinder {
+ public:
+  explicit ScopedWebNNServiceBinder(V8TestingScope& scope)
+      : fake_webnn_context_provider_(
+            std::make_unique<FakeWebNNContextProvider>()),
+        interface_broker_(
+            scope.GetExecutionContext()->GetBrowserInterfaceBroker()) {
+    interface_broker_.SetBinderForTesting(
+        blink_mojom::WebNNContextProvider::Name_,
+        WTF::BindRepeating(
+            &FakeWebNNContextProvider::BindRequest,
+            WTF::Unretained(fake_webnn_context_provider_.get())));
+  }
+
+  ~ScopedWebNNServiceBinder() {
+    interface_broker_.SetBinderForTesting(
+        blink_mojom::WebNNContextProvider::Name_, base::NullCallback());
+  }
+
+  bool IsWebNNContextBound() const {
+    return fake_webnn_context_provider_->IsBound();
+  }
+
+ private:
+  std::unique_ptr<FakeWebNNContextProvider> fake_webnn_context_provider_;
+  const BrowserInterfaceBrokerProxy& interface_broker_;
+};
+
+class MLGraphTestMojo : public testing::Test {};
+
+MLGraphMojo* ToMLGraphMojo(V8TestingScope* scope, ScriptValue value) {
+  return NativeValueTraits<MLGraphMojo>::NativeValue(
+      scope->GetIsolate(), value.V8Value(), scope->GetExceptionState());
+}
+
+// Build a simple MLGraph asynchronously with only one relu operator.
+ScriptPromise BuildSimpleGraph(V8TestingScope& scope,
+                               MLContextOptions* context_options) {
+  auto* builder =
+      CreateMLGraphBuilder(scope.GetExecutionContext(), context_options);
+  auto* input =
+      BuildInput(builder, "input", {3, 4, 5}, V8MLOperandType::Enum::kFloat32,
+                 scope.GetExceptionState());
+  auto* output = builder->relu(input, scope.GetExceptionState());
+  EXPECT_NE(output, nullptr);
+  return builder->build(scope.GetScriptState(), {{"output", output}},
+                        scope.GetExceptionState());
+}
+
+TEST_F(MLGraphTestMojo, CreateWebNNGraphTest) {
+  V8TestingScope scope;
+  // Bind fake WebNN Context in the service for testing.
+  ScopedWebNNServiceBinder scoped_setup_binder(scope);
+
+  auto* script_state = scope.GetScriptState();
+  auto* options = MLContextOptions::Create();
+  // Create WebNN Context with GPU device preference.
+  options->setDevicePreference(V8MLDevicePreference::Enum::kGpu);
+
+  {
+    // Test disabling WebNN Service by default. The promise should be rejected
+    // since the WebNN Service is disabled.
+    ScriptPromiseTester tester(script_state, BuildSimpleGraph(scope, options));
+    tester.WaitUntilSettled();
+    EXPECT_TRUE(tester.IsRejected());
+    auto* exception = V8DOMException::ToImplWithTypeCheck(
+        scope.GetIsolate(), tester.Value().V8Value());
+    EXPECT_NE(exception, nullptr);
+    EXPECT_EQ(exception->name(), "NotSupportedError");
+    EXPECT_EQ(exception->message(), "Not implemented");
+    EXPECT_FALSE(scoped_setup_binder.IsWebNNContextBound());
+  }
+
+  {
+    // Test enabling WebNN Service in feature list. The promise should be
+    // resoveld with an MLGraphMojo object.
+    base::test::ScopedFeatureList scoped_feature_list;
+    scoped_feature_list.InitAndEnableFeature(
+        blink::features::kEnableMachineLearningNeuralNetworkService);
+
+    ScriptPromiseTester tester(script_state, BuildSimpleGraph(scope, options));
+    tester.WaitUntilSettled();
+    EXPECT_TRUE(tester.IsFulfilled());
+    auto* mojo_graph = ToMLGraphMojo(&scope, tester.Value());
+    EXPECT_NE(mojo_graph, nullptr);
+    EXPECT_TRUE(scoped_setup_binder.IsWebNNContextBound());
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/wtf/hash_map_test.cc b/third_party/blink/renderer/platform/wtf/hash_map_test.cc
index ee8c678..dc30b4dd4 100644
--- a/third_party/blink/renderer/platform/wtf/hash_map_test.cc
+++ b/third_party/blink/renderer/platform/wtf/hash_map_test.cc
@@ -155,27 +155,27 @@
 TEST(HashMapTest, RefPtrAsKey) {
   bool is_deleted = false;
   DummyRefCounted::ref_invokes_count_ = 0;
-  scoped_refptr<DummyRefCounted> ptr =
+  scoped_refptr<DummyRefCounted> object =
       base::AdoptRef(new DummyRefCounted(is_deleted));
   EXPECT_EQ(0, DummyRefCounted::ref_invokes_count_);
   HashMap<scoped_refptr<DummyRefCounted>, int> map;
-  map.insert(ptr, 1);
+  map.insert(object, 1);
   // Referenced only once (to store a copy in the container).
   EXPECT_EQ(1, DummyRefCounted::ref_invokes_count_);
-  EXPECT_EQ(1, map.at(ptr));
+  EXPECT_EQ(1, map.at(object));
 
-  DummyRefCounted* raw_ptr = ptr.get();
+  DummyRefCounted* ptr = object.get();
 
-  EXPECT_TRUE(map.Contains(raw_ptr));
-  EXPECT_NE(map.end(), map.find(raw_ptr));
   EXPECT_TRUE(map.Contains(ptr));
   EXPECT_NE(map.end(), map.find(ptr));
+  EXPECT_TRUE(map.Contains(object));
+  EXPECT_NE(map.end(), map.find(object));
   EXPECT_EQ(1, DummyRefCounted::ref_invokes_count_);
 
-  ptr = nullptr;
+  object = nullptr;
   EXPECT_FALSE(is_deleted);
 
-  map.erase(raw_ptr);
+  map.erase(ptr);
   EXPECT_EQ(1, DummyRefCounted::ref_invokes_count_);
   EXPECT_TRUE(is_deleted);
   EXPECT_TRUE(map.empty());
@@ -188,16 +188,16 @@
   typedef HashMap<int, scoped_refptr<DummyRefCounted>> Map;
   Map map;
 
-  scoped_refptr<DummyRefCounted> ptr =
+  scoped_refptr<DummyRefCounted> object =
       base::AdoptRef(new DummyRefCounted(is_deleted));
   EXPECT_EQ(0, DummyRefCounted::ref_invokes_count_);
 
-  map.insert(1, ptr);
+  map.insert(1, object);
   // Referenced only once (to store a copy in the container).
   EXPECT_EQ(1, DummyRefCounted::ref_invokes_count_);
-  EXPECT_EQ(ptr, map.at(1));
+  EXPECT_EQ(object, map.at(1));
 
-  ptr = nullptr;
+  object = nullptr;
   EXPECT_FALSE(is_deleted);
 
   map.erase(1);
diff --git a/third_party/blink/renderer/platform/wtf/hash_set_test.cc b/third_party/blink/renderer/platform/wtf/hash_set_test.cc
index 1c8f7d7..f06c04f 100644
--- a/third_party/blink/renderer/platform/wtf/hash_set_test.cc
+++ b/third_party/blink/renderer/platform/wtf/hash_set_test.cc
@@ -230,25 +230,25 @@
   bool is_deleted = false;
   DummyRefCounted::ref_invokes_count_ = 0;
 
-  scoped_refptr<DummyRefCounted> ptr =
+  scoped_refptr<DummyRefCounted> object =
       base::AdoptRef(new DummyRefCounted(is_deleted));
   EXPECT_EQ(0, DummyRefCounted::ref_invokes_count_);
   HashSet<scoped_refptr<DummyRefCounted>> set;
-  set.insert(ptr);
+  set.insert(object);
   // Referenced only once (to store a copy in the container).
   EXPECT_EQ(1, DummyRefCounted::ref_invokes_count_);
 
-  DummyRefCounted* raw_ptr = ptr.get();
+  DummyRefCounted* ptr = object.get();
 
-  EXPECT_TRUE(set.Contains(raw_ptr));
-  EXPECT_NE(set.end(), set.find(raw_ptr));
   EXPECT_TRUE(set.Contains(ptr));
   EXPECT_NE(set.end(), set.find(ptr));
+  EXPECT_TRUE(set.Contains(object));
+  EXPECT_NE(set.end(), set.find(object));
 
-  ptr = nullptr;
+  object = nullptr;
   EXPECT_FALSE(is_deleted);
 
-  set.erase(raw_ptr);
+  set.erase(ptr);
   EXPECT_TRUE(is_deleted);
   EXPECT_TRUE(set.empty());
   EXPECT_EQ(1, DummyRefCounted::ref_invokes_count_);
diff --git a/third_party/blink/renderer/platform/wtf/linked_hash_set_test.cc b/third_party/blink/renderer/platform/wtf/linked_hash_set_test.cc
index c656d10..e824b000 100644
--- a/third_party/blink/renderer/platform/wtf/linked_hash_set_test.cc
+++ b/third_party/blink/renderer/platform/wtf/linked_hash_set_test.cc
@@ -730,28 +730,28 @@
     expected = 2;
   bool is_deleted = false;
   DummyRefCounted::ref_invokes_count_ = 0;
-  scoped_refptr<DummyRefCounted> ptr =
+  scoped_refptr<DummyRefCounted> object =
       base::AdoptRef(new DummyRefCounted(is_deleted));
   EXPECT_EQ(0, DummyRefCounted::ref_invokes_count_);
 
   Set set;
-  set.insert(ptr);
+  set.insert(object);
   // Referenced only once (to store a copy in the container).
   EXPECT_EQ(expected, DummyRefCounted::ref_invokes_count_);
-  EXPECT_EQ(ptr, set.front());
+  EXPECT_EQ(object, set.front());
   EXPECT_EQ(expected, DummyRefCounted::ref_invokes_count_);
 
-  DummyRefCounted* raw_ptr = ptr.get();
+  DummyRefCounted* ptr = object.get();
 
+  EXPECT_TRUE(set.Contains(object));
   EXPECT_TRUE(set.Contains(ptr));
-  EXPECT_TRUE(set.Contains(raw_ptr));
   EXPECT_EQ(expected, DummyRefCounted::ref_invokes_count_);
 
-  ptr = nullptr;
+  object = nullptr;
   EXPECT_FALSE(is_deleted);
   EXPECT_EQ(expected, DummyRefCounted::ref_invokes_count_);
 
-  set.erase(raw_ptr);
+  set.erase(ptr);
   EXPECT_TRUE(is_deleted);
 
   EXPECT_EQ(expected, DummyRefCounted::ref_invokes_count_);
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index f0432e3..3abdf60 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2948,6 +2948,7 @@
 crbug.com/626703 external/wpt/css/css-multicol/file-control-crash.html [ Crash ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Win11 ] virtual/attribution-reporting-debug-mode/wpt_internal/attribution-reporting/source-registration.sub.https.html?method=a&eligible [ Skip Timeout ]
 crbug.com/626703 [ Linux ] virtual/attribution-reporting-debug-mode/wpt_internal/attribution-reporting/source-registration.sub.https.html?method=a&eligible [ Skip Timeout ]
 crbug.com/626703 [ Mac13 ] virtual/attribution-reporting-debug-mode/wpt_internal/attribution-reporting/source-registration.sub.https.html?method=a&eligible [ Skip Timeout ]
 crbug.com/626703 [ Mac12 ] virtual/attribution-reporting-debug-mode/wpt_internal/attribution-reporting/source-registration.sub.https.html?method=a&eligible [ Skip Timeout ]
@@ -4230,7 +4231,8 @@
 # Sheriff 2019-04-17
 crbug.com/953591 [ Win ] fast/forms/datalist/input-appearance-range-with-transform.html [ Failure Pass ]
 crbug.com/953591 [ Win ] transforms/matrix-02.html [ Failure Pass ]
-crbug.com/938884 http/tests/devtools/elements/styles-3/styles-add-blank-property.js [ Pass Timeout ]
+# The following test also increased in flakiness due to icon rework: crbug.com/1427397 (but was flaky before)
+crbug.com/938884 http/tests/devtools/elements/styles-3/styles-add-blank-property.js [ Failure Pass Timeout ]
 
 # Sheriff 2019-04-30
 crbug.com/948785 fast/events/pointerevents/pointer-event-consumed-touchstart-in-slop-region.html [ Crash Failure Pass Timeout ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 900fb2e..b5ae7c9 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -145245,7 +145245,7 @@
         ]
        ],
        "clip-path-animation-filter.html": [
-        "cbfa8baaa769a25ca57aaa5d6f271b26810a8bf6",
+        "0ba7a0021da4e41a72ffad26f32028231edb6bfd",
         [
          null,
          [
@@ -145265,7 +145265,7 @@
              ],
              [
               0,
-              150
+              151
              ]
             ]
            ]
@@ -269813,11 +269813,11 @@
   "support": {
    ".cache": {
     "gitignore2.json": [
-     "2974606dfd61fd50081a3ff3cb92b88ad669f833",
+     "d61b28b5f9bc94eac1ecbb1d0ce8aa1659e69b29",
      []
     ],
     "mtime.json": [
-     "475b2dbc5076b7483788c571a2cdca6f6950791b",
+     "90847976db7fb31236cc41ee0f25a2ae554b25b8",
      []
     ]
    },
@@ -272348,7 +272348,7 @@
       []
      ],
      "bluetooth-test.js": [
-      "7ad1b937e1f5d1ca4a1e20da410e969ba229227e",
+      "7852aadf466cbb2617c3be049c4aa05b5edee0b6",
       []
      ],
      "health-thermometer-iframe.html": [
@@ -326806,6 +326806,10 @@
        "b8989649989330670d42de6c6dde8435a7c8b401",
        []
       ],
+      "kind-of-widget-fallback-input-submit-background-attachment-001.html.ini": [
+       "b75ba16b84918eeb9fa1a217e00685cde61067c7",
+       []
+      ],
       "kind-of-widget-fallback-input-submit-background-clip-001.html.ini": [
        "6583c45e05f102d5160f222fe5be6681d93d24da",
        []
@@ -328857,34 +328861,22 @@
       "888a51ea9b6ac04fb065ee5d84a18be8fe765aca",
       []
      ],
-     "exp-log-compute-expected.txt": [
-      "497cf5feea9aacf6a927be6fffd90cc3dd6da6d6",
-      []
-     ],
      "exp-log-compute.html.ini": [
       "beb0f9fc620395b26bdb0037cd14bdbb92ae1e61",
       []
      ],
      "exp-log-serialize-expected.txt": [
-      "4538042081cdc199458994b3e4d607970d94f58d",
+      "16ba188a215de786891552c8b1d71e06d2c163ac",
       []
      ],
      "exp-log-serialize.html.ini": [
       "65ba5095e1044754fecdf183e092af312a5099a6",
       []
      ],
-     "hypot-pow-sqrt-computed-expected.txt": [
-      "857ea19154ea8b234bcdebd48e0c217dc82d2ca9",
-      []
-     ],
      "hypot-pow-sqrt-computed.html.ini": [
       "9cb3accfcafc694746d14bfb167fbb90d1208ae8",
       []
      ],
-     "hypot-pow-sqrt-serialize-expected.txt": [
-      "4635a58db07db3f78590e9efef56dddf4ae42f84",
-      []
-     ],
      "hypot-pow-sqrt-serialize.html.ini": [
       "e2800ba79860b2382bd67ece12e89331ee2ed9ca",
       []
@@ -350977,11 +350969,11 @@
          []
         ],
         "canvas-display-p3-drawImage.https-expected.txt": [
-         "e2acfde8b8ac221e632efdb975bf5a14c7690e6a",
+         "7adc6fa541849f3a31f644ef6b44f10f318eb6ac",
          []
         ],
         "canvas-display-p3-drawImage.https.html.ini": [
-         "b6b1b9cf74d26875784ec0cbf6105897a37909d1",
+         "9c80c1ec5157e9934b3c90383f13ce3c4faade78",
          []
         ],
         "canvas-display-p3-pattern-image-expected.txt": [
@@ -351499,25 +351491,9 @@
        ]
       },
       "wide-gamut-canvas": {
-       "2d.color.space.p3.fillText-expected.txt": [
-        "9a33e9d34e03b9fde2946b65b1a656ade8b6598f",
-        []
-       ],
-       "2d.color.space.p3.fillText.html.ini": [
-        "5e3b6d27a6bef18ce6af80c2230d4fcadb67bbd4",
-        []
-       ],
        "2d.color.space.p3.fillText.shadow.html.ini": [
         "cb2b23ea57f6ab2b64c6c7b1793bd0eba07343d1",
         []
-       ],
-       "2d.color.space.p3.strokeText-expected.txt": [
-        "c182877a0daeea593d36ea4241011a86b57c2f7a",
-        []
-       ],
-       "2d.color.space.p3.strokeText.html.ini": [
-        "7ad37889efc150ff6a22096070777f979f434d7e",
-        []
        ]
       }
      },
@@ -369244,7 +369220,7 @@
     ]
    },
    "lint.ignore": [
-    "ebc25c5e623180c02674c1eafef98c9a6c880aca",
+    "762fbb149d2acbb34023bce5df2ffcf97978a182",
     []
    ],
    "loading": {
@@ -391121,7 +391097,7 @@
        []
       ],
       "prelu.json": [
-       "e1bf67826195d27c62115d0806493fe5db97c04b",
+       "e45e12cd4b6c9f6db1eeb2243396edea641813f6",
        []
       ],
       "reduce_max.json": [
@@ -414649,7 +414625,7 @@
        ]
       ],
       "characteristic-is-removed.https.window.js": [
-       "4af3d01e316909d9f71f1eac02c8ec427d7f2503",
+       "17f3ade7073d48bc43e3ccc3ae5bec0a58f17e48",
        [
         "bluetooth/characteristic/readValue/characteristic-is-removed.https.window.html",
         {
@@ -550141,6 +550117,13 @@
         }
        ]
       ],
+      "popover-move-documents.html": [
+       "2ead18a2b73956e8821cd61490c4f25861e33ed8",
+       [
+        null,
+        {}
+       ]
+      ],
       "popover-not-keyboard-focusable.html": [
        "5246073c960180fb92d411fe45f7e60d7c11babc",
        [
@@ -602106,7 +602089,7 @@
      ]
     ],
     "offsetTop-offsetLeft-across-shadow-boundaries.html": [
-     "e5494452121de53ca17cde77af8bb1980c02a74b",
+     "50a85afcbc1cbbfce6c06d0180afe7cd87255e54",
      [
       null,
       {}
@@ -632284,7 +632267,7 @@
      ]
     ],
     "concat.https.any.js": [
-     "07a1289cef0add6581aaeb859881aadf68c81261",
+     "b91e99e289e8ec3dbb7ef37ef189f54316b351c2",
      [
       "webnn/concat.https.any.html",
       {
@@ -633108,7 +633091,7 @@
      ]
     ],
     "reshape.https.any.js": [
-     "9fa3262fe5240c549cf12e6cc39fad56e8bd7d88",
+     "a7126e63a1028c49036addb2c6e0449256cf2903",
      [
       "webnn/reshape.https.any.html",
       {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-background-attachment-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-background-attachment-001.html.ini
new file mode 100644
index 0000000..b75ba16
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-background-attachment-001.html.ini
@@ -0,0 +1,3 @@
+[kind-of-widget-fallback-input-submit-background-attachment-001.html]
+  expected:
+    if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/webnn/concat.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/concat.https.any.js
index 07a1289..b91e99e 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/concat.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/concat.https.any.js
@@ -8,7 +8,7 @@
 // https://webmachinelearning.github.io/webnn/#api-mlgraphbuilder-concat
 
 const buildConcat = (operationName, builder, resources) => {
-  // MLOperand concat(sequence<MLOperand> inputs, long axis);
+  // MLOperand concat(sequence<MLOperand> inputs, unsigned long axis);
   const namedOutputOperand = {};
   const inputOperands = [];
   for (let input of resources.inputs) {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/reshape.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/reshape.https.any.js
index 9fa3262..a7126e6 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/reshape.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/reshape.https.any.js
@@ -8,7 +8,7 @@
 // https://webmachinelearning.github.io/webnn/#api-mlgraphbuilder-reshape
 
 const buildReshape = (operationName, builder, resources) => {
-  // MLOperand reshape(MLOperand input, sequence<long> newShape);
+  // MLOperand reshape(MLOperand input, sequence<unsigned long?> newShape);
   const namedOutputOperand = {};
   const inputOperand = createSingleInputOperand(builder, resources);
   // invoke builder.reshape()
diff --git a/third_party/blink/web_tests/external/wpt/webnn/resources/test_data/prelu.json b/third_party/blink/web_tests/external/wpt/webnn/resources/test_data/prelu.json
index e1bf6782..e45e12cd 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/resources/test_data/prelu.json
+++ b/third_party/blink/web_tests/external/wpt/webnn/resources/test_data/prelu.json
@@ -61,7 +61,8 @@
             -1.7995220850663962,
             9.29585020267449
           ],
-          "type": "float32"
+          "type": "float32",
+          "constant": true
         }
       },
       "expected": {
@@ -157,7 +158,8 @@
             -1.7995220850663962,
             9.29585020267449
           ],
-          "type": "float32"
+          "type": "float32",
+          "constant": true
         }
       },
       "expected": {
@@ -253,7 +255,8 @@
             -1.7995220850663962,
             9.29585020267449
           ],
-          "type": "float32"
+          "type": "float32",
+          "constant": true
         }
       },
       "expected": {
@@ -349,7 +352,8 @@
             -1.7995220850663962,
             9.29585020267449
           ],
-          "type": "float32"
+          "type": "float32",
+          "constant": true
         }
       },
       "expected": {
@@ -445,7 +449,8 @@
             -1.7995220850663962,
             9.29585020267449
           ],
-          "type": "float32"
+          "type": "float32",
+          "constant": true
         }
       },
       "expected": {
@@ -520,7 +525,8 @@
             0.48077445494619653,
             -7.091750168010829
           ],
-          "type": "float32"
+          "type": "float32",
+          "constant": true
         }
       },
       "expected": {
@@ -593,7 +599,8 @@
           "data": [
             5.0114545056636395
           ],
-          "type": "float32"
+          "type": "float32",
+          "constant": true
         }
       },
       "expected": {
@@ -671,7 +678,8 @@
             -4.424202960837338,
             -6.654683521499036
           ],
-          "type": "float32"
+          "type": "float32",
+          "constant": true
         }
       },
       "expected": {
@@ -746,7 +754,8 @@
             0.48077445494619653,
             -7.091750168010829
           ],
-          "type": "float32"
+          "type": "float32",
+          "constant": true
         }
       },
       "expected": {
@@ -819,7 +828,8 @@
           "data": [
             5.0114545056636395
           ],
-          "type": "float32"
+          "type": "float32",
+          "constant": true
         }
       },
       "expected": {
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/multiple-redirects-extrainfo-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/network/multiple-redirects-extrainfo-expected.txt
index 60c96dda7..f5400434 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/network/multiple-redirects-extrainfo-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/multiple-redirects-extrainfo-expected.txt
@@ -7,6 +7,7 @@
   redirectHasExtraInfo: true
 responseReceiveds: 1
   url: http://127.0.0.1:8000/inspector-protocol/resources/final.html
+  hasExtraInfo: true
 requestWillBeSentExtraInfos: 2
   has headers: true
   has headers: true
@@ -21,11 +22,10 @@
   redirectHasExtraInfo: true
 responseReceiveds: 1
   url: http://127.0.0.1:8000/inspector-protocol/resources/final.html
-requestWillBeSentExtraInfos: 2
+  hasExtraInfo: false
+requestWillBeSentExtraInfos: 1
   has headers: true
-  has headers: false
-responseReceivedExtraInfos: 2
-  has headers: true
+responseReceivedExtraInfos: 1
   has headers: true
 
 
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/multiple-redirects-extrainfo.js b/third_party/blink/web_tests/http/tests/inspector-protocol/network/multiple-redirects-extrainfo.js
index 73e8485..362f0596 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/network/multiple-redirects-extrainfo.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/multiple-redirects-extrainfo.js
@@ -39,7 +39,7 @@
     dp.Network.onResponseReceivedExtraInfo(event => {
       pushEvent('responseReceivedExtraInfo', event);
       extraInfoCount++;
-      if (extraInfoCount === 4)
+      if (extraInfoCount === 3)
         resolve();
     });
   });
@@ -83,6 +83,7 @@
       for (let i = 0; i < responseReceiveds.length; i++) {
         const responseReceived = responseReceiveds[i];
         testRunner.log(`  url: ${responseReceived.params.response.url}`);
+        testRunner.log(`  hasExtraInfo: ${responseReceived.params.hasExtraInfo}`);
       }
     } else {
       testRunner.log(`responseReceiveds: none`);
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/redirect-cached-navigation-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/network/redirect-cached-navigation-expected.txt
new file mode 100644
index 0000000..ab054ecd
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/redirect-cached-navigation-expected.txt
@@ -0,0 +1,32 @@
+Verifies that redirects to a cached URL do not produce extra info events
+
+Fresh redirect:
+request:
+  url: http://127.0.0.1:8000/inspector-protocol/network/resources/redirect-cached.php
+  !!redirectResponse: false
+  redirectHasExtraInfo: false
+request:
+  url: http://127.0.0.1:8000/inspector-protocol/network/resources/redirect-cached-target.php
+  !!redirectResponse: true
+  redirectHasExtraInfo: true
+response:
+  fromDiskCache: false
+  hasExtraInfo: true
+  requestExtraInfoCount: 2
+  responseExtraInfoCount: 2
+
+Redirect to a cached resource:
+request:
+  url: http://127.0.0.1:8000/inspector-protocol/network/resources/redirect-cached.php
+  !!redirectResponse: false
+  redirectHasExtraInfo: false
+request:
+  url: http://127.0.0.1:8000/inspector-protocol/network/resources/redirect-cached-target.php
+  !!redirectResponse: true
+  redirectHasExtraInfo: true
+response:
+  fromDiskCache: true
+  hasExtraInfo: false
+  requestExtraInfoCount: 1
+  responseExtraInfoCount: 1
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/redirect-cached-navigation.js b/third_party/blink/web_tests/http/tests/inspector-protocol/network/redirect-cached-navigation.js
new file mode 100644
index 0000000..6e99e95b
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/redirect-cached-navigation.js
@@ -0,0 +1,40 @@
+(async function(testRunner) {
+  const {dp} = await testRunner.startBlank(
+    `Verifies that redirects to a cached URL do not produce extra info events\n`);
+
+  function printRequest(request) {
+    testRunner.log(`request:`);
+    testRunner.log(`  url: ${request.params.request.url}`);
+    testRunner.log(`  !!redirectResponse: ${!!request.params.redirectResponse}`);
+    testRunner.log(`  redirectHasExtraInfo: ${request.params.redirectHasExtraInfo}`);
+  }
+  function printResponse(response) {
+    testRunner.log(`response:`);
+    testRunner.log(`  fromDiskCache: ${response.params.response.fromDiskCache}`);
+    testRunner.log(`  hasExtraInfo: ${response.params.hasExtraInfo}`);
+  }
+
+  dp.Network.onRequestWillBeSent(printRequest);
+  dp.Network.onResponseReceived(printResponse);
+
+  let requestExtraInfoCount = 0;
+  let responseExtraInfoCount = 0;
+  dp.Network.onRequestWillBeSentExtraInfo(() => requestExtraInfoCount++);
+  dp.Network.onResponseReceivedExtraInfo(() => responseExtraInfoCount++);
+
+  dp.Network.enable();
+  dp.Page.enable();
+  testRunner.log('Fresh redirect:');
+  dp.Page.navigate({url: testRunner.url('resources/redirect-cached.php')});
+  await dp.Network.onceLoadingFinished();
+  testRunner.log('  requestExtraInfoCount: ' + requestExtraInfoCount);
+  testRunner.log('  responseExtraInfoCount: ' + responseExtraInfoCount);
+  responseExtraInfoCount = requestExtraInfoCount = 0;
+
+  testRunner.log('\nRedirect to a cached resource:');
+  dp.Page.navigate({url: testRunner.url('resources/redirect-cached.php')});
+  await dp.Network.onceLoadingFinished();
+  testRunner.log('  requestExtraInfoCount: ' + requestExtraInfoCount);
+  testRunner.log('  responseExtraInfoCount: ' + responseExtraInfoCount);
+  testRunner.completeTest();
+});
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/resources/redirect-cached-target.php b/third_party/blink/web_tests/http/tests/inspector-protocol/network/resources/redirect-cached-target.php
new file mode 100644
index 0000000..5fb21a1
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/resources/redirect-cached-target.php
@@ -0,0 +1,9 @@
+<?php
+    header("Cache-control: max-age=360000");
+    header("Content-Type: text/html; charset=UTF-8");
+?>
+<html>
+<body>
+Today's lucky number: <?php echo(rand()) ?>
+</body>
+</body>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/resources/redirect-cached.php b/third_party/blink/web_tests/http/tests/inspector-protocol/network/resources/redirect-cached.php
new file mode 100644
index 0000000..d869ef2
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/resources/redirect-cached.php
@@ -0,0 +1,5 @@
+<?php
+header('HTTP/1.1 307 Temporary Redirect');
+header('Pragma: no-cache');
+header('Location: redirect-cached-target.php');
+?>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/preload/rule-set-updated-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/preload/rule-set-updated-expected.txt
index e4067ad..cc337be 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/preload/rule-set-updated-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/preload/rule-set-updated-expected.txt
@@ -2,83 +2,53 @@
 Running test: testEnabled
 Tests that Preload.ruleSetUpdated and Preload.ruleSetDeleted are dispatched.
 {
-    method : Preload.ruleSetUpdated
-    params : {
-        ruleSet : {
-            id : <string>
-            loaderId : <string>
-            sourceText : {
-                prefetch : [
-                    [0] : {
-                        source : list
-                        urls : [
-                            [0] : /subresource.js
-                        ]
-                    }
+    id : <string>
+    loaderId : <string>
+    sourceText : {
+        prefetch : [
+            [0] : {
+                source : list
+                urls : [
+                    [0] : /subresource.js
                 ]
             }
-        }
+        ]
     }
-    sessionId : <string>
 }
 {
-    method : Preload.ruleSetUpdated
-    params : {
-        ruleSet : {
-            id : <string>
-            loaderId : <string>
-            sourceText : {
-                prerender : [
-                    [0] : {
-                        source : list
-                        urls : [
-                            [0] : /page.html
-                        ]
-                    }
+    id : <string>
+    loaderId : <string>
+    sourceText : {
+        prerender : [
+            [0] : {
+                source : list
+                urls : [
+                    [0] : /page.html
                 ]
             }
-        }
+        ]
     }
-    sessionId : <string>
 }
 {
-    method : Preload.ruleSetUpdated
-    params : {
-        ruleSet : {
-            errorMessage : Line: 4, column: 7, Syntax error.
-            errorType : SourceIsNotJsonObject
-            id : <string>
-            loaderId : <string>
-            sourceText : {"prefetch":[
-        }
-    }
-    sessionId : <string>
+    errorMessage : Line: 4, column: 7, Syntax error.
+    errorType : SourceIsNotJsonObject
+    id : <string>
+    loaderId : <string>
+    sourceText : {"prefetch":[
 }
 {
-    method : Preload.ruleSetUpdated
-    params : {
-        ruleSet : {
-            errorMessage : Parsed JSON must be an object.
-            errorType : SourceIsNotJsonObject
-            id : <string>
-            loaderId : <string>
-            sourceText : "invalid"
-        }
-    }
-    sessionId : <string>
+    errorMessage : Parsed JSON must be an object.
+    errorType : SourceIsNotJsonObject
+    id : <string>
+    loaderId : <string>
+    sourceText : "invalid"
 }
 {
-    method : Preload.ruleSetUpdated
-    params : {
-        ruleSet : {
-            errorMessage : A rule set for a key must be an array: path = ["prerender"]
-            errorType : InvalidRulesSkipped
-            id : <string>
-            loaderId : <string>
-            sourceText : {"prefetch":[{"source":"list","urls":["/subresource.js"]}],"prerender":"invalid"}
-        }
-    }
-    sessionId : <string>
+    errorMessage : A rule set for a key must be an array: path = ["prerender"]
+    errorType : InvalidRulesSkipped
+    id : <string>
+    loaderId : <string>
+    sourceText : {"prefetch":[{"source":"list","urls":["/subresource.js"]}],"prerender":"invalid"}
 }
 {
     method : Preload.ruleSetRemoved
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/preload/rule-set-updated.js b/third_party/blink/web_tests/http/tests/inspector-protocol/preload/rule-set-updated.js
index 3095d55..6ba3b5a4 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/preload/rule-set-updated.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/preload/rule-set-updated.js
@@ -53,24 +53,18 @@
 
     await dp.Preload.enable();
 
-    await new Promise(resolve => {
-      let count = 5;
-      dp.Preload.onRuleSetUpdated(ruleSet => {
-        // Format sourceText.
-        ruleSet.params.ruleSet.sourceText =
-            ruleSet.params.ruleSet.errorType === undefined ?
-            JSON.parse(ruleSet.params.ruleSet.sourceText) :
-            // Prevent failures due to non visible differences coming from LF.
-            ruleSet.params.ruleSet.sourceText.replaceAll(/[\n ]+/g, '');
-        testRunner.log(ruleSet);
+    void page.loadHTML(html);
 
-        --count;
-        if (count === 0) {
-          resolve();
-        }
-      });
-      void page.loadHTML(html);
-    });
+    for (let count = 0; count < 5; ++count) {
+      const {ruleSet} = (await dp.Preload.onceRuleSetUpdated()).params;
+
+      // Format sourceText.
+      ruleSet.sourceText = ruleSet.errorType === undefined ?
+          JSON.parse(ruleSet.sourceText) :
+          // Prevent failures due to non visible differences coming from LF.
+          ruleSet.sourceText.replaceAll(/[\n ]+/g, '');
+      testRunner.log(ruleSet);
+    }
 
     session.evaluate('document.getElementById("prefetch").remove();');
     testRunner.log(await dp.Preload.onceRuleSetRemoved());
diff --git a/third_party/blink/web_tests/inspector-protocol/timeline/page-frames-expected.txt b/third_party/blink/web_tests/inspector-protocol/timeline/page-frames-expected.txt
index f71baa15..f7d8a2e 100644
--- a/third_party/blink/web_tests/inspector-protocol/timeline/page-frames-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/timeline/page-frames-expected.txt
@@ -1,10 +1,9 @@
 Tests certain trace events in iframes.
 Recording started
 Tracing complete
-Frames in TracingStartedInBrowser
-url: inspector-protocol/resources/inspector-protocol-page.html name:  parent: undefined nodeId: undefined
-url: data:text/html,<script>window.foo = 42</script> name: frame0 parent: string nodeId: undefined
-Frames in CommitLoad events
-url: about:blank name: Frame No. 1 parent: string nodeId: number
-url: inspector-protocol/resources/blank.html name:  parent: string nodeId: number
+Frames:
+  url: inspector-protocol/resources/inspector-protocol-page.html name:  parentUrl: -
+  url: data:text/html,<script>window.foo = 42</script> name: frame0 parentUrl: inspector-protocol/resources/inspector-protocol-page.html
+  url: about:blank name: Frame No. 1 parentUrl: inspector-protocol/resources/inspector-protocol-page.html
+  url: inspector-protocol/resources/blank.html name:  parentUrl: inspector-protocol/resources/inspector-protocol-page.html
 
diff --git a/third_party/blink/web_tests/inspector-protocol/timeline/page-frames.js b/third_party/blink/web_tests/inspector-protocol/timeline/page-frames.js
index c0e197d..d2915863 100644
--- a/third_party/blink/web_tests/inspector-protocol/timeline/page-frames.js
+++ b/third_party/blink/web_tests/inspector-protocol/timeline/page-frames.js
@@ -20,21 +20,23 @@
   const tracingHelper = new TracingHelper(testRunner, session);
   await tracingHelper.invokeAsyncWithTracing(performActions);
 
-  testRunner.log('Frames in TracingStartedInBrowser');
+  const frames = new Map();
+
   const tracingStarted = tracingHelper.findEvent('TracingStartedInBrowser', 'I');
-  for (const frame of tracingStarted.args['data']['frames'] || []) {
-    dumpFrame(frame);
-  }
+  startFrames = tracingStarted.args['data']['frames'] || [];
+  startFrames.forEach(f => frames.set(f.frame, f));
 
-  testRunner.log('Frames in CommitLoad events');
   const commitLoads = tracingHelper.findEvents('CommitLoad', 'X');
-  for (const event of commitLoads) {
-    dumpFrame(event.args['data']);
-  }
-  testRunner.completeTest();
+  commitLoads.forEach(({args: {data: f}}) => frames.set(f.frame, f));
 
-  function dumpFrame(frame) {
-    const url = frame.url.replace(/.*\/(([^/]*\/){2}[^/]*$)/, '$1');
-    testRunner.log(`url: ${url} name: ${frame.name} parent: ${typeof frame.parent} nodeId: ${typeof frame.nodeId}`);
+  const stripUrl = url => url.replace(/.*\/(([^/]*\/){2}[^/]*$)/, '$1');
+  testRunner.log('Frames:');
+  for (const [_id, frame] of frames) {
+    const url = stripUrl(frame.url);
+    const parentUrl =
+        frame.parent ? stripUrl(frames.get(frame.parent).url) : '-';
+    testRunner.log(`  url: ${url} name: ${frame.name} parentUrl: ${parentUrl}`);
   }
+
+  testRunner.completeTest();
 })
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 66de7cc..3f08918 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -13943,7 +13943,7 @@
   <int value="0" label="kUnknown"/>
   <int value="1" label="kSuccess"/>
   <int value="2" label="kInstallationProhibited"/>
-  <int value="3" label="kDlcInstallError"/>
+  <int value="3" label="kToolsDlcInstallError"/>
   <int value="4" label="kDownloadError"/>
   <int value="5" label="kInvalidFirmware"/>
   <int value="6" label="kInvalidBootDisk"/>
@@ -13952,6 +13952,7 @@
   <int value="9" label="kCreateDiskError"/>
   <int value="10" label="kStartVmFailed"/>
   <int value="11" label="kInstallPflashError"/>
+  <int value="12" label="kFirmwareDlcInstallError"/>
 </enum>
 
 <enum name="BruschettaResult">
@@ -61478,6 +61479,8 @@
   <int value="-311148335" label="v8-pac-mojo-out-of-process"/>
   <int value="-310908854" label="new-wallpaper-picker"/>
   <int value="-310615515" label="EnableSuggestedFiles:disabled"/>
+  <int value="-309744108"
+      label="DiacriticsOnPhysicalKeyboardLongpressDefaultOn:enabled"/>
   <int value="-308793293" label="WebShare:disabled"/>
   <int value="-308785012"
       label="QuickIntensiveWakeUpThrottlingAfterLoading:enabled"/>
@@ -64096,6 +64099,8 @@
   <int value="1115532551" label="EnableFrameSinkDesktopCapturerInCrd:enabled"/>
   <int value="1115564918" label="LacrosWaylandLogging:enabled"/>
   <int value="1115635149" label="EnableUnifiedMultiDeviceSetup:enabled"/>
+  <int value="1115946303"
+      label="EnableMachineLearningNeuralNetworkService:enabled"/>
   <int value="1116084116" label="BindingManagerConnectionLimit:enabled"/>
   <int value="1116593018" label="CaptureThumbnailOnLoadFinished:disabled"/>
   <int value="1116798400" label="NoncedPartitionedCookies:enabled"/>
@@ -65926,6 +65931,8 @@
       label="WebAuthenticationPasskeysUIExperiment:disabled"/>
   <int value="2098714203" label="enable-generic-sensors"/>
   <int value="2098907258" label="UseSurfaceLayerForVideo:disabled"/>
+  <int value="2099135667"
+      label="EnableMachineLearningNeuralNetworkService:disabled"/>
   <int value="2099583779" label="DefaultLinkCapturingInBrowser:enabled"/>
   <int value="2099945365" label="OmniboxAssistantVoiceSearch:enabled"/>
   <int value="2100128918" label="LibAssistantV2:enabled"/>
@@ -65970,6 +65977,8 @@
       label="lacros-data-backward-migration-policy:enabled"/>
   <int value="2122023503" label="enable-win32k-lockdown-mimetypes"/>
   <int value="2122256719" label="EnableCardboard:disabled"/>
+  <int value="2122690871"
+      label="DiacriticsOnPhysicalKeyboardLongpressDefaultOn:disabled"/>
   <int value="2122863344" label="WebViewSurfaceControl:disabled"/>
   <int value="2122876605" label="enable-bleeding-edge-rendering-fast-paths"/>
   <int value="2123183411" label="BlinkHeapIncrementalMarking:enabled"/>
@@ -70846,6 +70855,13 @@
   <int value="18" label="isolated-app"/>
 </enum>
 
+<enum name="NavigationSuddenTerminationDisabler">
+  <int value="0" label="Subframe-None"/>
+  <int value="1" label="MainFrame-None"/>
+  <int value="2" label="Subframe-Unload"/>
+  <int value="3" label="MainFrame-Unload"/>
+</enum>
+
 <enum name="NavigationSuggestionDigitalAssetLinkValidationEvent">
   <int value="0" label="kNone"/>
   <int value="1" label="kStarted">
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index 60d47107..a11c010b 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -571,7 +571,7 @@
 </histogram>
 
 <histogram name="Apps.AppList.FileResult.DefaultRelevanceUsed"
-    enum="BooleanUsage" expires_after="2023-05-30">
+    enum="BooleanUsage" expires_after="2023-11-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -584,7 +584,7 @@
 </histogram>
 
 <histogram name="Apps.AppList.FileResult.ThumbnailLoadedError"
-    enum="PlatformFileError" expires_after="2023-05-30">
+    enum="PlatformFileError" expires_after="2023-11-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -673,7 +673,7 @@
 </histogram>
 
 <histogram name="Apps.AppList.HelpAppProvider.QueryTime" units="ms"
-    expires_after="2023-05-30">
+    expires_after="2023-11-30">
   <owner>wrong@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>tby@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/local/histograms.xml b/tools/metrics/histograms/metadata/local/histograms.xml
index ef29b71..25fe2b8 100644
--- a/tools/metrics/histograms/metadata/local/histograms.xml
+++ b/tools/metrics/histograms/metadata/local/histograms.xml
@@ -38,7 +38,7 @@
 </variants>
 
 <histogram name="LocalSearchService.BindIndexHasError" enum="Boolean"
-    expires_after="2023-05-31">
+    expires_after="2023-11-30">
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
@@ -49,7 +49,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.MetricsDailyEventInterval"
-    enum="DailyEventIntervalType" expires_after="2023-05-31">
+    enum="DailyEventIntervalType" expires_after="2023-11-30">
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
@@ -59,7 +59,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.{IndexId}AddOrUpdateLatency" units="ms"
-    expires_after="2023-05-31">
+    expires_after="2023-11-30">
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
@@ -73,7 +73,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.{IndexId}Backend"
-    enum="LocalSearchServiceBackend" expires_after="2023-05-31">
+    enum="LocalSearchServiceBackend" expires_after="2023-11-30">
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
@@ -87,7 +87,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.{IndexId}ClearIndexLatency" units="ms"
-    expires_after="2023-05-31">
+    expires_after="2023-11-30">
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
@@ -101,7 +101,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.{IndexId}DailySearch" units="count"
-    expires_after="2023-05-31">
+    expires_after="2023-11-30">
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
@@ -120,7 +120,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.{IndexId}DeleteLatency" units="ms"
-    expires_after="2023-05-31">
+    expires_after="2023-11-30">
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
@@ -134,7 +134,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.{IndexId}NumberDocuments" units="count"
-    expires_after="2023-05-31">
+    expires_after="2023-11-30">
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
@@ -149,7 +149,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.{IndexId}NumberResults" units="count"
-    expires_after="2023-05-31">
+    expires_after="2023-11-30">
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
@@ -162,7 +162,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.{IndexId}NumberSearchPerformedDone"
-    enum="Boolean" expires_after="2023-05-31">
+    enum="Boolean" expires_after="2023-11-30">
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
@@ -176,7 +176,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.{IndexId}ResponseStatus"
-    enum="LocalSearchServiceResponseStatus" expires_after="2023-05-31">
+    enum="LocalSearchServiceResponseStatus" expires_after="2023-11-30">
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
@@ -189,7 +189,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.{IndexId}SearchLatency" units="ms"
-    expires_after="2023-05-31">
+    expires_after="2023-11-30">
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
@@ -203,7 +203,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.{IndexId}UpdateDocumentsLatency" units="ms"
-    expires_after="2023-05-31">
+    expires_after="2023-11-30">
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index 604f41b..6f277bf 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -1365,6 +1365,24 @@
   </summary>
 </histogram>
 
+<histogram name="Navigation.SuddenTerminationDisabler.{Origins}"
+    enum="NavigationSuddenTerminationDisabler" expires_after="2023-10-11">
+  <owner>fergal@chromium.org</owner>
+  <owner>rakina@chromium.org</owner>
+  <summary>
+    Records the combination of mainframe/subframe and what sudden termination
+    disablers were present. This is recorded on every cross-document navigation.
+    Currently only covers Unload. The SameOrigin variant only considers a frame
+    to be same origin as the main frame if it can be reached through a chain of
+    same-origin frames. So e.g. in a-&gt;b-&gt;a, the second a is not
+    same-origin.
+  </summary>
+  <token key="Origins">
+    <variant name="AllOrigins"/>
+    <variant name="SameOrigin"/>
+  </token>
+</histogram>
+
 <histogram name="Navigation.ThrottleDeferTime.{Event}" units="ms"
     expires_after="2023-02-11">
   <owner>cduvall@chromium.org</owner>
@@ -1667,19 +1685,6 @@
 </histogram>
 
 <histogram
-    name="Prerender.Experimental.CancellationPercentageByExcessiveMemoryUsage.SpeculationRule"
-    units="%" expires_after="2023-08-27">
-  <owner>asamidoi@chromium.org</owner>
-  <owner>chrome-prerendering@google.com</owner>
-  <summary>
-    Records the percentage of destroyed prerenders due to the excessive memory
-    usage in started prerenders. The result should be an integer between 0 and
-    100. This is recorded when SpeculationHostImpl is destructed or a primary
-    page is updated.
-  </summary>
-</histogram>
-
-<histogram
     name="Prerender.Experimental.CrossOriginRedirectionProtocolChange{PrerenderTriggerType}"
     enum="PrerenderCrossOriginRedirectionProtocolChange"
     expires_after="2023-09-03">
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index f8f0fd1..fcdf5bc 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -3299,7 +3299,7 @@
 
 <histogram name="ContextMenu.TimeToSelectShare" units="ms"
     expires_after="2023-02-19">
-  <owner>gayane@chromium.org</owner>
+  <owner>jeffreycohen@chromium.org</owner>
   <owner>chrome-shared-highlighting@google.com</owner>
   <summary>
     Records how long it takes to press on &quot;Share&quot; from the time
diff --git a/tools/style_variable_generator/css_generator.py b/tools/style_variable_generator/css_generator.py
index 9be65dcf..b89099d8 100644
--- a/tools/style_variable_generator/css_generator.py
+++ b/tools/style_variable_generator/css_generator.py
@@ -95,6 +95,9 @@
                 '$css_name-font-weight',
                 '$css_name-line-height',
             ])
+        elif variable_type == VariableType.LEGACY_MAPPING:
+            # No Clients should be directly using any of the legacy mappings.
+            pass
         else:
             raise ValueError("GetGeneratedVars() for '%s' not implemented")
 
diff --git a/tools/style_variable_generator/model.py b/tools/style_variable_generator/model.py
index a6e11b5..3e594bcc 100644
--- a/tools/style_variable_generator/model.py
+++ b/tools/style_variable_generator/model.py
@@ -9,6 +9,13 @@
 from abc import ABC, abstractmethod
 
 
+def full_token_name(name, context):
+    namespace = context['token_namespace']
+    if namespace:
+        return f'{namespace}.{name}'
+    return name
+
+
 class Modes:
     LIGHT = 'light'
     DARK = 'dark'
@@ -158,12 +165,12 @@
         self.variable_type = VariableType.COLOR
 
     def Add(self, name, value_obj, context):
+        name = full_token_name(name, context)
         added = []
         # If a color has generate_per_mode set, a separate variable will be
         # created for each mode, suffixed by mode name.
         # (e.g my_color_light, my_color_debug)
         generate_per_mode = False
-
         # If a color has generate_inverted set, a |color_name|_inverted will be
         # generated which uses the dark color for light mode and vice versa.
         generate_inverted = False
@@ -278,7 +285,6 @@
     def _CreateValue(self, value):
         return Color(value)
 
-
 class SimpleModel(collections.OrderedDict, Submodel):
     def __init__(self, variable_type, check_func=None):
         self.variable_type = variable_type
@@ -291,6 +297,13 @@
         return [StyleVariable(self.variable_type, name, value_obj, context)]
 
 
+# A simple model where all variables are prefixed with the current namespace.
+class NamespacedModel(SimpleModel):
+    def Add(self, name, value_obj, context):
+        name = full_token_name(name, context)
+        return super().Add(name, value_obj, context)
+
+
 class Model(object):
     def __init__(self):
         # A map of all variables to their |StyleVariable| object.
@@ -305,7 +318,7 @@
         self.colors = ColorModel(self.opacities)
         self.submodels[VariableType.COLOR] = self.colors
 
-        self.untyped_css = SimpleModel(VariableType.UNTYPED_CSS)
+        self.untyped_css = NamespacedModel(VariableType.UNTYPED_CSS)
         self.submodels[VariableType.UNTYPED_CSS] = self.untyped_css
 
         self.legacy_mappings = SimpleModel(VariableType.LEGACY_MAPPING)
@@ -317,23 +330,22 @@
             assert value_obj['font_weight']
             assert value_obj['line_height']
 
-        self.typefaces = SimpleModel(VariableType.TYPEFACE, CheckTypeFace)
+        self.typefaces = NamespacedModel(VariableType.TYPEFACE, CheckTypeFace)
         self.submodels[VariableType.TYPEFACE] = self.typefaces
 
         def CheckFontFamily(name, value_obj, context):
             assert name.startswith('font_family_')
 
-        self.font_families = SimpleModel(VariableType.FONT_FAMILY,
-                                         CheckFontFamily)
+        self.font_families = NamespacedModel(VariableType.FONT_FAMILY,
+                                             CheckFontFamily)
         self.submodels[VariableType.FONT_FAMILY] = self.font_families
 
     def Add(self, variable_type, name, value_obj, context):
         '''Adds a new variable to the submodel for |variable_type|.
         '''
         try:
-            full_name = self.FullTokenName(name, context)
-            added = self.submodels[variable_type].Add(full_name, value_obj,
-                                                      context)
+            submodel = self.submodels[variable_type]
+            added = self.submodels[variable_type].Add(name, value_obj, context)
         except ValueError as err:
             raise ValueError(
                 f'Error parsing {variable_type} "{full_name}": {value_obj}'
@@ -344,11 +356,6 @@
                 raise ValueError('Variable name "%s" is reused' % name)
             self.variable_map[var.name] = var
 
-    def FullTokenName(self, name, context):
-        namespace = context['token_namespace']
-        if namespace:
-            return f'{namespace}.{name}'
-        return name
 
     def PostProcess(self, default_preblend=True):
         '''Called after all variables have been added to perform operations that
diff --git a/tools/style_variable_generator/templates/ts_generator.tmpl b/tools/style_variable_generator/templates/ts_generator.tmpl
index a170701..d8b1bd42 100644
--- a/tools/style_variable_generator/templates/ts_generator.tmpl
+++ b/tools/style_variable_generator/templates/ts_generator.tmpl
@@ -31,6 +31,11 @@
    * mode values and ignores the documents prefers-color-scheme.
    */
   lockTheme?: 'light' | 'dark';
+  /**
+   * Opt into using material 3 color tokens (see go/cros-tokens). If true any
+   * legacy mappings specified in the input json5 files will be added into the
+   * document.
+   */
   useDynamicColors?: boolean;
 }
 
@@ -90,48 +95,32 @@
  * that all TS constant references resolve correctly.
  */
 export function getColorsCSS(options?: GetColorsCSSOptions) {
-  const legacyMappings = options?.useDynamicColors ? LEGACY_MAPPINGS_CSS : '';
-
-  let cssString;
-  if (options?.lockTheme === 'light') {
-    // Tag strings which are safe with a special comment so copybara can add
-    // the right safety wrappers whem moving this code into Google3.
+  // Tag strings which are safe with a special comment so copybara can add
+  // the right safety wrappers whem moving this code into Google3.
+  let cssString = /* SAFE */ ("");
+{% for lockTheme in ['\'light\'', '\'dark\'', 'undefined'] -%}
+{%-   for useDynamicColors in ['true', 'false'] %}
+  if (options?.lockTheme === {{lockTheme}} && !!options?.useDynamicColors === {{useDynamicColors}}) {
     cssString = /* SAFE */ (`
       html:not(body), :host {
         ${DEFAULT_CSS}
         ${UNTYPED_CSS}
         ${TYPOGRAPHY_CSS}
-        ${legacyMappings}
+{%-       if lockTheme == '\'dark\'' %}
+        ${DARK_MODE_OVERRIDES_CSS}
+{%-       endif %}
+{%-       if useDynamicColors == 'true' %}
+        ${LEGACY_MAPPINGS_CSS}
+{%-       endif %}
       }
       :host([inverted-colors]) {
-        ${DARK_MODE_OVERRIDES_CSS}
-      }
-    `);
-  } else if (options?.lockTheme === 'dark') {
-    cssString = /* SAFE */ (`
-      html:not(body), :host {
+{%-       if lockTheme == '\'dark\'' %}
         ${DEFAULT_CSS}
-        ${UNTYPED_CSS}
-        ${TYPOGRAPHY_CSS}
+{%-       else %}
         ${DARK_MODE_OVERRIDES_CSS}
-        ${legacyMappings}
+{%-       endif %}
       }
-      :host([inverted-colors]) {
-        ${DEFAULT_CSS}
-      }
-    `);
-  } else {
-    cssString = /* SAFE */ (`
-      html:not(body), :host {
-        ${DEFAULT_CSS}
-        ${UNTYPED_CSS}
-        ${TYPOGRAPHY_CSS}
-        ${legacyMappings}
-      }
-      :host([inverted-colors]) {
-        ${DARK_MODE_OVERRIDES_CSS}
-      }
-
+{%       if lockTheme == 'undefined' %}
       @media (prefers-color-scheme: dark) {
         html:not(body), :host {
           ${DARK_MODE_OVERRIDES_CSS}
@@ -140,9 +129,11 @@
           ${DEFAULT_CSS}
         }
       }
+{%-       endif %}
     `);
   }
-
+{%-   endfor -%}
+{%- endfor %}
   return cssString;
 }
 
diff --git a/tools/style_variable_generator/tests/colors_sys_tokens_test.json5 b/tools/style_variable_generator/tests/colors_sys_tokens_test.json5
index ae9b0ab..dc743043 100644
--- a/tools/style_variable_generator/tests/colors_sys_tokens_test.json5
+++ b/tools/style_variable_generator/tests/colors_sys_tokens_test.json5
@@ -9,6 +9,9 @@
       field_id: 2,
     },
   },
+  legacy_mappings: {
+    'cros-color-primary' : '$cros.sys.primary-container',
+  },
   colors: {
     /* Primary */
     primary: {
diff --git a/tools/style_variable_generator/tests/goldens/colors_test_include_style_sheet_expected.ts b/tools/style_variable_generator/tests/goldens/colors_test_include_style_sheet_expected.ts
index 9640361..ee0610b 100644
--- a/tools/style_variable_generator/tests/goldens/colors_test_include_style_sheet_expected.ts
+++ b/tools/style_variable_generator/tests/goldens/colors_test_include_style_sheet_expected.ts
@@ -16,6 +16,11 @@
    * mode values and ignores the documents prefers-color-scheme.
    */
   lockTheme?: 'light' | 'dark';
+  /**
+   * Opt into using material 3 color tokens (see go/cros-tokens). If true any
+   * legacy mappings specified in the input json5 files will be added into the
+   * document.
+   */
   useDynamicColors?: boolean;
 }
 
@@ -70,43 +75,73 @@
  * that all TS constant references resolve correctly.
  */
 export function getColorsCSS(options?: GetColorsCSSOptions) {
-  const legacyMappings = options?.useDynamicColors ? LEGACY_MAPPINGS_CSS : '';
+  // Tag strings which are safe with a special comment so copybara can add
+  // the right safety wrappers whem moving this code into Google3.
+  let cssString = /* SAFE */ ("");
 
-  let cssString;
-  if (options?.lockTheme === 'light') {
-    // Tag strings which are safe with a special comment so copybara can add
-    // the right safety wrappers whem moving this code into Google3.
+  if (options?.lockTheme === 'light' && !!options?.useDynamicColors === true) {
     cssString = /* SAFE */ (`
       html:not(body), :host {
         ${DEFAULT_CSS}
         ${UNTYPED_CSS}
         ${TYPOGRAPHY_CSS}
-        ${legacyMappings}
+        ${LEGACY_MAPPINGS_CSS}
       }
       :host([inverted-colors]) {
         ${DARK_MODE_OVERRIDES_CSS}
       }
+
     `);
-  } else if (options?.lockTheme === 'dark') {
+  }
+  if (options?.lockTheme === 'light' && !!options?.useDynamicColors === false) {
+    cssString = /* SAFE */ (`
+      html:not(body), :host {
+        ${DEFAULT_CSS}
+        ${UNTYPED_CSS}
+        ${TYPOGRAPHY_CSS}
+      }
+      :host([inverted-colors]) {
+        ${DARK_MODE_OVERRIDES_CSS}
+      }
+
+    `);
+  }
+  if (options?.lockTheme === 'dark' && !!options?.useDynamicColors === true) {
     cssString = /* SAFE */ (`
       html:not(body), :host {
         ${DEFAULT_CSS}
         ${UNTYPED_CSS}
         ${TYPOGRAPHY_CSS}
         ${DARK_MODE_OVERRIDES_CSS}
-        ${legacyMappings}
+        ${LEGACY_MAPPINGS_CSS}
       }
       :host([inverted-colors]) {
         ${DEFAULT_CSS}
       }
+
     `);
-  } else {
+  }
+  if (options?.lockTheme === 'dark' && !!options?.useDynamicColors === false) {
     cssString = /* SAFE */ (`
       html:not(body), :host {
         ${DEFAULT_CSS}
         ${UNTYPED_CSS}
         ${TYPOGRAPHY_CSS}
-        ${legacyMappings}
+        ${DARK_MODE_OVERRIDES_CSS}
+      }
+      :host([inverted-colors]) {
+        ${DEFAULT_CSS}
+      }
+
+    `);
+  }
+  if (options?.lockTheme === undefined && !!options?.useDynamicColors === true) {
+    cssString = /* SAFE */ (`
+      html:not(body), :host {
+        ${DEFAULT_CSS}
+        ${UNTYPED_CSS}
+        ${TYPOGRAPHY_CSS}
+        ${LEGACY_MAPPINGS_CSS}
       }
       :host([inverted-colors]) {
         ${DARK_MODE_OVERRIDES_CSS}
@@ -122,7 +157,27 @@
       }
     `);
   }
+  if (options?.lockTheme === undefined && !!options?.useDynamicColors === false) {
+    cssString = /* SAFE */ (`
+      html:not(body), :host {
+        ${DEFAULT_CSS}
+        ${UNTYPED_CSS}
+        ${TYPOGRAPHY_CSS}
+      }
+      :host([inverted-colors]) {
+        ${DARK_MODE_OVERRIDES_CSS}
+      }
 
+      @media (prefers-color-scheme: dark) {
+        html:not(body), :host {
+          ${DARK_MODE_OVERRIDES_CSS}
+        }
+        :host([inverted-colors]) {
+          ${DEFAULT_CSS}
+        }
+      }
+    `);
+  }
   return cssString;
 }
 
diff --git a/tools/style_variable_generator/tests/goldens/colors_test_typography_and_untyped_css_expected.ts b/tools/style_variable_generator/tests/goldens/colors_test_typography_and_untyped_css_expected.ts
index f8398cd..2666d55 100644
--- a/tools/style_variable_generator/tests/goldens/colors_test_typography_and_untyped_css_expected.ts
+++ b/tools/style_variable_generator/tests/goldens/colors_test_typography_and_untyped_css_expected.ts
@@ -18,6 +18,11 @@
    * mode values and ignores the documents prefers-color-scheme.
    */
   lockTheme?: 'light' | 'dark';
+  /**
+   * Opt into using material 3 color tokens (see go/cros-tokens). If true any
+   * legacy mappings specified in the input json5 files will be added into the
+   * document.
+   */
   useDynamicColors?: boolean;
 }
 
@@ -87,43 +92,73 @@
  * that all TS constant references resolve correctly.
  */
 export function getColorsCSS(options?: GetColorsCSSOptions) {
-  const legacyMappings = options?.useDynamicColors ? LEGACY_MAPPINGS_CSS : '';
+  // Tag strings which are safe with a special comment so copybara can add
+  // the right safety wrappers whem moving this code into Google3.
+  let cssString = /* SAFE */ ("");
 
-  let cssString;
-  if (options?.lockTheme === 'light') {
-    // Tag strings which are safe with a special comment so copybara can add
-    // the right safety wrappers whem moving this code into Google3.
+  if (options?.lockTheme === 'light' && !!options?.useDynamicColors === true) {
     cssString = /* SAFE */ (`
       html:not(body), :host {
         ${DEFAULT_CSS}
         ${UNTYPED_CSS}
         ${TYPOGRAPHY_CSS}
-        ${legacyMappings}
+        ${LEGACY_MAPPINGS_CSS}
       }
       :host([inverted-colors]) {
         ${DARK_MODE_OVERRIDES_CSS}
       }
+
     `);
-  } else if (options?.lockTheme === 'dark') {
+  }
+  if (options?.lockTheme === 'light' && !!options?.useDynamicColors === false) {
+    cssString = /* SAFE */ (`
+      html:not(body), :host {
+        ${DEFAULT_CSS}
+        ${UNTYPED_CSS}
+        ${TYPOGRAPHY_CSS}
+      }
+      :host([inverted-colors]) {
+        ${DARK_MODE_OVERRIDES_CSS}
+      }
+
+    `);
+  }
+  if (options?.lockTheme === 'dark' && !!options?.useDynamicColors === true) {
     cssString = /* SAFE */ (`
       html:not(body), :host {
         ${DEFAULT_CSS}
         ${UNTYPED_CSS}
         ${TYPOGRAPHY_CSS}
         ${DARK_MODE_OVERRIDES_CSS}
-        ${legacyMappings}
+        ${LEGACY_MAPPINGS_CSS}
       }
       :host([inverted-colors]) {
         ${DEFAULT_CSS}
       }
+
     `);
-  } else {
+  }
+  if (options?.lockTheme === 'dark' && !!options?.useDynamicColors === false) {
     cssString = /* SAFE */ (`
       html:not(body), :host {
         ${DEFAULT_CSS}
         ${UNTYPED_CSS}
         ${TYPOGRAPHY_CSS}
-        ${legacyMappings}
+        ${DARK_MODE_OVERRIDES_CSS}
+      }
+      :host([inverted-colors]) {
+        ${DEFAULT_CSS}
+      }
+
+    `);
+  }
+  if (options?.lockTheme === undefined && !!options?.useDynamicColors === true) {
+    cssString = /* SAFE */ (`
+      html:not(body), :host {
+        ${DEFAULT_CSS}
+        ${UNTYPED_CSS}
+        ${TYPOGRAPHY_CSS}
+        ${LEGACY_MAPPINGS_CSS}
       }
       :host([inverted-colors]) {
         ${DARK_MODE_OVERRIDES_CSS}
@@ -139,7 +174,27 @@
       }
     `);
   }
+  if (options?.lockTheme === undefined && !!options?.useDynamicColors === false) {
+    cssString = /* SAFE */ (`
+      html:not(body), :host {
+        ${DEFAULT_CSS}
+        ${UNTYPED_CSS}
+        ${TYPOGRAPHY_CSS}
+      }
+      :host([inverted-colors]) {
+        ${DARK_MODE_OVERRIDES_CSS}
+      }
 
+      @media (prefers-color-scheme: dark) {
+        html:not(body), :host {
+          ${DARK_MODE_OVERRIDES_CSS}
+        }
+        :host([inverted-colors]) {
+          ${DEFAULT_CSS}
+        }
+      }
+    `);
+  }
   return cssString;
 }
 
diff --git a/tools/style_variable_generator/tests/goldens/colors_test_typography_expected.ts b/tools/style_variable_generator/tests/goldens/colors_test_typography_expected.ts
index 05ec671..00e6c23 100644
--- a/tools/style_variable_generator/tests/goldens/colors_test_typography_expected.ts
+++ b/tools/style_variable_generator/tests/goldens/colors_test_typography_expected.ts
@@ -17,6 +17,11 @@
    * mode values and ignores the documents prefers-color-scheme.
    */
   lockTheme?: 'light' | 'dark';
+  /**
+   * Opt into using material 3 color tokens (see go/cros-tokens). If true any
+   * legacy mappings specified in the input json5 files will be added into the
+   * document.
+   */
   useDynamicColors?: boolean;
 }
 
@@ -82,43 +87,73 @@
  * that all TS constant references resolve correctly.
  */
 export function getColorsCSS(options?: GetColorsCSSOptions) {
-  const legacyMappings = options?.useDynamicColors ? LEGACY_MAPPINGS_CSS : '';
+  // Tag strings which are safe with a special comment so copybara can add
+  // the right safety wrappers whem moving this code into Google3.
+  let cssString = /* SAFE */ ("");
 
-  let cssString;
-  if (options?.lockTheme === 'light') {
-    // Tag strings which are safe with a special comment so copybara can add
-    // the right safety wrappers whem moving this code into Google3.
+  if (options?.lockTheme === 'light' && !!options?.useDynamicColors === true) {
     cssString = /* SAFE */ (`
       html:not(body), :host {
         ${DEFAULT_CSS}
         ${UNTYPED_CSS}
         ${TYPOGRAPHY_CSS}
-        ${legacyMappings}
+        ${LEGACY_MAPPINGS_CSS}
       }
       :host([inverted-colors]) {
         ${DARK_MODE_OVERRIDES_CSS}
       }
+
     `);
-  } else if (options?.lockTheme === 'dark') {
+  }
+  if (options?.lockTheme === 'light' && !!options?.useDynamicColors === false) {
+    cssString = /* SAFE */ (`
+      html:not(body), :host {
+        ${DEFAULT_CSS}
+        ${UNTYPED_CSS}
+        ${TYPOGRAPHY_CSS}
+      }
+      :host([inverted-colors]) {
+        ${DARK_MODE_OVERRIDES_CSS}
+      }
+
+    `);
+  }
+  if (options?.lockTheme === 'dark' && !!options?.useDynamicColors === true) {
     cssString = /* SAFE */ (`
       html:not(body), :host {
         ${DEFAULT_CSS}
         ${UNTYPED_CSS}
         ${TYPOGRAPHY_CSS}
         ${DARK_MODE_OVERRIDES_CSS}
-        ${legacyMappings}
+        ${LEGACY_MAPPINGS_CSS}
       }
       :host([inverted-colors]) {
         ${DEFAULT_CSS}
       }
+
     `);
-  } else {
+  }
+  if (options?.lockTheme === 'dark' && !!options?.useDynamicColors === false) {
     cssString = /* SAFE */ (`
       html:not(body), :host {
         ${DEFAULT_CSS}
         ${UNTYPED_CSS}
         ${TYPOGRAPHY_CSS}
-        ${legacyMappings}
+        ${DARK_MODE_OVERRIDES_CSS}
+      }
+      :host([inverted-colors]) {
+        ${DEFAULT_CSS}
+      }
+
+    `);
+  }
+  if (options?.lockTheme === undefined && !!options?.useDynamicColors === true) {
+    cssString = /* SAFE */ (`
+      html:not(body), :host {
+        ${DEFAULT_CSS}
+        ${UNTYPED_CSS}
+        ${TYPOGRAPHY_CSS}
+        ${LEGACY_MAPPINGS_CSS}
       }
       :host([inverted-colors]) {
         ${DARK_MODE_OVERRIDES_CSS}
@@ -134,7 +169,27 @@
       }
     `);
   }
+  if (options?.lockTheme === undefined && !!options?.useDynamicColors === false) {
+    cssString = /* SAFE */ (`
+      html:not(body), :host {
+        ${DEFAULT_CSS}
+        ${UNTYPED_CSS}
+        ${TYPOGRAPHY_CSS}
+      }
+      :host([inverted-colors]) {
+        ${DARK_MODE_OVERRIDES_CSS}
+      }
 
+      @media (prefers-color-scheme: dark) {
+        html:not(body), :host {
+          ${DARK_MODE_OVERRIDES_CSS}
+        }
+        :host([inverted-colors]) {
+          ${DEFAULT_CSS}
+        }
+      }
+    `);
+  }
   return cssString;
 }
 
diff --git a/tools/style_variable_generator/tests/goldens/colors_test_untyped_css_expected.ts b/tools/style_variable_generator/tests/goldens/colors_test_untyped_css_expected.ts
index 6468915..7fad399 100644
--- a/tools/style_variable_generator/tests/goldens/colors_test_untyped_css_expected.ts
+++ b/tools/style_variable_generator/tests/goldens/colors_test_untyped_css_expected.ts
@@ -17,6 +17,11 @@
    * mode values and ignores the documents prefers-color-scheme.
    */
   lockTheme?: 'light' | 'dark';
+  /**
+   * Opt into using material 3 color tokens (see go/cros-tokens). If true any
+   * legacy mappings specified in the input json5 files will be added into the
+   * document.
+   */
   useDynamicColors?: boolean;
 }
 
@@ -75,43 +80,73 @@
  * that all TS constant references resolve correctly.
  */
 export function getColorsCSS(options?: GetColorsCSSOptions) {
-  const legacyMappings = options?.useDynamicColors ? LEGACY_MAPPINGS_CSS : '';
+  // Tag strings which are safe with a special comment so copybara can add
+  // the right safety wrappers whem moving this code into Google3.
+  let cssString = /* SAFE */ ("");
 
-  let cssString;
-  if (options?.lockTheme === 'light') {
-    // Tag strings which are safe with a special comment so copybara can add
-    // the right safety wrappers whem moving this code into Google3.
+  if (options?.lockTheme === 'light' && !!options?.useDynamicColors === true) {
     cssString = /* SAFE */ (`
       html:not(body), :host {
         ${DEFAULT_CSS}
         ${UNTYPED_CSS}
         ${TYPOGRAPHY_CSS}
-        ${legacyMappings}
+        ${LEGACY_MAPPINGS_CSS}
       }
       :host([inverted-colors]) {
         ${DARK_MODE_OVERRIDES_CSS}
       }
+
     `);
-  } else if (options?.lockTheme === 'dark') {
+  }
+  if (options?.lockTheme === 'light' && !!options?.useDynamicColors === false) {
+    cssString = /* SAFE */ (`
+      html:not(body), :host {
+        ${DEFAULT_CSS}
+        ${UNTYPED_CSS}
+        ${TYPOGRAPHY_CSS}
+      }
+      :host([inverted-colors]) {
+        ${DARK_MODE_OVERRIDES_CSS}
+      }
+
+    `);
+  }
+  if (options?.lockTheme === 'dark' && !!options?.useDynamicColors === true) {
     cssString = /* SAFE */ (`
       html:not(body), :host {
         ${DEFAULT_CSS}
         ${UNTYPED_CSS}
         ${TYPOGRAPHY_CSS}
         ${DARK_MODE_OVERRIDES_CSS}
-        ${legacyMappings}
+        ${LEGACY_MAPPINGS_CSS}
       }
       :host([inverted-colors]) {
         ${DEFAULT_CSS}
       }
+
     `);
-  } else {
+  }
+  if (options?.lockTheme === 'dark' && !!options?.useDynamicColors === false) {
     cssString = /* SAFE */ (`
       html:not(body), :host {
         ${DEFAULT_CSS}
         ${UNTYPED_CSS}
         ${TYPOGRAPHY_CSS}
-        ${legacyMappings}
+        ${DARK_MODE_OVERRIDES_CSS}
+      }
+      :host([inverted-colors]) {
+        ${DEFAULT_CSS}
+      }
+
+    `);
+  }
+  if (options?.lockTheme === undefined && !!options?.useDynamicColors === true) {
+    cssString = /* SAFE */ (`
+      html:not(body), :host {
+        ${DEFAULT_CSS}
+        ${UNTYPED_CSS}
+        ${TYPOGRAPHY_CSS}
+        ${LEGACY_MAPPINGS_CSS}
       }
       :host([inverted-colors]) {
         ${DARK_MODE_OVERRIDES_CSS}
@@ -127,7 +162,27 @@
       }
     `);
   }
+  if (options?.lockTheme === undefined && !!options?.useDynamicColors === false) {
+    cssString = /* SAFE */ (`
+      html:not(body), :host {
+        ${DEFAULT_CSS}
+        ${UNTYPED_CSS}
+        ${TYPOGRAPHY_CSS}
+      }
+      :host([inverted-colors]) {
+        ${DARK_MODE_OVERRIDES_CSS}
+      }
 
+      @media (prefers-color-scheme: dark) {
+        html:not(body), :host {
+          ${DARK_MODE_OVERRIDES_CSS}
+        }
+        :host([inverted-colors]) {
+          ${DEFAULT_CSS}
+        }
+      }
+    `);
+  }
   return cssString;
 }
 
diff --git a/tools/style_variable_generator/tests/goldens/colors_tokens_test_expected.css b/tools/style_variable_generator/tests/goldens/colors_tokens_test_expected.css
index 2826742..1f6e527 100644
--- a/tools/style_variable_generator/tests/goldens/colors_tokens_test_expected.css
+++ b/tools/style_variable_generator/tests/goldens/colors_tokens_test_expected.css
@@ -29,6 +29,8 @@
   --cros-sys-disabled_opacity: 0.38;
 
   --cros-sys-reference_opacity: var(--cros-sys-disabled_opacity);
+
+  --cros-color-primary: var(--cros-sys-primary_container);
 }
 
 @media (prefers-color-scheme: dark) {
diff --git a/tools/style_variable_generator/tests/style_variable_generator_test.py b/tools/style_variable_generator/tests/style_variable_generator_test.py
index c77b41d3..a80d943 100755
--- a/tools/style_variable_generator/tests/style_variable_generator_test.py
+++ b/tools/style_variable_generator/tests/style_variable_generator_test.py
@@ -317,7 +317,7 @@
 ! UPDATE_GOLDENS IS TRUE. EACH TIME THE TESTS ARE RUN ALL GOLDENS
   WILL BE UPDATED TO MATCH CURRENT BEHAVIOUR.
 ! ALL TESTS WILL PASS WITHOUT BEING CHECKED.
-! THE CODE SHOULD NOT BE SUBBMITTED AS IS.
+! THE CODE SHOULD NOT BE SUBMITTED AS IS.
 ===================================================================\033[0m
         """)
     unittest.main()
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index ca8c4cb..337fe4bf6 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -412,7 +412,7 @@
  <item id="wallpaper_download_google_photo" added_in_milestone="102" content_hash_code="0565daa5" os_list="chromeos" file_path="ash/wallpaper/wallpaper_image_downloader.cc" />
  <item id="wallpaper_online_downloader" added_in_milestone="110" content_hash_code="00286fc5" os_list="chromeos" file_path="ash/wallpaper/wallpaper_image_downloader.cc" />
  <item id="chrome_support_tool_file_upload" added_in_milestone="113" content_hash_code="04a07122" os_list="chromeos" file_path="chrome/browser/policy/messaging_layer/upload/file_upload_impl.cc" />
- <item id="service_worker_race_network_request" added_in_milestone="113" content_hash_code="01abb946" os_list="linux,windows,android,chromeos" file_path="content/common/service_worker/race_network_request_url_loader_client.cc" />
+ <item id="service_worker_race_network_request" added_in_milestone="113" content_hash_code="0090e590" os_list="linux,windows,android,chromeos" file_path="content/common/service_worker/race_network_request_url_loader_client.cc" />
  <item id="safe_browsing_ohttp_key_fetch" added_in_milestone="113" content_hash_code="0309cb19" os_list="linux,windows,android,chromeos" file_path="components/safe_browsing/core/browser/hashprefix_realtime/ohttp_key_service.cc" />
  <item id="glanceables_tasks_integration" added_in_milestone="113" content_hash_code="06e038c9" os_list="chromeos" file_path="chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.cc" />
  <item id="bookmarks_image_fetcher" added_in_milestone="114" content_hash_code="01dd68ad" os_list="chromeos,linux,windows" file_path="chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc" />
diff --git a/ui/accessibility/ax_tree_serializer.h b/ui/accessibility/ax_tree_serializer.h
index a22731d..0fb9303 100644
--- a/ui/accessibility/ax_tree_serializer.h
+++ b/ui/accessibility/ax_tree_serializer.h
@@ -439,9 +439,9 @@
     return nullptr;
   if (!ClientTreeNodeById(parent->id)) {
     std::ostringstream error;
-    error << "Child: " << tree_->GetDebugString(tree_->GetFromId(obj->id))
+    error << "Child: " << tree_->GetDebugString(tree_->EnsureGetFromId(obj->id))
           << "\nParent: "
-          << tree_->GetDebugString(tree_->GetFromId(parent->id));
+          << tree_->GetDebugString(tree_->EnsureGetFromId(parent->id));
     static auto* missing_parent_err = base::debug::AllocateCrashKeyString(
         "ax_ts_missing_parent_err", base::debug::CrashKeySize::Size256);
     base::debug::SetCrashKeyString(missing_parent_err,
@@ -721,11 +721,11 @@
       // also reset virtual buffers, causing users to lose their place.
       std::ostringstream error;
       error << "Passed-in parent: "
-            << tree_->GetDebugString(tree_->GetFromId(client_node->id))
+            << tree_->GetDebugString(tree_->EnsureGetFromId(client_node->id))
             << "\nChild: " << tree_->GetDebugString(child)
             << "\nChild's parent: "
             << tree_->GetDebugString(
-                   tree_->GetFromId(client_child->parent->id));
+                   tree_->EnsureGetFromId(client_child->parent->id));
       static auto* reparent_err = base::debug::AllocateCrashKeyString(
           "ax_ts_reparent_err", base::debug::CrashKeySize::Size256);
       base::debug::SetCrashKeyString(reparent_err, error.str().substr(0, 230));
@@ -783,11 +783,12 @@
           << "A kRootWebArea role was used on an object that is not the root: "
           << "\n* Actual root: " << tree_->GetDebugString(tree_->GetRoot())
           << "\n* Illegal node with root web area role: "
-          << tree_->GetDebugString(tree_->GetFromId(serialized_node->id))
+          << tree_->GetDebugString(tree_->EnsureGetFromId(serialized_node->id))
           << "\n* Parent of illegal node: "
-          << (client_node->parent ? tree_->GetDebugString(tree_->GetFromId(
-                                        client_node->parent->id))
-                                  : "");
+          << (client_node->parent
+                  ? tree_->GetDebugString(
+                        tree_->EnsureGetFromId(client_node->parent->id))
+                  : "");
     }
   }
 
@@ -842,10 +843,10 @@
         std::ostringstream error;
         error << "Child id " << child_id << " already in map."
               << "\nChild: "
-              << tree_->GetDebugString(tree_->GetFromId(child_id))
+              << tree_->GetDebugString(tree_->EnsureGetFromId(child_id))
               << "\nWanted for parent " << tree_->GetDebugString(node)
               << "\nAlready had parent "
-              << tree_->GetDebugString(tree_->GetFromId(
+              << tree_->GetDebugString(tree_->EnsureGetFromId(
                      ClientTreeNodeById(child_id)->parent->id));
         static auto* dupe_id_err = base::debug::AllocateCrashKeyString(
             "ax_ts_dupe_id_err", base::debug::CrashKeySize::Size256);
diff --git a/ui/accessibility/ax_tree_source.h b/ui/accessibility/ax_tree_source.h
index 3f42684b..e2cacf7 100644
--- a/ui/accessibility/ax_tree_source.h
+++ b/ui/accessibility/ax_tree_source.h
@@ -41,6 +41,12 @@
   // null node.
   virtual AXNodeSource GetFromId(AXNodeID id) const = 0;
 
+  AXNodeSource EnsureGetFromId(AXNodeID id) const {
+    AXNodeSource node = GetFromId(id);
+    DCHECK(node);
+    return node;
+  }
+
   // Return the id of a node. All ids must be positive integers; 0 is not a
   // valid ID. IDs are unique only across the current tree source, not across
   // tree sources.
diff --git a/ui/accessibility/ax_tree_source_checker.h b/ui/accessibility/ax_tree_source_checker.h
index 49d2fbb..a953e78a 100644
--- a/ui/accessibility/ax_tree_source_checker.h
+++ b/ui/accessibility/ax_tree_source_checker.h
@@ -133,7 +133,7 @@
     }
     AXNodeID parent_id = tree_->GetId(parent);
     if (parent_id != expected_parent_id) {
-      AXSourceNode expected_parent = tree_->GetFromId(expected_parent_id);
+      AXSourceNode expected_parent = tree_->EnsureGetFromId(expected_parent_id);
       std::string msg = base::StringPrintf(
           "Expected node %d to have a parent of %d, but found a parent of %d.\n"
           "Node: %s\n"
diff --git a/ui/chromeos/styles/cros_sys_colors.json5 b/ui/chromeos/styles/cros_sys_colors.json5
index 7075205..3e471e6 100644
--- a/ui/chromeos/styles/cros_sys_colors.json5
+++ b/ui/chromeos/styles/cros_sys_colors.json5
@@ -18,6 +18,68 @@
       field_id: 1,
     },
   },
+  legacy_mappings: {
+    'cros-color-primary' : '$cros.sys.on-surface',
+    'cros-color-secondary' : '$cros.sys.secondary',
+    'cros-color-prominent' : '$cros.sys.primary',
+    'cros-color-disabled' : '$cros.sys.disabled',
+    'cros-text-color-secondary': '$cros.sys.on-surface-variant',
+    'cros-bg-color' : '$cros.sys.app-base',
+    'cros-bg-color-elevation1' : '$cros.sys.base-elevated',
+    'cros-bg-color-elevation2' : '$cros.sys.base-elevated',
+    'cros-bg-color-elevation3' : '$cros.sys.base-elevated',
+    'cros-bg-color-elevation4' : '$cros.sys.base-elevated',
+    'cros-bg-color-elevation5' : '$cros.sys.base-elevated',
+    'cros-bg-color-dropped-elevation1' : '$cros.sys.app-base-shaded',
+    'cros-bg-color-dropped-elevation2' : '$cros.sys.app-base-shaded',
+    'cros-ripple-color' : '$cros.sys.hover-on-prominent',
+    'cros-ripple-color-prominent' : '$cros.sys.ripple-primary',
+    'cros-separator-color' : '$cros.sys.separator',
+    'cros-link-color' : '$cros.sys.primary',
+    'cros-app-scrollbar-color' : '$cros.sys.scrollbar',
+    'cros-app-scrollbar-color-hover' : '$cros.sys.scrollbar-hover',
+    'cros-app-shield-color' : '$cros.sys.scrim',
+    'cros-app-shield20' : '$cros.sys.scrim',
+    'cros-app-shield40' : '$cros.sys.scrim',
+    'cros-app-shield60' : '$cros.sys.scrim',
+    'cros-app-shield80' : '$cros.sys.scrim',
+    'cros-highlight-color' : '$cros.sys.highlight-shape',
+    'cros-highlight-color-hover' : '$cros.sys.hover-on-subtle',
+    'cros-highlight-color-focus' : '$cros.sys.ripple-neutral-on-subtle',
+    'cros-highlight-color-error' : '$cros.sys.error-container',
+    'cros-highlight-color-green' : '$cros.sys.positive-container',
+    'cros-highlight-color-red' : '$cros.sys.error-container',
+    'cros-highlight-color-yellow' : '$cros.sys.warning-container',
+    'cros-text-highlight-color' : '$cros.sys.highlight-text',
+    'cros-button-label-color-secondary' : '$cros.sys.on-primary-container',
+    'cros-button-ripple-color-secondary' : '$cros.sys.ripple-primary',
+    'cros-highlight-color' : '$cros.sys.primary',
+    'cros-textfield-background-color' : '$cros.sys.input-field-on-shaded',
+    'cros-textfield-label-color' : '$cros.sys.on-surface',
+    'cros-slider-color-active' : '$cros.sys.primary',
+    /** cros.sys.primary-container @ 30% */
+    'cros-slider-track-color-active': 'rgba($cros.sys.primary-container.rgb,.3)',
+    /** cros.sys.primary-container @ 30% */
+    'cros-slider-track-color-inactive': 'rgba($cros.sys.disabled.rgb,.3)',
+    'cros-slider-label-text-color' : '$cros.sys.on-primary',
+    'cros-slider-color-inactive' : '$cros.sys.disabled',
+    'cros-switch-knob-color-active' : '$cros.sys.on-primary',
+    'cros-switch-knob-color-inactive' : '$cros.sys.on-secondary',
+    'cros-switch-track-color-active' : '$cros.sys.primary',
+    'cros-switch-track-color-inactive' : '$cros.sys.secondary',
+    'cros-tooltip-label-color' : '$cros.sys.inverse-on-surface',
+    'cros-tooltip-background-color' : '$cros.sys.on-surface',
+    'cros-nudge-label-color' : '$cros.sys.on-primary',
+    'cros-nudge-icon-color' : '$cros.sys.on-primary',
+    'cros-nudge-background-color' : '$cros.sys.primary',
+    'cros-menu-label-color' : '$cros.sys.on-surface',
+    'cros-menu-icon-color' : '$cros.sys.on-surface',
+    'cros-menu-shortcut-color' : '$cros.sys.secondary',
+    'cros-menu-item-background-hover' : '$cros.sys.hover-on-subtle',
+    'cros-color-positive' : '$cros.sys.positive',
+    'cros-color-warning' : '$cros.sys.warning',
+    'cros-color-alert' : '$cros.sys.error',
+  },
   colors: {
     /* Primary */
     /* If this is changed, please also update SampleColorScheme */
diff --git a/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc b/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc
index 41fdfc7c..c7cf29d 100644
--- a/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc
+++ b/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc
@@ -116,7 +116,7 @@
   return haptic_touchpad_handler_ != nullptr;
 }
 
-bool EventReaderLibevdevCros::CanHandleHapticFeedback() {
+bool EventReaderLibevdevCros::CanHandleHapticFeedback() const {
   return haptic_touchpad_handler_ && haptic_feedback_enabled_ &&
          touch_count_ > 0;
 }
diff --git a/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h b/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h
index add89f3..e99ad76 100644
--- a/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h
+++ b/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h
@@ -87,7 +87,7 @@
 
   // Returns true if this is a haptic touchpad, UI haptics are enabled, and it
   // is actively being touched.
-  bool CanHandleHapticFeedback();
+  bool CanHandleHapticFeedback() const;
 
   // Input modalities for this device.
   bool has_keyboard_;
diff --git a/ui/file_manager/BUILD.gn b/ui/file_manager/BUILD.gn
index 6030456..b3e4468 100644
--- a/ui/file_manager/BUILD.gn
+++ b/ui/file_manager/BUILD.gn
@@ -2,13 +2,13 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//ash/webui/tools/ash_ts_library.gni")
 import("//chrome/common/features.gni")
 import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/grit/grit_rule.gni")
 import("//tools/grit/preprocess_if_expr.gni")
 import("//tools/polymer/html_to_wrapper.gni")
 import("//tools/typescript/ts_definitions.gni")
+import("//tools/typescript/ts_library.gni")
 import("//ui/file_manager/file_names.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
@@ -119,12 +119,20 @@
   ]
 }
 
-ash_ts_library("build_ts") {
+ts_library("build_ts") {
   root_dir = preprocess_folder
   out_dir = "$target_gen_dir/tsc"
   tsconfig_base = "tsconfig_base.json"
   composite = true
-  use_lit = true
+
+  path_mappings = [
+    "tslib|" + rebase_path(
+            "//third_party/material_web_components/components-chromium/node_modules/tslib/tslib.d.ts",
+            target_gen_dir),
+    "chrome://resources/mwc/*|" + rebase_path(
+            "//third_party/material_web_components/components-chromium/node_modules/*",
+            target_gen_dir),
+  ]
 
   extra_deps = [
     ":copy_definitions_to_gen",
@@ -142,6 +150,7 @@
     "//ash/webui/common/resources:build_ts",
     "//third_party/cros-components:cros_components_ts",
     "//third_party/material_web_components:bundle_lit_ts",
+    "//third_party/material_web_components:library",
     "//third_party/polymer/v3_0:library",
     "//ui/webui/resources/cr_elements:build_ts",
     "//ui/webui/resources/js:build_ts",
diff --git a/ui/file_manager/file_manager/common/js/tslib_shim.ts b/ui/file_manager/file_manager/common/js/tslib_shim.ts
new file mode 100644
index 0000000..7692a46
--- /dev/null
+++ b/ui/file_manager/file_manager/common/js/tslib_shim.ts
@@ -0,0 +1,20 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import * as tslib from 'chrome://resources/mwc/tslib/tslib.js';
+
+/**
+ * This file serves as a shim to tslib. Using experimental features like
+ * decorator will make TS generates compiled JS code like "import 'tslib'",
+ * but our existing build toolchain can't handle that import correctly. To
+ * mitigate that, we use "noEmitHelpers: true" in the tsconfig to make sure
+ * it won't generate "import 'tslib'", but this configuration requires the
+ * functions from tslib are available in the global space, hence the assignment
+ * below.
+ *
+ * Note: for any functions we expose here, we also need to add function
+ * type declaration to closure type externs in app_window_common.js.
+ */
+
+(globalThis as any).__decorate = tslib.__decorate;
diff --git a/ui/file_manager/file_manager/containers/search_container.ts b/ui/file_manager/file_manager/containers/search_container.ts
index 84de696..faaae1c1 100644
--- a/ui/file_manager/file_manager/containers/search_container.ts
+++ b/ui/file_manager/file_manager/containers/search_container.ts
@@ -506,9 +506,10 @@
         break;
       }
       case OptionKind.FILE_TYPE: {
-        const type = value as unknown as chrome.fileManagerPrivate.FileCategory;
-        if (type !== this.currentOptions_.type) {
-          this.currentOptions_.type = type;
+        const category =
+            value as unknown as chrome.fileManagerPrivate.FileCategory;
+        if (category !== this.currentOptions_.fileCategory) {
+          this.currentOptions_.fileCategory = category;
           this.updateSearchOptions_();
         }
         break;
diff --git a/ui/file_manager/file_manager/externs/app_window_common.js b/ui/file_manager/file_manager/externs/app_window_common.js
index e6f1aa1..a41c24c 100644
--- a/ui/file_manager/file_manager/externs/app_window_common.js
+++ b/ui/file_manager/file_manager/externs/app_window_common.js
@@ -24,4 +24,14 @@
  *
  * @type {boolean}
  */
-Window.prototype.IN_TEST;
\ No newline at end of file
+Window.prototype.IN_TEST;
+
+/**
+ * The function below is added by tslib_shim.ts to the global namespace.
+ *
+ * @param {*} decorators
+ * @param {*} target
+ * @param {string=} key
+ * @param {*=} desc
+ */
+const __decorate = function(decorators, target, key, desc) {};
diff --git a/ui/file_manager/file_manager/externs/ts/state.js b/ui/file_manager/file_manager/externs/ts/state.js
index 50f0017..8f3dc196 100644
--- a/ui/file_manager/file_manager/externs/ts/state.js
+++ b/ui/file_manager/file_manager/externs/ts/state.js
@@ -244,7 +244,7 @@
  * @typedef {{
  *   location: !SearchLocation,
  *   recency: SearchRecency,
- *   type:  chrome.fileManagerPrivate.FileCategory,
+ *   fileCategory:  chrome.fileManagerPrivate.FileCategory,
  * }}
  */
 export let SearchOptions;
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents.js b/ui/file_manager/file_manager/foreground/js/directory_contents.js
index 9b7b78fe..7028d70 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_contents.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_contents.js
@@ -458,7 +458,7 @@
   async scan(
       entriesCallback, successCallback, errorCallback,
       invalidateCache = false) {
-    const category = this.options_.type;
+    const category = this.options_.fileCategory;
     const timestamp = getEarliestTimestamp(this.options_.recency, new Date());
     const maxResults = 100;
 
diff --git a/ui/file_manager/file_manager/foreground/js/directory_model.js b/ui/file_manager/file_manager/foreground/js/directory_model.js
index d39c91d8..9cad9971 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_model.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_model.js
@@ -79,7 +79,7 @@
 function getFileCategory(entry, query, options) {
   if (query) {
     if (options) {
-      return options.type;
+      return options.fileCategory;
     }
   }
   return entry.fileCategory;
diff --git a/ui/file_manager/file_manager/state/reducers/search.ts b/ui/file_manager/file_manager/state/reducers/search.ts
index 647b1d8..b0b564d 100644
--- a/ui/file_manager/file_manager/state/reducers/search.ts
+++ b/ui/file_manager/file_manager/state/reducers/search.ts
@@ -19,7 +19,8 @@
     return true;
   }
   return fresh.location !== stored.location ||
-      fresh.recency !== stored.recency || fresh.type !== stored.type;
+      fresh.recency !== stored.recency ||
+      fresh.fileCategory !== stored.fileCategory;
 }
 
 export function search(state: State, action: SearchAction): State {
diff --git a/ui/file_manager/file_manager/state/reducers/search_unittest.ts b/ui/file_manager/file_manager/state/reducers/search_unittest.ts
index f80d836..0897452 100644
--- a/ui/file_manager/file_manager/state/reducers/search_unittest.ts
+++ b/ui/file_manager/file_manager/state/reducers/search_unittest.ts
@@ -30,7 +30,7 @@
   const currentOptions = {
     location: SearchLocation.THIS_FOLDER,
     recency: SearchRecency.ANYTIME,
-    type: chrome.fileManagerPrivate.FileCategory.ALL,
+    fileCategory: chrome.fileManagerPrivate.FileCategory.ALL,
   };
   store.dispatch(updateSearch({
     query: undefined,
@@ -62,7 +62,7 @@
   const freshRecencyOptions = {
     location: SearchLocation.THIS_FOLDER,
     recency: SearchRecency.LAST_WEEK,
-    type: chrome.fileManagerPrivate.FileCategory.ALL,
+    fileCategory: chrome.fileManagerPrivate.FileCategory.ALL,
   };
   store.dispatch(updateSearch({
     query: undefined,
diff --git a/ui/file_manager/file_manager/state/store.ts b/ui/file_manager/file_manager/state/store.ts
index 7d38f233..5487377 100644
--- a/ui/file_manager/file_manager/state/store.ts
+++ b/ui/file_manager/file_manager/state/store.ts
@@ -68,7 +68,7 @@
   return {
     location: SearchLocation.THIS_FOLDER,
     recency: SearchRecency.ANYTIME,
-    type: chrome.fileManagerPrivate.FileCategory.ALL,
+    fileCategory: chrome.fileManagerPrivate.FileCategory.ALL,
   } as SearchOptions;
 }
 
diff --git a/ui/file_manager/file_manager/widgets/xf_base.ts b/ui/file_manager/file_manager/widgets/xf_base.ts
index cf909a3..791a9022 100644
--- a/ui/file_manager/file_manager/widgets/xf_base.ts
+++ b/ui/file_manager/file_manager/widgets/xf_base.ts
@@ -7,6 +7,8 @@
  * @suppress {checkTypes} closure can't recognize LitElement
  */
 
+import '../common/js/tslib_shim.js';
+
 import {classMap, css, CSSResult, CSSResultGroup, customElement, html, ifDefined, LitElement, nothing, property, PropertyValues, query, repeat, state, styleMap, svg} from 'chrome://resources/mwc/lit/index.js';
 
 export {
diff --git a/ui/file_manager/file_names.gni b/ui/file_manager/file_names.gni
index a3efc04..515b029 100644
--- a/ui/file_manager/file_names.gni
+++ b/ui/file_manager/file_names.gni
@@ -239,6 +239,7 @@
 ts_files = [
   # Common.
   "file_manager/common/js/dom_utils.ts",
+  "file_manager/common/js/tslib_shim.ts",
   "file_manager/common/js/trash.ts",
   "file_manager/common/js/entry_utils.ts",
 
diff --git a/ui/file_manager/tsconfig_base.json b/ui/file_manager/tsconfig_base.json
index 50b40c3..aa0fa68 100644
--- a/ui/file_manager/tsconfig_base.json
+++ b/ui/file_manager/tsconfig_base.json
@@ -14,7 +14,7 @@
       "filewriter"
     ],
     "experimentalDecorators": true,
-    "importHelpers": true,
+    "noEmitHelpers": true,
     "skipLibCheck": true
   }
 }
diff --git a/ui/gl/dc_layer_overlay_params.h b/ui/gl/dc_layer_overlay_params.h
index f6183e6..22f7261 100644
--- a/ui/gl/dc_layer_overlay_params.h
+++ b/ui/gl/dc_layer_overlay_params.h
@@ -53,6 +53,9 @@
   gfx::HDRMetadata hdr_metadata;
 
   bool maybe_video_fullscreen_letterboxing = false;
+
+  // When false, this overlay will be scaled with linear sampling.
+  bool nearest_neighbor_filter = false;
 };
 
 }  // namespace gl
diff --git a/ui/gl/dc_layer_tree.cc b/ui/gl/dc_layer_tree.cc
index f92a91f..df6bb8b3 100644
--- a/ui/gl/dc_layer_tree.cc
+++ b/ui/gl/dc_layer_tree.cc
@@ -2,16 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <d3d11_1.h>
-
 #include "ui/gl/dc_layer_tree.h"
 
+#include <d3d11_1.h>
+
 #include <utility>
 
 #include "base/feature_list.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/trace_event/trace_event.h"
+#include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gl/direct_composition_child_surface_win.h"
 #include "ui/gl/direct_composition_support.h"
 #include "ui/gl/gl_angle_util_win.h"
@@ -24,19 +25,8 @@
 }
 
 bool NeedSwapChainPresenter(const DCLayerOverlayParams* overlay) {
-  // TODO(tangm): when we have more overlays originating from
-  // SkiaOutputDeviceDComp, we should replace this with an explicit "needs swap
-  // chain presenter" flag on DCLayerOverlayParams.
-  switch (overlay->overlay_image->type()) {
-    case DCLayerOverlayType::kNV12Texture:
-    case DCLayerOverlayType::kNV12Pixmap:
-    case DCLayerOverlayType::kDCompSurfaceProxy:
-      return true;
-    case DCLayerOverlayType::kDCompVisualContent:
-      // Z-order of 0 indicates the backbuffer, which already has been presented
-      // and ready for the DComp tree.
-      return overlay->z_order != 0;
-  }
+  return overlay->overlay_image->type() !=
+         DCLayerOverlayType::kDCompVisualContent;
 }
 
 // TODO(http://crbug.com/1380822): Implement dcomp visual tree optimization.
@@ -209,7 +199,9 @@
     IDCompositionDevice2* dcomp_device,
     Microsoft::WRL::ComPtr<IUnknown> dcomp_visual_content,
     uint64_t dcomp_surface_serial,
-    const gfx::Vector2d& quad_rect_offset,
+    const gfx::Rect& content_rect,
+    const gfx::Rect& quad_rect,
+    bool nearest_neighbor_filter,
     const gfx::Transform& quad_to_root_transform,
     const absl::optional<gfx::Rect>& clip_rect_in_root) {
   bool needs_commit = false;
@@ -269,16 +261,56 @@
     CHECK_EQ(hr, S_OK);
   }
 
-  if (offset_ != quad_rect_offset) {
-    offset_ = quad_rect_offset;
+  if (nearest_neighbor_filter_ != nearest_neighbor_filter) {
+    nearest_neighbor_filter_ = nearest_neighbor_filter;
     needs_commit = true;
 
+    hr = transform_visual_->SetBitmapInterpolationMode(
+        nearest_neighbor_filter_
+            ? DCOMPOSITION_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR
+            : DCOMPOSITION_BITMAP_INTERPOLATION_MODE_LINEAR);
+    CHECK_EQ(hr, S_OK);
+  }
+
+  if (content_rect_ != content_rect || quad_rect_ != quad_rect) {
+    content_rect_ = content_rect;
+    quad_rect_ = quad_rect;
+    needs_commit = true;
+
+    // Exclude content outside the content rect region
+    const auto content_clip =
+        D2D1::RectF(content_rect_.x(), content_rect_.y(), content_rect_.right(),
+                    content_rect_.bottom());
+    hr = content_visual_->SetClip(content_clip);
+    CHECK_EQ(hr, S_OK);
+
+    // Transform the (clipped) content so that it fills |quad_rect_|'s bounds.
+    // |quad_rect_|'s offset is handled below, so we exclude it from the matrix.
+    const bool needs_offset = !content_rect_.OffsetFromOrigin().IsZero();
+    const bool needs_scale = quad_rect_.width() != content_rect_.width() ||
+                             quad_rect_.height() != content_rect_.height();
+    if (needs_offset || needs_scale) {
+      const float scale_x = static_cast<float>(quad_rect_.width()) /
+                            static_cast<float>(content_rect_.width());
+      const float scale_y = static_cast<float>(quad_rect_.height()) /
+                            static_cast<float>(content_rect_.height());
+      const D2D_MATRIX_3X2_F matrix =
+          D2D1::Matrix3x2F::Translation(-content_rect_.x(),
+                                        -content_rect_.y()) *
+          D2D1::Matrix3x2F::Scale(scale_x, scale_y);
+      hr = content_visual_->SetTransform(matrix);
+      CHECK_EQ(hr, S_OK);
+    } else {
+      hr = content_visual_->SetTransform(nullptr);
+      CHECK_EQ(hr, S_OK);
+    }
+
     // Visual offset is applied after transform so it is affected by the
     // transform, which is consistent with how the compositor maps quad rects to
     // their target space.
-    hr = content_visual_->SetOffsetX(offset_.x());
+    hr = content_visual_->SetOffsetX(quad_rect_.x());
     CHECK_EQ(hr, S_OK);
-    hr = content_visual_->SetOffsetY(offset_.y());
+    hr = content_visual_->SetOffsetY(quad_rect_.y());
     CHECK_EQ(hr, S_OK);
   }
 
@@ -308,7 +340,7 @@
     gfx::Point* offset,
     gfx::Rect* clip_rect) const {
   *transform = transform_;
-  *offset = gfx::Point() + offset_;
+  *offset = quad_rect_.origin();
   *clip_rect = clip_rect_.value_or(gfx::Rect());
 }
 
@@ -333,6 +365,14 @@
   visual_subtrees.resize(overlays.size());
   // Build or update visual subtree for each overlay.
   for (size_t i = 0; i < overlays.size(); ++i) {
+    const bool is_root_plane = overlays[i]->z_order == 0;
+    if (!is_root_plane && overlays[i]->overlay_image) {
+      TRACE_EVENT2(
+          "gpu", "DCLayerTree::VisualTree::UpdateOverlay", "image_type",
+          DCLayerOverlayTypeToString(overlays[i]->overlay_image->type()),
+          "size", overlays[i]->content_rect.size().ToString());
+    }
+
     IUnknown* dcomp_visual_content =
         overlays[i]->overlay_image->dcomp_visual_content();
     // Find matching subtree for each overlay. If subtree is found, move it
@@ -368,7 +408,8 @@
         dc_layer_tree_->dcomp_device_.Get(),
         overlays[i]->overlay_image->dcomp_visual_content(),
         overlays[i]->overlay_image->dcomp_surface_serial(),
-        overlays[i]->quad_rect.OffsetFromOrigin(), overlays[i]->transform,
+        overlays[i]->content_rect, overlays[i]->quad_rect,
+        overlays[i]->nearest_neighbor_filter, overlays[i]->transform,
         overlays[i]->clip_rect);
 
     // Zero z_order represents root layer.
@@ -463,6 +504,8 @@
       root_params->overlay_image = DCLayerOverlayImage(
           root_surface->GetSize(), std::move(root_visual_content),
           root_surface->dcomp_surface_serial());
+      root_params->content_rect = gfx::Rect(root_params->overlay_image->size());
+      root_params->quad_rect = gfx::Rect(root_params->overlay_image->size());
       ScheduleDCLayer(std::move(root_params));
     } else {
       auto it = std::find_if(
@@ -544,7 +587,12 @@
       DLOG(ERROR) << "PresentToSwapChain failed";
       return false;
     }
+    // |SwapChainPresenter| may have changed the size of the overlay's quad
+    // rect, e.g. to present to a swap chain exactly the size of the display
+    // rect when the source video is larger.
     overlays[i]->transform = transform;
+    overlays[i]->content_rect = gfx::Rect(video_swap_chain->content_size());
+    overlays[i]->quad_rect.set_size(video_swap_chain->content_size());
     if (overlays[i]->clip_rect.has_value())
       overlays[i]->clip_rect = clip_rect;
     overlays[i]->overlay_image = DCLayerOverlayImage(
diff --git a/ui/gl/dc_layer_tree.h b/ui/gl/dc_layer_tree.h
index 3b5faca..540c9c8 100644
--- a/ui/gl/dc_layer_tree.h
+++ b/ui/gl/dc_layer_tree.h
@@ -203,7 +203,9 @@
       bool Update(IDCompositionDevice2* dcomp_device,
                   Microsoft::WRL::ComPtr<IUnknown> dcomp_visual_content,
                   uint64_t dcomp_surface_serial,
-                  const gfx::Vector2d& quad_rect_offset,
+                  const gfx::Rect& content_rect,
+                  const gfx::Rect& quad_rect,
+                  bool nearest_neighbor_filter,
                   const gfx::Transform& quad_to_root_transform,
                   const absl::optional<gfx::Rect>& clip_rect_in_root);
 
@@ -245,8 +247,18 @@
       // is updated.
       uint64_t dcomp_surface_serial_ = 0;
 
-      // Offset of the top left of the visual in quad space
-      gfx::Vector2d offset_;
+      // The portion of |dcomp_visual_content_| to display. This area will be
+      // mapped to |quad_rect_|'s bounds.
+      gfx::Rect content_rect_;
+
+      // The bounds which contain this overlay. When mapped by |transform_|,
+      // this is the bounds of the overlay in root space.
+      gfx::Rect quad_rect_;
+
+      // Whether or not to use nearest-neighbor filtering to scale
+      // |dcomp_visual_content_|. This is applied to |transform_visual_| since
+      // both it and |content_visual_| can scale the content.
+      bool nearest_neighbor_filter_ = false;
 
       // Transform from quad space to root space
       gfx::Transform transform_;
diff --git a/ui/gl/dcomp_presenter_unittest.cc b/ui/gl/dcomp_presenter_unittest.cc
index 3e8af75..a0861f2 100644
--- a/ui/gl/dcomp_presenter_unittest.cc
+++ b/ui/gl/dcomp_presenter_unittest.cc
@@ -113,6 +113,57 @@
 // margin for error.
 const int kMaxColorChannelDeviation = 10;
 
+// Create an overlay image with an initial color and rectangles, drawn using the
+// painter's algorithm.
+DCLayerOverlayImage CreateDCompSurface(
+    const gfx::Size& surface_size,
+    SkColor4f initial_color,
+    std::vector<std::pair<gfx::Rect, SkColor4f>> rectangles_back_to_front =
+        {}) {
+  HRESULT hr = S_OK;
+
+  Microsoft::WRL::ComPtr<IDCompositionDevice2> dcomp_device =
+      gl::GetDirectCompositionDevice();
+
+  Microsoft::WRL::ComPtr<IDCompositionSurface> surface;
+  hr = dcomp_device->CreateSurface(surface_size.width(), surface_size.height(),
+                                   DXGI_FORMAT_B8G8R8A8_UNORM,
+                                   DXGI_ALPHA_MODE_IGNORE, &surface);
+  CHECK_EQ(S_OK, hr);
+
+  // Add a rect that initializes the whole surface to |initial_color|.
+  rectangles_back_to_front.insert(rectangles_back_to_front.begin(),
+                                  {gfx::Rect(surface_size), initial_color});
+
+  Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
+      gl::QueryD3D11DeviceObjectFromANGLE();
+  Microsoft::WRL::ComPtr<ID3D11DeviceContext> immediate_context;
+  d3d11_device->GetImmediateContext(&immediate_context);
+
+  for (const auto& [draw_rect, color] : rectangles_back_to_front) {
+    CHECK(gfx::Rect(surface_size).Contains(draw_rect));
+
+    Microsoft::WRL::ComPtr<ID3D11Texture2D> update_texture;
+    RECT rect = draw_rect.ToRECT();
+    POINT update_offset;
+    hr = surface->BeginDraw(&rect, IID_PPV_ARGS(&update_texture),
+                            &update_offset);
+    CHECK_EQ(S_OK, hr);
+
+    Microsoft::WRL::ComPtr<ID3D11RenderTargetView> rtv;
+    hr = d3d11_device->CreateRenderTargetView(update_texture.Get(), nullptr,
+                                              &rtv);
+    CHECK_EQ(S_OK, hr);
+
+    immediate_context->ClearRenderTargetView(rtv.Get(), color.vec());
+
+    hr = surface->EndDraw();
+    CHECK_EQ(S_OK, hr);
+  }
+
+  return DCLayerOverlayImage(surface_size, surface);
+}
+
 }  // namespace
 
 class DCompPresenterTest : public testing::Test {
@@ -501,43 +552,13 @@
   // via an overlay the size of the window.
   void InitializeRootAndScheduleRootSurface(const gfx::Size& window_size,
                                             SkColor4f initial_color) {
-    Microsoft::WRL::ComPtr<IDCompositionDevice2> dcomp_device =
-        gl::GetDirectCompositionDevice();
-    Microsoft::WRL::ComPtr<IDCompositionSurface> root_surface;
-    ASSERT_HRESULT_SUCCEEDED(dcomp_device->CreateSurface(
-        window_size.width(), window_size.height(), DXGI_FORMAT_B8G8R8A8_UNORM,
-        DXGI_ALPHA_MODE_IGNORE, &root_surface));
-
-    // Clear the root surface to |initial_color|
-    Microsoft::WRL::ComPtr<ID3D11Texture2D> update_texture;
-    RECT rect = gfx::Rect(window_size).ToRECT();
-    POINT update_offset;
-    ASSERT_HRESULT_SUCCEEDED(root_surface->BeginDraw(
-        &rect, IID_PPV_ARGS(&update_texture), &update_offset));
-
-    Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
-        gl::QueryD3D11DeviceObjectFromANGLE();
-    Microsoft::WRL::ComPtr<ID3D11DeviceContext> immediate_context;
-    d3d11_device->GetImmediateContext(&immediate_context);
-    Microsoft::WRL::ComPtr<ID3D11RenderTargetView> rtv;
-    D3D11_RENDER_TARGET_VIEW_DESC desc;
-    desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
-    desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
-    desc.Texture2D.MipSlice = 0;
-    ASSERT_HRESULT_SUCCEEDED(d3d11_device->CreateRenderTargetView(
-        update_texture.Get(), &desc, &rtv));
-    immediate_context->ClearRenderTargetView(rtv.Get(), initial_color.vec());
-
-    ASSERT_HRESULT_SUCCEEDED(root_surface->EndDraw());
-
     // Schedule the root surface as a normal overlay
     std::unique_ptr<DCLayerOverlayParams> params =
         std::make_unique<DCLayerOverlayParams>();
     params->z_order = 0;
     params->quad_rect = gfx::Rect(window_size);
     params->content_rect = params->quad_rect;
-    params->overlay_image = DCLayerOverlayImage(window_size, root_surface,
-                                                /*dcomp_presenter_serial=*/0);
+    params->overlay_image = CreateDCompSurface(window_size, initial_color);
     EXPECT_TRUE(presenter_->ScheduleDCLayer(std::move(params)));
   }
 
@@ -568,6 +589,132 @@
     Sleep(1000);
   }
 
+  // If |scale_via_buffer| is true, use the content/quad rects to scale the
+  // buffer. If it is false, use the overlay's transform to scale the visual.
+  void RunNearestNeighborTest(bool scale_via_buffer) {
+    const gfx::Size window_size(100, 100);
+
+    EXPECT_TRUE(presenter_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
+    EXPECT_TRUE(presenter_->SetDrawRectangle(gfx::Rect(window_size)));
+
+    InitializeRootAndScheduleRootSurface(window_size, SkColors::kBlack);
+
+    auto dc_layer_params = std::make_unique<DCLayerOverlayParams>();
+    dc_layer_params->content_rect = gfx::Rect(2, 2);
+    dc_layer_params->overlay_image = CreateDCompSurface(
+        dc_layer_params->content_rect.size(), SkColors::kBlack,
+        {{gfx::Rect(0, 0, 1, 1), SkColors::kRed},
+         {gfx::Rect(1, 0, 1, 1), SkColors::kGreen},
+         {gfx::Rect(0, 1, 1, 1), SkColors::kBlue},
+         {gfx::Rect(1, 1, 1, 1), SkColors::kBlack}});
+    dc_layer_params->color_space = gfx::ColorSpace::CreateSRGB();
+    dc_layer_params->z_order = 1;
+    dc_layer_params->nearest_neighbor_filter = true;
+
+    if (scale_via_buffer) {
+      // Pick a large quad rect so the buffer is scaled up
+      dc_layer_params->quad_rect = gfx::Rect(window_size);
+    } else {
+      // Pick a small quad rect and assign a transform so the quad rect is
+      // scaled up
+      dc_layer_params->quad_rect = dc_layer_params->content_rect;
+      dc_layer_params->transform = gfx::Transform::MakeScale(
+          window_size.width() / dc_layer_params->quad_rect.width(),
+          window_size.height() / dc_layer_params->quad_rect.height());
+    }
+
+    presenter_->ScheduleDCLayer(std::move(dc_layer_params));
+    PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
+
+    GLTestHelper::WindowPixels pixels =
+        GLTestHelper::ReadBackWindow(window_.hwnd(), window_size);
+
+    EXPECT_SKCOLOR_CLOSE(SK_ColorRED, pixels.GetPixel(gfx::Point(49, 49)), 0);
+    EXPECT_SKCOLOR_CLOSE(SK_ColorGREEN, pixels.GetPixel(gfx::Point(51, 49)), 0);
+    EXPECT_SKCOLOR_CLOSE(SK_ColorBLUE, pixels.GetPixel(gfx::Point(49, 51)), 0);
+    EXPECT_SKCOLOR_CLOSE(SK_ColorBLACK, pixels.GetPixel(gfx::Point(51, 51)), 0);
+  }
+
+  // These colors are used for |CheckOverlayExactlyFillsHole|.
+  // The initial root surface color
+  const SkColor4f kRootSurfaceInitialColor = SkColors::kBlack;
+  // The "hole" in the root surface that we expect the overlay to completely
+  // cover.
+  const SkColor4f kRootSurfaceHiddenColor = SkColors::kRed;
+  // The color of the visible portion of the overlay image.
+  const SkColor4f kOverlayExpectedColor = SkColors::kBlue;
+  // The color of the portion of the overlay image hidden by the content rect.
+  const SkColor4f kOverlayImageHiddenColor = SkColors::kGreen;
+
+  const char* CheckOverlayExactlyFillsHoleColorToString(SkColor4f c) {
+    if (c == kRootSurfaceInitialColor) {
+      return "RootSurfaceInitialColor";
+    } else if (c == kRootSurfaceHiddenColor) {
+      return "RootSurfaceHiddenColor";
+    } else if (c == kOverlayExpectedColor) {
+      return "OverlayExpectedColor";
+    } else if (c == kOverlayImageHiddenColor) {
+      return "OverlayImageHiddenColor";
+    }
+    return "unexpected color";
+  }
+
+  // Check that |fit_in_hole_overlay| exactly covers |root_surface_hole|.
+  // This test uses the colors defined above to test for coverage: the resulting
+  // image should only contain |kOverlayExpectedColor| where the hole was and
+  // |kRootSurfaceInitialColor| elsewhere.
+  void CheckOverlayExactlyFillsHole(
+      const gfx::Size& window_size,
+      const gfx::Rect& root_surface_hole,
+      std::unique_ptr<DCLayerOverlayParams> fit_in_hole_overlay) {
+    EXPECT_TRUE(gfx::Rect(window_size).Contains(root_surface_hole));
+
+    EXPECT_TRUE(presenter_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
+    EXPECT_TRUE(presenter_->SetDrawRectangle(gfx::Rect(window_size)));
+
+    auto root_surface = std::make_unique<DCLayerOverlayParams>();
+    root_surface->quad_rect = gfx::Rect(window_size);
+    root_surface->content_rect = gfx::Rect(window_size);
+    root_surface->overlay_image =
+        CreateDCompSurface(window_size, kRootSurfaceInitialColor,
+                           {{root_surface_hole, kRootSurfaceHiddenColor}});
+    root_surface->color_space = gfx::ColorSpace::CreateSRGB();
+    root_surface->z_order = 0;
+    presenter_->ScheduleDCLayer(std::move(root_surface));
+
+    presenter_->ScheduleDCLayer(std::move(fit_in_hole_overlay));
+
+    PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
+
+    auto pixels = GLTestHelper::ReadBackWindow(window_.hwnd(), window_size);
+
+    for (int y = 0; y < window_size.height(); y++) {
+      for (int x = 0; x < window_size.width(); x++) {
+        gfx::Point location(x, y);
+        bool in_hole = root_surface_hole.Contains(location);
+        SkColor actual_color = pixels.GetPixel(location);
+        SkColor expected_color =
+            (in_hole ? kOverlayExpectedColor : kRootSurfaceInitialColor)
+                .toSkColor();
+        if (actual_color != expected_color) {
+          ADD_FAILURE() << "Unexpected pixel at " << location.ToString()
+                        << " (in_hole=" << in_hole << ")\n"
+                        << "Expected:\n  " << std::hex << "0x" << expected_color
+                        << " ("
+                        << CheckOverlayExactlyFillsHoleColorToString(
+                               SkColor4f::FromColor(expected_color))
+                        << ")\n"
+                        << "But got:\n  "
+                        << "0x" << actual_color << " ("
+                        << CheckOverlayExactlyFillsHoleColorToString(
+                               SkColor4f::FromColor(actual_color))
+                        << ")";
+          return;
+        }
+      }
+    }
+  }
+
   TestPlatformDelegate platform_delegate_;
   ui::WinWindow window_;
 };
@@ -1189,41 +1336,15 @@
   const gfx::Transform quad_to_root_transform(
       gfx::AxisTransform2d(0.5, gfx::Vector2dF()));
 
-  Microsoft::WRL::ComPtr<IDCompositionDevice2> dcomp_device =
-      GetDirectCompositionDevice();
-
-  Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
-      QueryD3D11DeviceObjectFromANGLE();
-  ASSERT_TRUE(d3d11_device);
-
-  Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
-  d3d11_device->GetImmediateContext(&context);
-  ASSERT_TRUE(context);
-
   gfx::Size window_size(100, 100);
   EXPECT_TRUE(presenter_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
   EXPECT_TRUE(presenter_->SetDrawRectangle(gfx::Rect(window_size)));
 
   InitializeRootAndScheduleRootSurface(window_size, SkColors::kBlack);
 
-  Microsoft::WRL::ComPtr<IDCompositionSurface> surface;
-  ASSERT_HRESULT_SUCCEEDED(dcomp_device->CreateSurface(
-      quad_rect.width(), quad_rect.height(), DXGI_FORMAT_B8G8R8A8_UNORM,
-      DXGI_ALPHA_MODE_IGNORE, &surface));
-  RECT update_rect = D2D1::Rect(0, 0, quad_rect.width(), quad_rect.height());
-  Microsoft::WRL::ComPtr<ID3D11Texture2D> update_texture;
-  POINT update_offset;
-  ASSERT_HRESULT_SUCCEEDED(surface->BeginDraw(
-      &update_rect, IID_PPV_ARGS(&update_texture), &update_offset));
-  Microsoft::WRL::ComPtr<ID3D11RenderTargetView> rtv;
-  ASSERT_HRESULT_SUCCEEDED(d3d11_device->CreateRenderTargetView(
-      update_texture.Get(), nullptr, &rtv));
-  context->ClearRenderTargetView(rtv.Get(), SkColors::kRed.vec());
-  ASSERT_HRESULT_SUCCEEDED(surface->EndDraw());
-
   auto dc_layer_params = std::make_unique<DCLayerOverlayParams>();
   dc_layer_params->overlay_image =
-      DCLayerOverlayImage(quad_rect.size(), surface);
+      CreateDCompSurface(quad_rect.size(), SkColors::kRed);
   dc_layer_params->content_rect = gfx::Rect(quad_rect.size());
   dc_layer_params->quad_rect = quad_rect;
   dc_layer_params->transform = quad_to_root_transform;
@@ -1259,6 +1380,170 @@
       kMaxColorChannelDeviation);
 }
 
+// Test that scaling a (very) small texture up works with nearest neighbor
+// filtering using the content rect and quad rects.
+TEST_F(DCompPresenterPixelTest, NearestNeighborFilteringScaleViaBuffer) {
+  if (!presenter_) {
+    return;
+  }
+  // Fails on AMD RX 5500 XT. https://crbug.com/1152565.
+  if (context_ && context_->GetVersionInfo() &&
+      context_->GetVersionInfo()->driver_vendor.find("AMD") !=
+          std::string::npos) {
+    return;
+  }
+
+  RunNearestNeighborTest(true);
+}
+
+// Test that scaling a (very) small texture up works with nearest neighbor
+// filtering using the overlay's transform.
+TEST_F(DCompPresenterPixelTest, NearestNeighborFilteringScaleViaTransform) {
+  if (!presenter_) {
+    return;
+  }
+  // Fails on AMD RX 5500 XT. https://crbug.com/1152565.
+  if (context_ && context_->GetVersionInfo() &&
+      context_->GetVersionInfo()->driver_vendor.find("AMD") !=
+          std::string::npos) {
+    return;
+  }
+
+  RunNearestNeighborTest(false);
+}
+
+// Test that the |content_rect| of an overlay scales the buffer to fit the
+// display rect, if needed.
+TEST_F(DCompPresenterPixelTest, ContentRectScalesUpBuffer) {
+  if (!presenter_) {
+    return;
+  }
+  // Fails on AMD RX 5500 XT. https://crbug.com/1152565.
+  if (context_ && context_->GetVersionInfo() &&
+      context_->GetVersionInfo()->driver_vendor.find("AMD") !=
+          std::string::npos) {
+    return;
+  }
+
+  const gfx::Size window_size(100, 100);
+  const gfx::Rect root_surface_hole = gfx::Rect(5, 10, 50, 75);
+
+  // Provide an overlay that's smaller than the hole it needs to fill
+  auto overlay = std::make_unique<DCLayerOverlayParams>();
+  overlay->content_rect = gfx::Rect(1, 1);
+  overlay->quad_rect = root_surface_hole;
+  overlay->overlay_image =
+      CreateDCompSurface(overlay->content_rect.size(), kOverlayExpectedColor);
+  overlay->color_space = gfx::ColorSpace::CreateSRGB();
+  overlay->z_order = 1;
+  CheckOverlayExactlyFillsHole(window_size, root_surface_hole,
+                               std::move(overlay));
+}
+
+// Test that the |content_rect| of an overlay scales the buffer to fit the
+// display rect, if needed.
+TEST_F(DCompPresenterPixelTest, ContentRectScalesDownBuffer) {
+  if (!presenter_) {
+    return;
+  }
+  // Fails on AMD RX 5500 XT. https://crbug.com/1152565.
+  if (context_ && context_->GetVersionInfo() &&
+      context_->GetVersionInfo()->driver_vendor.find("AMD") !=
+          std::string::npos) {
+    return;
+  }
+
+  const gfx::Size window_size(100, 100);
+  const gfx::Rect root_surface_hole = gfx::Rect(5, 10, 50, 75);
+
+  // Provide an overlay that's larger than the hole it needs to fill
+  auto overlay = std::make_unique<DCLayerOverlayParams>();
+  overlay->content_rect = gfx::Rect(75, 100);
+  overlay->quad_rect = root_surface_hole;
+  overlay->overlay_image =
+      CreateDCompSurface(overlay->content_rect.size(), kOverlayExpectedColor);
+  overlay->color_space = gfx::ColorSpace::CreateSRGB();
+  overlay->z_order = 1;
+  CheckOverlayExactlyFillsHole(window_size, root_surface_hole,
+                               std::move(overlay));
+}
+
+// Test that the |content_rect| of an overlay clips portions of the buffer.
+TEST_F(DCompPresenterPixelTest, ContentRectClipsBuffer) {
+  if (!presenter_) {
+    return;
+  }
+  // Fails on AMD RX 5500 XT. https://crbug.com/1152565.
+  if (context_ && context_->GetVersionInfo() &&
+      context_->GetVersionInfo()->driver_vendor.find("AMD") !=
+          std::string::npos) {
+    return;
+  }
+
+  const gfx::Size window_size(100, 100);
+  const gfx::Rect tex_coord = gfx::Rect(1, 2, 50, 60);
+  const gfx::Rect root_surface_hole =
+      gfx::Rect(gfx::Point(20, 25), tex_coord.size());
+
+  // Ensure the overlay is not scaled.
+  EXPECT_EQ(root_surface_hole.width(), tex_coord.width());
+  EXPECT_EQ(root_surface_hole.height(), tex_coord.height());
+
+  // Provide an overlay that is the right size, but has extra data that is
+  // clipped via content rect
+  auto overlay = std::make_unique<DCLayerOverlayParams>();
+  overlay->content_rect = tex_coord;
+  overlay->quad_rect = root_surface_hole;
+  overlay->overlay_image =
+      CreateDCompSurface(window_size, kOverlayImageHiddenColor,
+                         {{tex_coord, kOverlayExpectedColor}});
+  overlay->color_space = gfx::ColorSpace::CreateSRGB();
+  overlay->z_order = 1;
+  CheckOverlayExactlyFillsHole(window_size, root_surface_hole,
+                               std::move(overlay));
+}
+
+// Test that the |content_rect| of an overlay can clip a buffer and scale it's
+// contents.
+TEST_F(DCompPresenterPixelTest, ContentRectClipsAndScalesBuffer) {
+  if (!presenter_) {
+    return;
+  }
+  // Fails on AMD RX 5500 XT. https://crbug.com/1152565.
+  if (context_ && context_->GetVersionInfo() &&
+      context_->GetVersionInfo()->driver_vendor.find("AMD") !=
+          std::string::npos) {
+    return;
+  }
+
+  const gfx::Size window_size(100, 100);
+  const gfx::Rect tex_coord = gfx::Rect(5, 10, 15, 20);
+  const gfx::Rect root_surface_hole =
+      gfx::Rect(gfx::Point(20, 25), gfx::Size(50, 60));
+
+  // Ensure the overlay is scaled
+  EXPECT_NE(root_surface_hole.width(), tex_coord.width());
+  EXPECT_NE(root_surface_hole.height(), tex_coord.height());
+
+  // Provide an overlay that needs to be scaled and has extra data that is
+  // clipped via content rect
+  auto overlay = std::make_unique<DCLayerOverlayParams>();
+  overlay->content_rect = tex_coord;
+  overlay->quad_rect = root_surface_hole;
+  overlay->overlay_image =
+      CreateDCompSurface(window_size, kOverlayImageHiddenColor,
+                         {{tex_coord, kOverlayExpectedColor}});
+  overlay->color_space = gfx::ColorSpace::CreateSRGB();
+  overlay->z_order = 1;
+
+  // Use nearest neighbor to avoid interpolation at the edges of the content
+  // rect
+  overlay->nearest_neighbor_filter = true;
+
+  CheckOverlayExactlyFillsHole(window_size, root_surface_hole,
+                               std::move(overlay));
+}
+
 class DCompPresenterBufferCountTest : public DCompPresenterTest,
                                       public testing::WithParamInterface<bool> {
  public:
diff --git a/ui/gl/gl_display.cc b/ui/gl/gl_display.cc
index 5e8bde6..ce97bb0b 100644
--- a/ui/gl/gl_display.cc
+++ b/ui/gl/gl_display.cc
@@ -24,6 +24,7 @@
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context_egl.h"
 #include "ui/gl/gl_display_egl_util.h"
+#include "ui/gl/gl_features.h"
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_surface.h"
 
@@ -143,6 +144,21 @@
 
 namespace {
 
+void AdjustAngleFeaturesFromChromeFeatures(
+    std::vector<std::string>& enabled_angle_features,
+    std::vector<std::string>& disabled_angle_features) {
+#if BUILDFLAG(IS_MAC)
+  if (base::FeatureList::IsEnabled(features::kWriteMetalShaderCacheToDisk)) {
+    disabled_angle_features.push_back("enableParallelMtlLibraryCompilation");
+    enabled_angle_features.push_back("compileMetalShaders");
+    enabled_angle_features.push_back("disableProgramCaching");
+  }
+  if (base::FeatureList::IsEnabled(features::kUseBuiltInMetalShaderCache)) {
+    enabled_angle_features.push_back("loadMetalShadersFromBlobCache");
+  }
+#endif
+}
+
 std::vector<const char*> GetAttribArrayFromStringVector(
     const std::vector<std::string>& strings) {
   std::vector<const char*> attribs;
@@ -730,6 +746,9 @@
       GetStringVectorFromCommandLine(command_line,
                                      switches::kDisableANGLEFeatures);
 
+  AdjustAngleFeaturesFromChromeFeatures(enabled_angle_features,
+                                        disabled_angle_features);
+
   bool disable_all_angle_features =
       command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds);
 
diff --git a/ui/gl/gl_features.cc b/ui/gl/gl_features.cc
index 564913a..d745ea3 100644
--- a/ui/gl/gl_features.cc
+++ b/ui/gl/gl_features.cc
@@ -90,6 +90,25 @@
              base::FEATURE_DISABLED_BY_DEFAULT);
 #endif  // !defined(PASSTHROUGH_COMMAND_DECODER_LAUNCHED)
 
+#if BUILDFLAG(IS_MAC)
+// If true, metal shader programs are written to disk.
+//
+// As the gpu process writes to disk when this is set, you must also disable
+// the sandbox.
+//
+// The path the shaders are written to is controlled via the command line switch
+// --shader-cache-path (default is /tmp/shaders).
+BASE_FEATURE(kWriteMetalShaderCacheToDisk,
+             "WriteMetalShaderCacheToDisk",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+// If true, the metal shader cache is read from a file and put into BlobCache
+// during startup.
+BASE_FEATURE(kUseBuiltInMetalShaderCache,
+             "UseBuiltInMetalShaderCache",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+#endif
+
 bool UseGpuVsync() {
   return !base::CommandLine::ForCurrentProcess()->HasSwitch(
              switches::kDisableGpuVsync) &&
diff --git a/ui/gl/gl_features.h b/ui/gl/gl_features.h
index c526a298..a89029a 100644
--- a/ui/gl/gl_features.h
+++ b/ui/gl/gl_features.h
@@ -28,6 +28,11 @@
 GL_EXPORT BASE_DECLARE_FEATURE(kDefaultPassthroughCommandDecoder);
 #endif
 
+#if BUILDFLAG(IS_MAC)
+GL_EXPORT BASE_DECLARE_FEATURE(kWriteMetalShaderCacheToDisk);
+GL_EXPORT BASE_DECLARE_FEATURE(kUseBuiltInMetalShaderCache);
+#endif
+
 GL_EXPORT bool IsAndroidFrameDeadlineEnabled();
 
 GL_EXPORT bool UsePassthroughCommandDecoder();
diff --git a/ui/gl/swap_chain_presenter.cc b/ui/gl/swap_chain_presenter.cc
index 2288ae67..5438d7b 100644
--- a/ui/gl/swap_chain_presenter.cc
+++ b/ui/gl/swap_chain_presenter.cc
@@ -1166,6 +1166,8 @@
                                             gfx::Transform* visual_transform,
                                             gfx::Rect* visual_clip_rect) {
   DCHECK(params.overlay_image);
+  DCHECK_NE(params.overlay_image->type(),
+            gl::DCLayerOverlayType::kDCompVisualContent);
 
   gl::DCLayerOverlayType overlay_type = params.overlay_image->type();
 
@@ -1183,35 +1185,8 @@
   // content is shown again.
   ReleaseDCOMPSurfaceResourcesIfNeeded();
 
-  gfx::Size content_size;
-  gfx::Size swap_chain_size;
-  if (overlay_type == gl::DCLayerOverlayType::kDCompVisualContent) {
-    content_size = params.overlay_image->size();
-    // |visual_transform| now scales from |content_size| to on screen bounds.
-    UpdateSwapChainTransform(params.quad_rect.size(), content_size,
-                             visual_transform);
-  } else {
-    swap_chain_size =
-        CalculateSwapChainSize(params, visual_transform, visual_clip_rect);
-    content_size = swap_chain_size;
-  }
-
-  TRACE_EVENT2("gpu", "SwapChainPresenter::PresentToSwapChain", "image_type",
-               DCLayerOverlayTypeToString(overlay_type), "size",
-               content_size.ToString());
-
-  // Swap chain image already has a swap chain that's presented by the client
-  // e.g. for webgl/canvas low-latency/desynchronized mode.
-  if (overlay_type == gl::DCLayerOverlayType::kDCompVisualContent) {
-    DCHECK(params.overlay_image->dcomp_visual_content());
-    if (last_overlay_image_ != params.overlay_image) {
-      ReleaseSwapChainResources();
-      content_ = params.overlay_image->dcomp_visual_content();
-      content_size_ = content_size;
-      last_overlay_image_ = std::move(params.overlay_image);
-    }
-    return true;
-  }
+  gfx::Size swap_chain_size =
+      CalculateSwapChainSize(params, visual_transform, visual_clip_rect);
 
   if (overlay_type == gl::DCLayerOverlayType::kNV12Texture &&
       !params.overlay_image->nv12_texture()) {
diff --git a/ui/views/controls/menu/menu_scroll_view_container.cc b/ui/views/controls/menu/menu_scroll_view_container.cc
index 5635af2..c4f9cea 100644
--- a/ui/views/controls/menu/menu_scroll_view_container.cc
+++ b/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -324,6 +324,16 @@
   const MenuConfig& menu_config = MenuConfig::instance();
   extra.menu_background.corner_radius = menu_config.CornerRadiusForMenu(
       content_view_->GetMenuItem()->GetMenuController());
+  if (border_color_id_.has_value()) {
+    ui::ColorProvider* color_provider = GetColorProvider();
+    cc::PaintFlags flags;
+    flags.setAntiAlias(true);
+    flags.setStyle(cc::PaintFlags::kFill_Style);
+    flags.setColor(color_provider->GetColor(border_color_id_.value()));
+    canvas->DrawRoundRect(GetLocalBounds(), extra.menu_background.corner_radius,
+                          flags);
+    return;
+  }
   GetNativeTheme()->Paint(canvas->sk_canvas(), GetColorProvider(),
                           ui::NativeTheme::kMenuPopupBackground,
                           ui::NativeTheme::kNormal, bounds, extra);
diff --git a/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.ts b/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.ts
index 1b01b9e..53137d7 100644
--- a/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.ts
+++ b/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.ts
@@ -125,6 +125,10 @@
   }
 
   private showRipple_() {
+    if (this.noink) {
+      return;
+    }
+
     this.getRipple().showAndHoldDown();
   }